/
githubmirror
/
panama-vector
Обзор
Документация
Войти
/
githubmirror
/
panama-vector
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/java.desktop/share/classes/sun/font/CompositeGlyphMapper.java
264 строки
10 KB
Daniel Gredler
8359955: Regressions ~7% in several J2DBench in 25-b26
20 авг 2025, 10:26
20 авг 2025, 10:26
c220a6c
Код
Авторство
О чём код?
/* * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package sun.font; /* Remember that the API requires a Font use a * consistent glyph id. for a code point, and this is a * problem if a particular strike uses native scaler sometimes * and the JDK scaler others. That needs to be dealt with somewhere, but * here we can just always get the same glyph code without * needing a strike. * * The C implementation would cache the results of anything up * to the maximum surrogate pair code point. * This implementation will not cache as much, since the storage * requirements are not justifiable. Even so it still can use up * to 2*216*256*4 bytes of storage per composite font. If an app * calls canDisplay on this range for all 20 composite fonts that's * over 2Mb of cached data. May need to employ WeakReferences if * this appears to cause problems. */ import static sun.font.FontUtilities.isDefaultIgnorable; import static sun.font.FontUtilities.isIgnorableWhitespace; public class CompositeGlyphMapper extends CharToGlyphMapper { public static final int SLOTMASK = 0xff000000; public static final int GLYPHMASK = 0x00ffffff; public static final int NBLOCKS = 216; public static final int BLOCKSZ = 256; public static final int MAXUNICODE = NBLOCKS*BLOCKSZ; private final CompositeFont font; private final CharToGlyphMapper[] slotMappers; private final int[][] glyphMapsRaw; private final int[][] glyphMapsMod; private final boolean hasExcludes; public CompositeGlyphMapper(CompositeFont compFont) { font = compFont; glyphMapsRaw = new int[NBLOCKS][]; glyphMapsMod = new int[NBLOCKS][]; slotMappers = new CharToGlyphMapper[font.numSlots]; /* This requires that slot 0 is never empty. */ missingGlyph = font.getSlotFont(0).getMissingGlyphCode(); missingGlyph = compositeGlyphCode(0, missingGlyph); /* This is often false which saves the overhead of a * per-mapped char method call. */ hasExcludes = compFont.exclusionRanges != null && compFont.maxIndices != null; } public int compositeGlyphCode(int slot, int glyphCode) { return (slot << 24 | (glyphCode & GLYPHMASK)); } private int getCachedGlyphCode(int unicode, boolean raw) { if (unicode >= MAXUNICODE) { return UNINITIALIZED_GLYPH; // don't cache surrogates } int[] gmap; int[][] glyphMaps = raw ? glyphMapsRaw : glyphMapsMod; if ((gmap = glyphMaps[unicode >> 8]) == null) { return UNINITIALIZED_GLYPH; } return gmap[unicode & 0xff]; } private void setCachedGlyphCode(int unicode, int glyphCode, boolean raw) { if (unicode >= MAXUNICODE) { return; // don't cache surrogates } int index0 = unicode >> 8; int[][] glyphMaps = raw ? glyphMapsRaw : glyphMapsMod; if (glyphMaps[index0] == null) { glyphMaps[index0] = new int[BLOCKSZ]; for (int i=0;i<BLOCKSZ;i++) { glyphMaps[index0][i] = UNINITIALIZED_GLYPH; } } glyphMaps[index0][unicode & 0xff] = glyphCode; } private CharToGlyphMapper getSlotMapper(int slot) { CharToGlyphMapper mapper = slotMappers[slot]; if (mapper == null) { mapper = font.getSlotFont(slot).getMapper(); slotMappers[slot] = mapper; } return mapper; } private int getGlyph(int unicode, boolean raw) { int glyphCode = getCachedGlyphCode(unicode, raw); if (glyphCode != UNINITIALIZED_GLYPH) { return glyphCode; } if (isIgnorableWhitespace(unicode) || (isDefaultIgnorable(unicode) && !raw)) { glyphCode = INVISIBLE_GLYPH_ID; setCachedGlyphCode(unicode, glyphCode, raw); return glyphCode; } for (int slot = 0; slot < font.numSlots; slot++) { if (!hasExcludes || !font.isExcludedChar(slot, unicode)) { CharToGlyphMapper mapper = getSlotMapper(slot); glyphCode = mapper.charToGlyphRaw(unicode); if (glyphCode != mapper.getMissingGlyphCode()) { glyphCode = compositeGlyphCode(slot, glyphCode); setCachedGlyphCode(unicode, glyphCode, raw); return glyphCode; } } } return missingGlyph; } public int getNumGlyphs() { int numGlyphs = 0; /* The number of glyphs in a composite is affected by * exclusion ranges and duplicates (ie the same code point is * mapped by two different fonts) and also whether or not to * count fallback fonts. A nearly correct answer would be very * expensive to generate. A rough ballpark answer would * just count the glyphs in all the slots. However this would * initialize mappers for all slots when they aren't necessarily * needed. For now just use the first slot as JDK 1.4 did. */ for (int slot=0; slot<1 /*font.numSlots*/; slot++) { CharToGlyphMapper mapper = slotMappers[slot]; if (mapper == null) { mapper = font.getSlotFont(slot).getMapper(); slotMappers[slot] = mapper; } numGlyphs += mapper.getNumGlyphs(); } return numGlyphs; } public int charToGlyphRaw(int unicode) { int glyphCode = getGlyph(unicode, true); return glyphCode; } public int charToGlyph(int unicode) { int glyphCode = getGlyph(unicode, false); return glyphCode; } public int charToGlyph(int unicode, int prefSlot) { if (prefSlot >= 0) { CharToGlyphMapper mapper = getSlotMapper(prefSlot); int glyphCode = mapper.charToGlyph(unicode); if (glyphCode != mapper.getMissingGlyphCode()) { return compositeGlyphCode(prefSlot, glyphCode); } } return charToGlyph(unicode); } public int charToGlyph(char unicode) { int glyphCode = getGlyph(unicode, false); return glyphCode; } /* This variant checks if shaping is needed and immediately * returns true if it does. A caller of this method should be expecting * to check the return type because it needs to know how to handle * the character data for display. */ public boolean charsToGlyphsNS(int count, char[] unicodes, int[] glyphs) { for (int i=0; i<count; i++) { int code = unicodes[i]; // char is unsigned. if (code >= HI_SURROGATE_START && code <= HI_SURROGATE_END && i < count - 1) { char low = unicodes[i + 1]; if (low >= LO_SURROGATE_START && low <= LO_SURROGATE_END) { code = (code - HI_SURROGATE_START) * 0x400 + low - LO_SURROGATE_START + 0x10000; glyphs[i + 1] = INVISIBLE_GLYPH_ID; } } glyphs[i] = getGlyph(code, false); if (code < FontUtilities.MIN_LAYOUT_CHARCODE) { continue; } else if (FontUtilities.isComplexCharCode(code) || CharToGlyphMapper.isVariationSelector(code)) { return true; } else if (code >= 0x10000) { i += 1; // Empty glyph slot after surrogate continue; } } return false; } /* The conversion is not very efficient - looping as it does, converting * one char at a time. However the cache should fill very rapidly. */ public void charsToGlyphs(int count, char[] unicodes, int[] glyphs) { for (int i=0; i<count; i++) { int code = unicodes[i]; // char is unsigned. if (code >= HI_SURROGATE_START && code <= HI_SURROGATE_END && i < count - 1) { char low = unicodes[i + 1]; if (low >= LO_SURROGATE_START && low <= LO_SURROGATE_END) { code = (code - HI_SURROGATE_START) * 0x400 + low - LO_SURROGATE_START + 0x10000; glyphs[i] = getGlyph(code, false); i += 1; // Empty glyph slot after surrogate glyphs[i] = INVISIBLE_GLYPH_ID; continue; } } glyphs[i] = getGlyph(code, false); } } public void charsToGlyphs(int count, int[] unicodes, int[] glyphs) { for (int i=0; i<count; i++) { int code = unicodes[i]; glyphs[i] = getGlyph(code, false); } } }