mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
JBR-4072 Migrate font fallback implementation on macOS to cascade lists
(cherry picked from commit a155760e94)
This commit is contained in:
@@ -128,12 +128,8 @@ public class CCharToGlyphMapper extends CharToGlyphMapper {
|
||||
};
|
||||
}
|
||||
|
||||
// This mapper returns either the glyph code, or if the character can be
|
||||
// replaced on-the-fly using CoreText substitution; the negative unicode
|
||||
// value. If this "glyph code int" is treated as an opaque code, it will
|
||||
// strike and measure exactly as a real glyph code - whether the character
|
||||
// is present or not. Missing characters for any font on the system will
|
||||
// be returned as 0, as the getMissingGlyphCode() function above indicates.
|
||||
// Missing characters for any font on the system will be returned as 0,
|
||||
// as the getMissingGlyphCode() function above indicates.
|
||||
private static native void nativeCharsToGlyphs(final long nativeFontPtr,
|
||||
int count, char[] unicodes,
|
||||
int[] glyphs);
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package sun.font;
|
||||
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class CCompositeFont extends CompositeFont {
|
||||
private final List<CFont> fallbackFonts = new ArrayList<>();
|
||||
|
||||
public CCompositeFont(CFont font) {
|
||||
super(new PhysicalFont[]{font});
|
||||
mapper = new CCompositeGlyphMapper(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized int getNumSlots() {
|
||||
return super.getNumSlots();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CFont getSlotFont(int slot) {
|
||||
if (slot == 0) return (CFont) super.getSlotFont(0);
|
||||
synchronized (this) {
|
||||
return fallbackFonts.get(slot - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
synchronized FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
|
||||
return super.getStrike(desc, copy);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected synchronized int getValidatedGlyphCode(int glyphCode) {
|
||||
return super.getValidatedGlyphCode(glyphCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSupplementaryChars() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean useAAForPtSize(int ptsize) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public synchronized int findSlot(String fontName) {
|
||||
for (int slot = 0; slot < numSlots; slot++) {
|
||||
CFont slotFont = getSlotFont(slot);
|
||||
if (fontName.equals(slotFont.getNativeFontName())) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public synchronized int addSlot(CFont font) {
|
||||
int slot = findSlot(font.getNativeFontName());
|
||||
if (slot >= 0) return slot;
|
||||
fallbackFonts.add(font);
|
||||
lastFontStrike = new SoftReference<>(null);
|
||||
strikeCache.clear();
|
||||
return numSlots++;
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, 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;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public final class CCompositeGlyphMapper extends CompositeGlyphMapper {
|
||||
public CCompositeGlyphMapper(CCompositeFont compFont) {
|
||||
super(compFont);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int convertToGlyph(int unicode) {
|
||||
CCompositeFont compositeFont = (CCompositeFont) font;
|
||||
CFont mainFont = (CFont) font.getSlotFont(0);
|
||||
String[] fallbackFontInfo = new String[2];
|
||||
int glyphCode = nativeCodePointToGlyph(mainFont.getNativeFontPtr(), unicode, fallbackFontInfo);
|
||||
if (glyphCode == missingGlyph) {
|
||||
setCachedGlyphCode(unicode, missingGlyph);
|
||||
return missingGlyph;
|
||||
}
|
||||
String fallbackFontName = fallbackFontInfo[0];
|
||||
String fallbackFontFamilyName = fallbackFontInfo[1];
|
||||
if (fallbackFontName == null || fallbackFontFamilyName == null) {
|
||||
int result = compositeGlyphCode(0, glyphCode);
|
||||
setCachedGlyphCode(unicode, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
int slot = compositeFont.findSlot(fallbackFontName);
|
||||
|
||||
if (slot < 0) {
|
||||
Font2D fallbackFont = FontManagerFactory.getInstance().findFont2D(fallbackFontName,
|
||||
Font.PLAIN, FontManager.NO_FALLBACK);
|
||||
if (!(fallbackFont instanceof CFont) ||
|
||||
!fallbackFontName.equals(((CFont) fallbackFont).getNativeFontName())) {
|
||||
// Native font fallback mechanism can return "hidden" fonts - their names start with dot,
|
||||
// and they are not returned in a list of fonts available in system, but they can still be used
|
||||
// if requested explicitly.
|
||||
fallbackFont = new CFont(fallbackFontName, fallbackFontFamilyName, null);
|
||||
}
|
||||
|
||||
if (mainFont.isFakeItalic()) fallbackFont = ((CFont)fallbackFont).createItalicVariant(false);
|
||||
|
||||
slot = compositeFont.addSlot((CFont) fallbackFont);
|
||||
}
|
||||
|
||||
int result = compositeGlyphCode(slot, glyphCode);
|
||||
setCachedGlyphCode(unicode, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
// This invokes native font fallback mechanism, returning information about font (its Postscript and family names)
|
||||
// able to display a given character, and corresponding glyph code
|
||||
private static native int nativeCodePointToGlyph(long nativeFontPtr, int codePoint, String[] result);
|
||||
}
|
||||
@@ -31,6 +31,9 @@ import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
// Right now this class is final to avoid a problem with native code.
|
||||
// For some reason the JNI IsInstanceOf was not working correctly
|
||||
@@ -175,14 +178,12 @@ public final class CFont extends PhysicalFont implements FontSubstitution, FontW
|
||||
isFakeItalic = other.isFakeItalic;
|
||||
}
|
||||
|
||||
public CFont createItalicVariant(boolean updateStyle) {
|
||||
public CFont createItalicVariant() {
|
||||
CFont font = new CFont(this, familyName);
|
||||
font.nativeFontName = fullName;
|
||||
font.fullName =
|
||||
fullName + (style == Font.BOLD ? "" : "-") + "Italic-Derived";
|
||||
if (updateStyle) {
|
||||
font.style |= Font.ITALIC;
|
||||
}
|
||||
font.style |= Font.ITALIC;
|
||||
font.isFakeItalic = true;
|
||||
return font;
|
||||
}
|
||||
@@ -204,11 +205,51 @@ public final class CFont extends PhysicalFont implements FontSubstitution, FontW
|
||||
return getCGFontPtrNative(getNativeFontPtr());
|
||||
}
|
||||
|
||||
static native void getCascadeList(long nativeFontPtr, ArrayList<String> listOfString);
|
||||
|
||||
private CompositeFont createCompositeFont() {
|
||||
ArrayList<String> listOfString = new ArrayList<String>();
|
||||
getCascadeList(getNativeFontPtr(), listOfString);
|
||||
|
||||
Set<String> components = new LinkedHashSet<>(listOfString);
|
||||
// In some italic cases the standard Mac cascade list is missing Arabic.
|
||||
components.add("GeezaPro");
|
||||
CFontManager fm = (CFontManager) FontManagerFactory.getInstance();
|
||||
components.addAll(fm.getAdditionalFallbackVariants());
|
||||
int numFonts = 1 + components.size();
|
||||
PhysicalFont[] fonts = new PhysicalFont[numFonts];
|
||||
fonts[0] = this;
|
||||
int idx = 1;
|
||||
if (FontUtilities.isLogging()) {
|
||||
FontUtilities.logInfo("Cascading list for " + this + " :");
|
||||
}
|
||||
for (String s : components) {
|
||||
if (FontUtilities.isLogging()) {
|
||||
FontUtilities.logInfo("Fallback:" + s);
|
||||
}
|
||||
if (s.equals(".AppleSymbolsFB")) {
|
||||
// Don't know why we get the weird name above .. replace.
|
||||
s = "AppleSymbols";
|
||||
}
|
||||
Font2D f2d = fm.getOrCreateFallbackFont(s);
|
||||
if (f2d == null || f2d == this) {
|
||||
continue;
|
||||
}
|
||||
fonts[idx++] = (PhysicalFont)f2d;
|
||||
}
|
||||
if (idx < fonts.length) {
|
||||
PhysicalFont[] orig = fonts;
|
||||
fonts = new PhysicalFont[idx];
|
||||
System.arraycopy(orig, 0, fonts, 0, idx);
|
||||
}
|
||||
return new CompositeFont(fonts);
|
||||
}
|
||||
|
||||
private CompositeFont compFont;
|
||||
|
||||
public CompositeFont getCompositeFont2D() {
|
||||
if (compFont == null) {
|
||||
compFont = new CCompositeFont(this);
|
||||
compFont = createCompositeFont();
|
||||
}
|
||||
return compFont;
|
||||
}
|
||||
@@ -236,14 +277,6 @@ public final class CFont extends PhysicalFont implements FontSubstitution, FontW
|
||||
return new CStrike(this, desc);
|
||||
}
|
||||
|
||||
boolean isFakeItalic() {
|
||||
return isFakeItalic;
|
||||
}
|
||||
|
||||
String getNativeFontName() {
|
||||
return nativeFontName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTypographicSubfamilyName() {
|
||||
return faceName == null ? super.getTypographicSubfamilyName() : faceName;
|
||||
@@ -276,8 +309,4 @@ public final class CFont extends PhysicalFont implements FontSubstitution, FontW
|
||||
", familyName: " + familyName + ", style: " + style +
|
||||
" } aka: " + super.toString();
|
||||
}
|
||||
|
||||
public Font2D createItalic() {
|
||||
return this.createItalicVariant(true);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,20 +30,27 @@ import java.io.File;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
|
||||
import sun.awt.FontConfiguration;
|
||||
import sun.awt.HeadlessToolkit;
|
||||
import sun.lwawt.macosx.*;
|
||||
import sun.security.action.GetBooleanAction;
|
||||
import sun.util.logging.PlatformLogger;
|
||||
|
||||
public final class CFontManager extends SunFontManager {
|
||||
private static Hashtable<String, Font2D> genericFonts = new Hashtable<String, Font2D>();
|
||||
private final Map<String, Font2D> fallbackFonts = new ConcurrentHashMap<>();
|
||||
private final List<String> extFallbackVariants = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
protected FontConfiguration createFontConfiguration() {
|
||||
@@ -230,6 +237,7 @@ public final class CFontManager extends SunFontManager {
|
||||
public Object run() {
|
||||
if (!loadedAllFonts) {
|
||||
loadNativeFonts();
|
||||
collectAdditionalFallbackVariants();
|
||||
loadedAllFonts = true;
|
||||
}
|
||||
return null;
|
||||
@@ -337,4 +345,40 @@ public final class CFontManager extends SunFontManager {
|
||||
@Override
|
||||
protected void populateFontFileNameMap(HashMap<String, String> fontToFileMap, HashMap<String, String> fontToFamilyNameMap,
|
||||
HashMap<String, ArrayList<String>> familyToFontListMap, Locale locale) {}
|
||||
|
||||
@SuppressWarnings("removal")
|
||||
private void collectAdditionalFallbackVariants() {
|
||||
if (AccessController.doPrivileged(new GetBooleanAction("mac.ext.font.fallback"))) {
|
||||
for (String fontName : genericFonts.keySet()) {
|
||||
boolean accept = false;
|
||||
if (fontName.equals("ArialUnicodeMS")) {
|
||||
accept = true;
|
||||
} else if (fontName.startsWith("NotoSans")) {
|
||||
int pos = fontName.indexOf('-');
|
||||
accept = pos == -1 || fontName.substring(pos + 1).equals("Regular");
|
||||
}
|
||||
if (accept) {
|
||||
extFallbackVariants.add(fontName);
|
||||
}
|
||||
}
|
||||
Collections.sort(extFallbackVariants); // ensure predictable order
|
||||
}
|
||||
}
|
||||
|
||||
List<String> getAdditionalFallbackVariants() {
|
||||
return extFallbackVariants;
|
||||
}
|
||||
|
||||
Font2D getOrCreateFallbackFont(String fontName) {
|
||||
Font2D font2D = findFont2D(fontName, Font.PLAIN, FontManager.NO_FALLBACK);
|
||||
if (font2D != null || fontName.startsWith(".")) {
|
||||
return font2D;
|
||||
} else {
|
||||
// macOS doesn't list some system fonts in [NSFontManager availableFontFamilies] output,
|
||||
// so they are not registered in font manager as part of 'loadNativeFonts'.
|
||||
// These fonts are present in [NSFontManager availableFonts] output though,
|
||||
// and can be accessed in the same way as other system fonts.
|
||||
return fallbackFonts.computeIfAbsent(fontName, name -> new CFont(name, null, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,18 +358,14 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
}
|
||||
|
||||
// This class stores glyph pointers, and is indexed based on glyph codes,
|
||||
// and negative unicode values. See the comments in
|
||||
// CCharToGlyphMapper for more details on our glyph code strategy.
|
||||
// This class stores glyph pointers, and is indexed based on glyph codes.
|
||||
private static class GlyphInfoCache extends CStrikeDisposer {
|
||||
private static final int FIRST_LAYER_SIZE = 256;
|
||||
private static final int SECOND_LAYER_SIZE = 16384; // 16384 = 128x128
|
||||
|
||||
// rdar://problem/5204197
|
||||
private final AtomicBoolean disposed = new AtomicBoolean(false);
|
||||
|
||||
private final long[] firstLayerCache;
|
||||
private SparseBitShiftingTwoLayerArray secondLayerCache;
|
||||
private HashMap<Integer, Long> generalCache;
|
||||
|
||||
GlyphInfoCache(final Font2D nativeFont, final FontStrikeDesc desc) {
|
||||
@@ -378,19 +374,9 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
|
||||
public synchronized long get(final int index) {
|
||||
if (index < 0) {
|
||||
if (-index < SECOND_LAYER_SIZE) {
|
||||
// catch common unicodes
|
||||
if (secondLayerCache == null) {
|
||||
return 0L;
|
||||
}
|
||||
return secondLayerCache.get(-index);
|
||||
}
|
||||
} else {
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
return firstLayerCache[index];
|
||||
}
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
return firstLayerCache[index];
|
||||
}
|
||||
|
||||
if (generalCache == null) {
|
||||
@@ -404,21 +390,10 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
|
||||
public synchronized void put(final int index, final long value) {
|
||||
if (index < 0) {
|
||||
if (-index < SECOND_LAYER_SIZE) {
|
||||
// catch common unicodes
|
||||
if (secondLayerCache == null) {
|
||||
secondLayerCache = new SparseBitShiftingTwoLayerArray(SECOND_LAYER_SIZE, 7); // 128x128
|
||||
}
|
||||
secondLayerCache.put(-index, value);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
firstLayerCache[index] = value;
|
||||
return;
|
||||
}
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
firstLayerCache[index] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (generalCache == null) {
|
||||
@@ -441,14 +416,6 @@ public final class CStrike extends PhysicalStrike {
|
||||
// clean out the first array
|
||||
disposeLongArray(firstLayerCache);
|
||||
|
||||
// clean out the two layer arrays
|
||||
if (secondLayerCache != null) {
|
||||
final long[][] secondLayerLongArrayArray = secondLayerCache.cache;
|
||||
for (final long[] longArray : secondLayerLongArrayArray) {
|
||||
if (longArray != null) disposeLongArray(longArray);
|
||||
}
|
||||
}
|
||||
|
||||
// clean up everyone else
|
||||
if (generalCache != null) {
|
||||
for (Long aLong : generalCache.values()) {
|
||||
@@ -485,56 +452,18 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SparseBitShiftingTwoLayerArray {
|
||||
final long[][] cache;
|
||||
final int shift;
|
||||
final int secondLayerLength;
|
||||
|
||||
SparseBitShiftingTwoLayerArray(final int size, final int shift) {
|
||||
this.shift = shift;
|
||||
this.cache = new long[1 << shift][];
|
||||
this.secondLayerLength = size >> shift;
|
||||
}
|
||||
|
||||
public long get(final int index) {
|
||||
final int firstIndex = index >> shift;
|
||||
final long[] firstLayerRow = cache[firstIndex];
|
||||
if (firstLayerRow == null) return 0L;
|
||||
return firstLayerRow[index - (firstIndex * (1 << shift))];
|
||||
}
|
||||
|
||||
public void put(final int index, final long value) {
|
||||
final int firstIndex = index >> shift;
|
||||
long[] firstLayerRow = cache[firstIndex];
|
||||
if (firstLayerRow == null) {
|
||||
cache[firstIndex] = firstLayerRow = new long[secondLayerLength];
|
||||
}
|
||||
firstLayerRow[index - (firstIndex * (1 << shift))] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class GlyphAdvanceCache {
|
||||
private static final int FIRST_LAYER_SIZE = 256;
|
||||
private static final int SECOND_LAYER_SIZE = 16384; // 16384 = 128x128
|
||||
|
||||
private final float[] firstLayerCache = new float[FIRST_LAYER_SIZE];
|
||||
private SparseBitShiftingTwoLayerArray secondLayerCache;
|
||||
private HashMap<Integer, Float> generalCache;
|
||||
|
||||
public synchronized float get(final int index) {
|
||||
if (index < 0) {
|
||||
if (-index < SECOND_LAYER_SIZE) {
|
||||
// catch common unicodes
|
||||
if (secondLayerCache == null) return 0;
|
||||
return secondLayerCache.get(-index);
|
||||
}
|
||||
} else {
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
return firstLayerCache[index];
|
||||
}
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
return firstLayerCache[index];
|
||||
}
|
||||
|
||||
if (generalCache == null) return 0;
|
||||
@@ -544,21 +473,10 @@ public final class CStrike extends PhysicalStrike {
|
||||
}
|
||||
|
||||
public synchronized void put(final int index, final float value) {
|
||||
if (index < 0) {
|
||||
if (-index < SECOND_LAYER_SIZE) {
|
||||
// catch common unicodes
|
||||
if (secondLayerCache == null) {
|
||||
secondLayerCache = new SparseBitShiftingTwoLayerArray(SECOND_LAYER_SIZE, 7); // 128x128
|
||||
}
|
||||
secondLayerCache.put(-index, value);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
firstLayerCache[index] = value;
|
||||
return;
|
||||
}
|
||||
if (index < FIRST_LAYER_SIZE) {
|
||||
// catch common glyphcodes
|
||||
firstLayerCache[index] = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (generalCache == null) {
|
||||
@@ -567,34 +485,5 @@ public final class CStrike extends PhysicalStrike {
|
||||
|
||||
generalCache.put(Integer.valueOf(index), Float.valueOf(value));
|
||||
}
|
||||
|
||||
private static class SparseBitShiftingTwoLayerArray {
|
||||
final float[][] cache;
|
||||
final int shift;
|
||||
final int secondLayerLength;
|
||||
|
||||
SparseBitShiftingTwoLayerArray(final int size, final int shift) {
|
||||
this.shift = shift;
|
||||
this.cache = new float[1 << shift][];
|
||||
this.secondLayerLength = size >> shift;
|
||||
}
|
||||
|
||||
public float get(final int index) {
|
||||
final int firstIndex = index >> shift;
|
||||
final float[] firstLayerRow = cache[firstIndex];
|
||||
if (firstLayerRow == null) return 0L;
|
||||
return firstLayerRow[index - (firstIndex * (1 << shift))];
|
||||
}
|
||||
|
||||
public void put(final int index, final float value) {
|
||||
final int firstIndex = index >> shift;
|
||||
float[] firstLayerRow = cache[firstIndex];
|
||||
if (firstLayerRow == null) {
|
||||
cache[firstIndex] = firstLayerRow =
|
||||
new float[secondLayerLength];
|
||||
}
|
||||
firstLayerRow[index - (firstIndex * (1 << shift))] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,51 +41,6 @@ static const CGAffineTransform sInverseTX = { 1, 0, 0, -1, 0, 0 };
|
||||
#pragma mark --- CoreText Support ---
|
||||
|
||||
|
||||
// Translates a Unicode into a CGGlyph/CTFontRef pair
|
||||
// Returns the substituted font, and places the appropriate glyph into "glyphRef"
|
||||
CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForUnicode
|
||||
(const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count) {
|
||||
CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, charRef, count);
|
||||
if (fallback == NULL)
|
||||
{
|
||||
// use the original font if we somehow got duped into trying to fallback something we can't
|
||||
fallback = (CTFontRef)font->fFont;
|
||||
CFRetain(fallback);
|
||||
}
|
||||
|
||||
CTFontGetGlyphsForCharacters(fallback, charRef, glyphRef, count);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
// Translates a Java glyph code int (might be a negative unicode value) into a CGGlyph/CTFontRef pair
|
||||
// Returns the substituted font, and places the appropriate glyph into "glyph"
|
||||
CTFontRef JavaCT_CopyCTFallbackFontAndGlyphForJavaGlyphCode
|
||||
(const AWTFont *font, const jint glyphCode, CGGlyph *glyphRef)
|
||||
{
|
||||
// negative glyph codes are really unicodes, which were placed there by the mapper
|
||||
// to indicate we should use CoreText to substitute the character
|
||||
if (glyphCode >= 0)
|
||||
{
|
||||
*glyphRef = glyphCode;
|
||||
CFRetain(font->fFont);
|
||||
return (CTFontRef)font->fFont;
|
||||
}
|
||||
|
||||
UTF16Char character = -glyphCode;
|
||||
return JavaCT_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
|
||||
}
|
||||
|
||||
// Breakup a 32 bit unicode value into the component surrogate pairs
|
||||
void JavaCT_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]) {
|
||||
int value = uniChar - 0x10000;
|
||||
UTF16Char low_surrogate = (value & 0x3FF) | LO_SURROGATE_START;
|
||||
UTF16Char high_surrogate = (((int)(value & 0xFFC00)) >> 10) | HI_SURROGATE_START;
|
||||
charRef[0] = high_surrogate;
|
||||
charRef[1] = low_surrogate;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Callback for CoreText which uses the CoreTextProviderStruct to feed CT UniChars
|
||||
* We only use it for one-off lines, and don't attempt to fragment our strings
|
||||
@@ -129,7 +84,7 @@ static NSDictionary* ctsDictionaryFor(const NSFont *font, BOOL useFractionalMetr
|
||||
// Itterates though each glyph, and if a transform is present for that glyph, apply it to the CGContext, and strike the glyph.
|
||||
// If there is no per-glyph transform, just strike the glyph. Advances must also be transformed on-the-spot as well.
|
||||
void JavaCT_DrawGlyphVector
|
||||
(const QuartzSDOps *qsdo, const AWTStrike *strike, const BOOL useSubstituion, const int uniChars[], const CGGlyph glyphs[], CGSize advances[], const jint g_gvTXIndicesAsInts[], const jdouble g_gvTransformsAsDoubles[], const CFIndex length)
|
||||
(const QuartzSDOps *qsdo, const AWTStrike *strike, const CGGlyph glyphs[], CGSize advances[], const jint g_gvTXIndicesAsInts[], const jdouble g_gvTransformsAsDoubles[], const CFIndex length)
|
||||
{
|
||||
CGPoint pt = { 0, 0 };
|
||||
|
||||
@@ -137,49 +92,12 @@ void JavaCT_DrawGlyphVector
|
||||
CGContextRef cgRef = qsdo->cgRef;
|
||||
CGAffineTransform ctmText = CGContextGetTextMatrix(cgRef);
|
||||
|
||||
BOOL saved = false;
|
||||
|
||||
CGAffineTransform invTx = CGAffineTransformInvert(strike->fTx);
|
||||
|
||||
NSInteger i;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
CGGlyph glyph = glyphs[i];
|
||||
int uniChar = uniChars[i];
|
||||
// if we found a unichar instead of a glyph code, get the fallback font,
|
||||
// find the glyph code for the fallback font, and set the font on the current context
|
||||
if (uniChar != 0)
|
||||
{
|
||||
CTFontRef fallback;
|
||||
if (uniChar > 0xFFFF) {
|
||||
UTF16Char charRef[2];
|
||||
JavaCT_BreakupUnicodeIntoSurrogatePairs(uniChar, charRef);
|
||||
CGGlyph glyphTmp[2];
|
||||
fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);
|
||||
glyph = glyphTmp[0];
|
||||
} else {
|
||||
const UTF16Char u = uniChar;
|
||||
fallback = JavaCT_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, &u, (CGGlyph *)&glyph, 1);
|
||||
}
|
||||
if (fallback) {
|
||||
const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
|
||||
CFRelease(fallback);
|
||||
|
||||
if (cgFallback) {
|
||||
if (!saved) {
|
||||
CGContextSaveGState(cgRef);
|
||||
saved = true;
|
||||
}
|
||||
CGContextSetFont(cgRef, cgFallback);
|
||||
CFRelease(cgFallback);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (saved) {
|
||||
CGContextRestoreGState(cgRef);
|
||||
saved = false;
|
||||
}
|
||||
}
|
||||
|
||||
// if we have per-glyph transformations
|
||||
int tin = (g_gvTXIndicesAsInts == NULL) ? -1 : (g_gvTXIndicesAsInts[i] - 1) * 6;
|
||||
@@ -214,10 +132,6 @@ void JavaCT_DrawGlyphVector
|
||||
pt.y += advances[i].height;
|
||||
|
||||
}
|
||||
// reset the font on the context after striking a unicode with CoreText
|
||||
if (saved) {
|
||||
CGContextRestoreGState(cgRef);
|
||||
}
|
||||
}
|
||||
|
||||
// Using the Quartz Surface Data context, draw a hot-substituted character run
|
||||
@@ -327,24 +241,16 @@ static jclass jc_StandardGlyphVector = NULL;
|
||||
// Checks the GlyphVector Java object for any transforms that were applied to individual characters. If none are present,
|
||||
// strike the glyphs immediately in Core Graphics. Otherwise, obtain the arrays, and defer to above.
|
||||
static inline void doDrawGlyphsPipe_checkForPerGlyphTransforms
|
||||
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, BOOL useSubstituion, int *uniChars, CGGlyph *glyphs, CGSize *advances, size_t length)
|
||||
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, CGGlyph *glyphs, CGSize *advances, size_t length)
|
||||
{
|
||||
// if we have no character substitution, and no per-glyph transformations - strike now!
|
||||
// if we have no per-glyph transformations - strike now!
|
||||
GET_SGV_CLASS();
|
||||
DECLARE_FIELD(jm_StandardGlyphVector_gti, jc_StandardGlyphVector, "gti", "Lsun/font/StandardGlyphVector$GlyphTransformInfo;");
|
||||
jobject gti = (*env)->GetObjectField(env, gVector, jm_StandardGlyphVector_gti);
|
||||
if (gti == 0)
|
||||
{
|
||||
if (useSubstituion)
|
||||
{
|
||||
// quasi-simple case, substitution, but no per-glyph transforms
|
||||
JavaCT_DrawGlyphVector(qsdo, strike, TRUE, uniChars, glyphs, advances, NULL, NULL, length);
|
||||
}
|
||||
else
|
||||
{
|
||||
// fast path, straight to CG without per-glyph transforms
|
||||
CGContextShowGlyphsWithAdvances(qsdo->cgRef, glyphs, advances, length);
|
||||
}
|
||||
// fast path, straight to CG without per-glyph transforms
|
||||
CGContextShowGlyphsWithAdvances(qsdo->cgRef, glyphs, advances, length);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -369,8 +275,8 @@ static inline void doDrawGlyphsPipe_checkForPerGlyphTransforms
|
||||
(*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
|
||||
return;
|
||||
}
|
||||
// slowest case, we have per-glyph transforms, and possibly glyph substitution as well
|
||||
JavaCT_DrawGlyphVector(qsdo, strike, useSubstituion, uniChars, glyphs, advances, g_gvTXIndicesAsInts, g_gvTransformsAsDoubles, length);
|
||||
// slowest case, we have per-glyph transforms
|
||||
JavaCT_DrawGlyphVector(qsdo, strike, glyphs, advances, g_gvTXIndicesAsInts, g_gvTransformsAsDoubles, length);
|
||||
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, g_gtiTransformsArray, g_gvTransformsAsDoubles, JNI_ABORT);
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, g_gtiTXIndicesArray, g_gvTXIndicesAsInts, JNI_ABORT);
|
||||
@@ -379,35 +285,11 @@ static inline void doDrawGlyphsPipe_checkForPerGlyphTransforms
|
||||
(*env)->DeleteLocalRef(env, g_gtiTXIndicesArray);
|
||||
}
|
||||
|
||||
// Retrieves advances for translated unicodes
|
||||
// Uses "glyphs" as a temporary buffer for the glyph-to-unicode translation
|
||||
void JavaCT_GetAdvancesForUnichars
|
||||
(const NSFont *font, const int uniChars[], CGGlyph glyphs[], const size_t length, CGSize advances[])
|
||||
{
|
||||
// cycle over each spot, and if we discovered a unicode to substitute, we have to calculate the advance for it
|
||||
size_t i;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
UniChar uniChar = uniChars[i];
|
||||
if (uniChar == 0) continue;
|
||||
|
||||
CGGlyph glyph = 0;
|
||||
const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font, &uniChar, 1);
|
||||
if (fallback) {
|
||||
CTFontGetGlyphsForCharacters(fallback, &uniChar, &glyph, 1);
|
||||
CTFontGetAdvancesForGlyphs(fallback, kCTFontDefaultOrientation, &glyph, &(advances[i]), 1);
|
||||
CFRelease(fallback);
|
||||
}
|
||||
|
||||
glyphs[i] = glyph;
|
||||
}
|
||||
}
|
||||
|
||||
// Fills the glyph buffer with glyphs from the GlyphVector object. Also checks to see if the glyph's positions have been
|
||||
// already caculated from GlyphVector, or we simply ask Core Graphics to make some advances for us. Pre-calculated positions
|
||||
// are translated into advances, since CG only understands advances.
|
||||
static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers
|
||||
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, CGGlyph *glyphs, int *uniChars, CGSize *advances, size_t length, jintArray glyphsArray)
|
||||
(JNIEnv *env, QuartzSDOps *qsdo, const AWTStrike *strike, jobject gVector, CGGlyph *glyphs, CGSize *advances, size_t length, jintArray glyphsArray)
|
||||
{
|
||||
// fill the glyph buffer
|
||||
jint *glyphsAsInts = (*env)->GetPrimitiveArrayCritical(env, glyphsArray, NULL);
|
||||
@@ -415,24 +297,10 @@ static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers
|
||||
return;
|
||||
}
|
||||
|
||||
// if a glyph code from Java is negative, that means it is really a unicode value
|
||||
// which we can use in CoreText to strike the character in another font
|
||||
size_t i;
|
||||
BOOL complex = NO;
|
||||
for (i = 0; i < length; i++)
|
||||
{
|
||||
jint code = glyphsAsInts[i];
|
||||
if (code < 0)
|
||||
{
|
||||
complex = YES;
|
||||
uniChars[i] = -code;
|
||||
glyphs[i] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
uniChars[i] = 0;
|
||||
glyphs[i] = code;
|
||||
}
|
||||
glyphs[i] = glyphsAsInts[i];
|
||||
}
|
||||
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, glyphsArray, glyphsAsInts, JNI_ABORT);
|
||||
@@ -483,15 +351,10 @@ static inline void doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers
|
||||
// there were no pre-calculated positions from the glyph buffer on the Java side
|
||||
AWTFont *awtFont = strike->fAWTFont;
|
||||
CTFontGetAdvancesForGlyphs((CTFontRef)awtFont->fFont, kCTFontDefaultOrientation, glyphs, advances, length);
|
||||
|
||||
if (complex)
|
||||
{
|
||||
JavaCT_GetAdvancesForUnichars(awtFont->fFont, uniChars, glyphs, length, advances);
|
||||
}
|
||||
}
|
||||
|
||||
// continue on to the next stage of the pipe
|
||||
doDrawGlyphsPipe_checkForPerGlyphTransforms(env, qsdo, strike, gVector, complex, uniChars, glyphs, advances, length);
|
||||
doDrawGlyphsPipe_checkForPerGlyphTransforms(env, qsdo, strike, gVector, glyphs, advances, length);
|
||||
}
|
||||
|
||||
// Obtains the glyph array to determine the number of glyphs we are dealing with. If we are dealing a large number of glyphs,
|
||||
@@ -515,18 +378,16 @@ static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
|
||||
{
|
||||
// if we are small enough, fit everything onto the stack
|
||||
CGGlyph glyphs[length];
|
||||
int uniChars[length];
|
||||
CGSize advances[length];
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, advances, length, glyphsArray);
|
||||
}
|
||||
else
|
||||
{
|
||||
// otherwise, we should malloc and free buffers for this large run
|
||||
CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * length);
|
||||
int *uniChars = (int *)malloc(sizeof(int) * length);
|
||||
CGSize *advances = (CGSize *)malloc(sizeof(CGSize) * length);
|
||||
|
||||
if (glyphs == NULL || uniChars == NULL || advances == NULL)
|
||||
if (glyphs == NULL || advances == NULL)
|
||||
{
|
||||
(*env)->DeleteLocalRef(env, glyphsArray);
|
||||
[NSException raise:NSMallocException format:@"%s-%s:%d", __FILE__, __FUNCTION__, __LINE__];
|
||||
@@ -534,10 +395,6 @@ static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
|
||||
{
|
||||
free(glyphs);
|
||||
}
|
||||
if (uniChars)
|
||||
{
|
||||
free(uniChars);
|
||||
}
|
||||
if (advances)
|
||||
{
|
||||
free(advances);
|
||||
@@ -545,10 +402,9 @@ static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
|
||||
return;
|
||||
}
|
||||
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
|
||||
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, advances, length, glyphsArray);
|
||||
|
||||
free(glyphs);
|
||||
free(uniChars);
|
||||
free(advances);
|
||||
}
|
||||
|
||||
|
||||
@@ -3341,6 +3341,64 @@ Java_sun_awt_FontDescriptor_initIDs
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Class: sun_font_CFont
|
||||
* Method: getCascadeList
|
||||
* Signature: (JLjava/util/ArrayList;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_sun_font_CFont_getCascadeList
|
||||
(JNIEnv *env, jclass cls, jlong awtFontPtr, jobject arrayListOfString)
|
||||
{
|
||||
JNI_COCOA_ENTER(env);
|
||||
jclass alc = (*env)->FindClass(env, "java/util/ArrayList");
|
||||
if (alc == NULL) return;
|
||||
jmethodID addMID = (*env)->GetMethodID(env, alc, "add", "(Ljava/lang/Object;)Z");
|
||||
if (addMID == NULL) return;
|
||||
|
||||
CFIndex i;
|
||||
AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
|
||||
NSFont* nsFont = awtFont->fFont;
|
||||
#ifdef DEBUG
|
||||
CFStringRef base = CTFontCopyFullName((CTFontRef)nsFont);
|
||||
NSLog(@"BaseFont is : %@", (NSString*)base);
|
||||
CFRelease(base);
|
||||
#endif
|
||||
bool anotherBaseFont = false;
|
||||
if (awtFont->fFallbackBase != nil) {
|
||||
nsFont = awtFont->fFallbackBase;
|
||||
anotherBaseFont = true;
|
||||
}
|
||||
CTFontRef font = (CTFontRef)nsFont;
|
||||
CFArrayRef codes = CFLocaleCopyISOLanguageCodes();
|
||||
|
||||
CFArrayRef fds = CTFontCopyDefaultCascadeListForLanguages(font, codes);
|
||||
CFRelease(codes);
|
||||
CFIndex cnt = CFArrayGetCount(fds);
|
||||
for (i= anotherBaseFont ? -1 : 0; i<cnt; i++) {
|
||||
CFStringRef fontname;
|
||||
if (i < 0) {
|
||||
fontname = CTFontCopyPostScriptName(font);
|
||||
} else {
|
||||
CTFontDescriptorRef ref = CFArrayGetValueAtIndex(fds, i);
|
||||
fontname = CTFontDescriptorCopyAttribute(ref, kCTFontNameAttribute);
|
||||
}
|
||||
#ifdef DEBUG
|
||||
NSLog(@"Font is : %@", (NSString*)fontname);
|
||||
#endif
|
||||
jstring jFontName = (jstring)NSStringToJavaString(env, fontname);
|
||||
CFRelease(fontname);
|
||||
(*env)->CallBooleanMethod(env, arrayListOfString, addMID, jFontName);
|
||||
if ((*env)->ExceptionOccurred(env)) {
|
||||
CFRelease(fds);
|
||||
return;
|
||||
}
|
||||
(*env)->DeleteLocalRef(env, jFontName);
|
||||
}
|
||||
CFRelease(fds);
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
static CFStringRef EMOJI_FONT_NAME = CFSTR("Apple Color Emoji");
|
||||
|
||||
bool IsEmojiFont(CTFontRef font)
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#import "sun_font_CStrikeDisposer.h"
|
||||
#import "CGGlyphImages.h"
|
||||
#import "CGGlyphOutlines.h"
|
||||
#import "CoreTextSupport.h"
|
||||
#import "JNIUtilities.h"
|
||||
#include "fontscalerdefs.h"
|
||||
#import "LWCToolkit.h"
|
||||
@@ -160,12 +159,8 @@ JNI_COCOA_ENTER(env);
|
||||
AWTStrike *awtStrike = (AWTStrike *)jlong_to_ptr(awtStrikePtr);
|
||||
AWTFont *awtFont = awtStrike->fAWTFont;
|
||||
|
||||
// negative glyph codes are really unicodes, which were placed there by the mapper
|
||||
// to indicate we should use CoreText to substitute the character
|
||||
CGGlyph glyph;
|
||||
const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);
|
||||
CGGlyphImages_GetGlyphMetrics(fallback, &awtStrike->fAltTx, awtStrike->fSize, awtStrike->fStyle, &glyph, 1, NULL, &advance, IS_OSX_GT10_14);
|
||||
CFRelease(fallback);
|
||||
CGGlyph glyph = glyphCode;
|
||||
CGGlyphImages_GetGlyphMetrics((CTFontRef)awtFont->fFont, &awtStrike->fAltTx, awtStrike->fSize, awtStrike->fStyle, &glyph, 1, NULL, &advance, IS_OSX_GT10_14);
|
||||
advance = CGSizeApplyAffineTransform(advance, awtStrike->fFontTx);
|
||||
if (!JRSFontStyleUsesFractionalMetrics(awtStrike->fStyle)) {
|
||||
advance.width = round(advance.width);
|
||||
@@ -195,14 +190,9 @@ JNI_COCOA_ENTER(env);
|
||||
tx.tx += x;
|
||||
tx.ty += y;
|
||||
|
||||
// negative glyph codes are really unicodes, which were placed there by the mapper
|
||||
// to indicate we should use CoreText to substitute the character
|
||||
CGGlyph glyph;
|
||||
const CTFontRef fallback = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtFont, glyphCode, &glyph);
|
||||
|
||||
CGGlyph glyph = glyphCode;
|
||||
CGRect bbox;
|
||||
CGGlyphImages_GetGlyphMetrics(fallback, &tx, awtStrike->fSize, awtStrike->fStyle, &glyph, 1, &bbox, NULL, IS_OSX_GT10_14);
|
||||
CFRelease(fallback);
|
||||
CGGlyphImages_GetGlyphMetrics((CTFontRef)awtFont->fFont, &tx, awtStrike->fSize, awtStrike->fStyle, &glyph, 1, &bbox, NULL, IS_OSX_GT10_14);
|
||||
|
||||
// the origin of this bounding box is relative to the bottom-left corner baseline
|
||||
CGFloat decender = -bbox.origin.y;
|
||||
@@ -251,14 +241,12 @@ AWT_FONT_CLEANUP_CHECK(awtfont);
|
||||
tx.tx += xPos;
|
||||
tx.ty += yPos;
|
||||
|
||||
// get the right font and glyph for this "Java GlyphCode"
|
||||
|
||||
CGGlyph glyph;
|
||||
const CTFontRef font = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(awtfont, glyphCode, &glyph);
|
||||
CGGlyph glyph = glyphCode;
|
||||
NSFont *font = awtfont->fFont;
|
||||
|
||||
// get the advance of this glyph
|
||||
CGSize advance;
|
||||
CTFontGetAdvancesForGlyphs(font, kCTFontDefaultOrientation, &glyph, &advance, 1);
|
||||
CTFontGetAdvancesForGlyphs((CTFontRef)font, kCTFontDefaultOrientation, &glyph, &advance, 1);
|
||||
|
||||
// Create AWTPath
|
||||
path = AWTPathCreate(CGSizeMake(xPos, yPos));
|
||||
@@ -267,8 +255,7 @@ AWT_FONT_CLEANUP_CHECK(path);
|
||||
// Get the paths
|
||||
tx = awtStrike->fTx;
|
||||
tx = CGAffineTransformConcat(tx, sInverseTX);
|
||||
AWTGetGlyphOutline(&glyph, (NSFont *)font, &advance, &tx, 0, 1, &path);
|
||||
CFRelease(font);
|
||||
AWTGetGlyphOutline(&glyph, font, &advance, &tx, 0, 1, &path);
|
||||
|
||||
pointCoords = (*env)->NewFloatArray(env, path->fNumberOfDataElements);
|
||||
AWT_FONT_CLEANUP_CHECK(pointCoords);
|
||||
@@ -322,19 +309,14 @@ JNIEXPORT void JNICALL Java_sun_font_CStrike_getNativeGlyphOutlineBounds
|
||||
AWT_FONT_CLEANUP_SETUP;
|
||||
AWT_FONT_CLEANUP_CHECK(awtfont);
|
||||
|
||||
// get the right font and glyph for this "Java GlyphCode"
|
||||
CGGlyph glyph;
|
||||
const CTFontRef font = CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(
|
||||
awtfont, glyphCode, &glyph);
|
||||
|
||||
CGGlyph glyph = glyphCode;
|
||||
CGRect bbox = CTFontGetBoundingRectsForGlyphs(
|
||||
font, kCTFontOrientationDefault, &glyph, NULL, 1);
|
||||
(CTFontRef)awtfont->fFont, kCTFontOrientationDefault, &glyph, NULL, 1);
|
||||
|
||||
CGAffineTransform tx = CGAffineTransformConcat(awtStrike->fTx,
|
||||
sInverseTX);
|
||||
|
||||
bbox = CGRectApplyAffineTransform (bbox, tx);
|
||||
CFRelease(font);
|
||||
jfloat *rawRectData =
|
||||
(*env)->GetPrimitiveArrayCritical(env, rectData, NULL);
|
||||
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#import "CoreTextSupport.h"
|
||||
|
||||
#import "sun_font_CCharToGlyphMapper.h"
|
||||
#import "sun_font_CCompositeGlyphMapper.h"
|
||||
|
||||
/*
|
||||
* Class: sun_font_CCharToGlyphMapper
|
||||
@@ -114,28 +113,3 @@ JNI_COCOA_ENTER(env);
|
||||
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_font_CCompositeGlyphMapper
|
||||
* Method: nativeCodePointToGlyph
|
||||
* Signature: (JI[Ljava/lang/String;)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_sun_font_CCompositeGlyphMapper_nativeCodePointToGlyph
|
||||
(JNIEnv *env, jclass clazz, jlong awtFontPtr, jint codePoint, jobjectArray resultArray)
|
||||
{
|
||||
JNI_COCOA_ENTER(env);
|
||||
AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
|
||||
CFStringRef fontNames[] = {NULL, NULL};
|
||||
CGGlyph glyph = CTS_CopyGlyphAndFontNamesForCodePoint(awtFont, (UnicodeScalarValue)codePoint, fontNames);
|
||||
if (glyph > 0) {
|
||||
jstring fontName = NSStringToJavaString(env, (NSString *)fontNames[0]);
|
||||
(*env)->SetObjectArrayElement(env, resultArray, 0, fontName);
|
||||
jstring fontFamilyName = NSStringToJavaString(env, (NSString *)fontNames[1]);
|
||||
(*env)->SetObjectArrayElement(env, resultArray, 1, fontFamilyName);
|
||||
}
|
||||
if (fontNames[0]) CFRelease(fontNames[0]);
|
||||
if (fontNames[1]) CFRelease(fontNames[1]);
|
||||
return glyph;
|
||||
JNI_COCOA_EXIT(env);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
#import "JNIUtilities.h"
|
||||
#import "CGGlyphImages.h"
|
||||
#import "CoreTextSupport.h"
|
||||
#import "fontscalerdefs.h" // contains the definition of GlyphInfo struct
|
||||
|
||||
#import "sun_awt_SunHints.h"
|
||||
@@ -739,78 +738,6 @@ CGGI_CreateImageForGlyph
|
||||
/*
|
||||
* CoreText path...
|
||||
*/
|
||||
static inline GlyphInfo *
|
||||
CGGI_CreateImageForUnicode
|
||||
(CGGI_GlyphCanvas *canvas, const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode, const UnicodeScalarValue uniChar,
|
||||
const bool isCatalinaOrAbove)
|
||||
{
|
||||
// save the graphics state
|
||||
CGContextSaveGState(canvas->context);
|
||||
// text matrix is not considered part of graphics state
|
||||
CGAffineTransform originalTx = CGContextGetTextMatrix(canvas->context);
|
||||
|
||||
// get the glyph, measure it using CG
|
||||
CGGlyph glyph;
|
||||
CTFontRef fallback;
|
||||
if (uniChar > 0xFFFF) {
|
||||
UTF16Char charRef[2];
|
||||
CTS_BreakupUnicodeIntoSurrogatePairs(uniChar, charRef);
|
||||
CGGlyph glyphTmp[2];
|
||||
fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, (CGGlyph *)&glyphTmp, 2);
|
||||
glyph = glyphTmp[0];
|
||||
} else {
|
||||
UTF16Char charRef;
|
||||
charRef = (UTF16Char) uniChar; // truncate.
|
||||
fallback = CTS_CopyCTFallbackFontAndGlyphForUnicode(strike->fAWTFont, (const UTF16Char *)&charRef, &glyph, 1);
|
||||
}
|
||||
|
||||
JRSFontRenderingStyle style = JRSFontAlignStyleForFractionalMeasurement(strike->fStyle);
|
||||
|
||||
CGGI_GlyphInfoDescriptor *glyphDescriptor = CGGI_GetGlyphInfoDescriptor(mode, fallback);
|
||||
|
||||
bool subpixelResolution = mode->subpixelResolution && glyphDescriptor == &grey;
|
||||
|
||||
CGRect bbox;
|
||||
CGSize advance;
|
||||
CGGlyphImages_GetGlyphMetrics(fallback, &strike->fTx, strike->fSize, style, &glyph, 1, &bbox, &advance, isCatalinaOrAbove);
|
||||
|
||||
|
||||
// create the Sun2D GlyphInfo we are going to strike into
|
||||
GlyphInfo *info = CGGI_CreateNewGlyphInfoFrom(advance, bbox, strike, glyphDescriptor, subpixelResolution);
|
||||
|
||||
// fix the context size, just in case the substituted character is unexpectedly large
|
||||
CGGI_SizeCanvas(canvas, info->width * info->subpixelResolutionX, info->height * info->subpixelResolutionY, mode);
|
||||
|
||||
// align the transform for the real CoreText strike
|
||||
CGContextSetTextMatrix(canvas->context, strike->fAltTx);
|
||||
|
||||
const CGFontRef cgFallback = CTFontCopyGraphicsFont(fallback, NULL);
|
||||
CGContextSetFont(canvas->context, cgFallback);
|
||||
CFRelease(cgFallback);
|
||||
|
||||
// clean the canvas - align, strike, and copy the glyph from the canvas into the info
|
||||
CGGI_CreateImageForGlyph(canvas, glyph, info, glyphDescriptor, strike, fallback, isCatalinaOrAbove);
|
||||
|
||||
// restore graphics state
|
||||
CGContextRestoreGState(canvas->context);
|
||||
CGContextSetTextMatrix(canvas->context, originalTx);
|
||||
|
||||
CFRelease(fallback);
|
||||
#ifdef CGGI_DEBUG
|
||||
DUMP_GLYPHINFO(info);
|
||||
#endif
|
||||
|
||||
#ifdef CGGI_DEBUG_DUMP
|
||||
DUMP_IMG_PIXELS("CGGI Canvas", canvas->image);
|
||||
#if 0
|
||||
PRINT_CGSTATES_INFO(NULL);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark --- GlyphInfo Filling and Canvas Managment ---
|
||||
|
||||
@@ -825,7 +752,6 @@ CGGI_FillImagesForGlyphsWithSizedCanvas(CGGI_GlyphCanvas *canvas,
|
||||
const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
jlong glyphInfos[],
|
||||
const UnicodeScalarValue uniChars[],
|
||||
const CGGlyph glyphs[],
|
||||
const CFIndex len)
|
||||
{
|
||||
@@ -838,13 +764,8 @@ CGGI_FillImagesForGlyphsWithSizedCanvas(CGGI_GlyphCanvas *canvas,
|
||||
CFIndex i;
|
||||
for (i = 0; i < len; i++) {
|
||||
GlyphInfo *info = (GlyphInfo *)jlong_to_ptr(glyphInfos[i]);
|
||||
if (info != NULL) {
|
||||
CGGI_CreateImageForGlyph(canvas, glyphs[i], info, mode->mainFontDescriptor,
|
||||
strike, (CTFontRef)strike->fAWTFont->fFont, isMojaveOrAbove);
|
||||
} else {
|
||||
info = CGGI_CreateImageForUnicode(canvas, strike, mode, uniChars[i], isMojaveOrAbove);
|
||||
glyphInfos[i] = ptr_to_jlong(info);
|
||||
}
|
||||
CGGI_CreateImageForGlyph(canvas, glyphs[i], info, mode->mainFontDescriptor,
|
||||
strike, (CTFontRef)strike->fAWTFont->fFont, isMojaveOrAbove);
|
||||
#ifdef CGGI_DEBUG
|
||||
DUMP_GLYPHINFO(info);
|
||||
#endif
|
||||
@@ -879,7 +800,7 @@ static NSString *threadLocalLCDCanvasKey =
|
||||
static inline void
|
||||
CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
|
||||
const CGGlyph glyphs[],
|
||||
const size_t maxWidth, const size_t maxHeight,
|
||||
const CFIndex len)
|
||||
{
|
||||
@@ -889,8 +810,7 @@ CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
|
||||
CGGI_GlyphCanvas *tmpCanvas = [[CGGI_GlyphCanvas alloc] init];
|
||||
CGGI_InitCanvas(tmpCanvas, maxWidth, maxHeight, mode);
|
||||
CGGI_FillImagesForGlyphsWithSizedCanvas(tmpCanvas, strike,
|
||||
mode, glyphInfos, uniChars,
|
||||
glyphs, len);
|
||||
mode, glyphInfos, glyphs, len);
|
||||
CGGI_FreeCanvas(tmpCanvas);
|
||||
|
||||
[tmpCanvas release];
|
||||
@@ -910,7 +830,7 @@ CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
|
||||
|
||||
CGGI_SizeCanvas(canvas, maxWidth, maxHeight, mode);
|
||||
CGGI_FillImagesForGlyphsWithSizedCanvas(canvas, strike, mode,
|
||||
glyphInfos, uniChars, glyphs, len);
|
||||
glyphInfos, glyphs, len);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -926,7 +846,7 @@ CGGI_FillImagesForGlyphs(jlong *glyphInfos, const AWTStrike *strike,
|
||||
static inline void
|
||||
CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
const UnicodeScalarValue uniChars[], const CGGlyph glyphs[],
|
||||
const CGGlyph glyphs[],
|
||||
CGSize advances[], CGRect bboxes[], const CFIndex len)
|
||||
{
|
||||
AWTFont *font = strike->fAWTFont;
|
||||
@@ -941,12 +861,6 @@ CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
|
||||
CFIndex i;
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
if (uniChars[i] != 0)
|
||||
{
|
||||
glyphInfos[i] = 0L;
|
||||
continue; // will be handled later
|
||||
}
|
||||
|
||||
CGSize advance = advances[i];
|
||||
CGRect bbox = bboxes[i];
|
||||
|
||||
@@ -963,41 +877,29 @@ CGGI_CreateGlyphInfos(jlong *glyphInfos, const AWTStrike *strike,
|
||||
glyphInfos[i] = ptr_to_jlong(glyphInfo);
|
||||
}
|
||||
|
||||
CGGI_FillImagesForGlyphs(glyphInfos, strike, mode, uniChars,
|
||||
CGGI_FillImagesForGlyphs(glyphInfos, strike, mode,
|
||||
glyphs, maxWidth, maxHeight, len);
|
||||
}
|
||||
|
||||
|
||||
#pragma mark --- Temporary Buffer Allocations and Initialization ---
|
||||
|
||||
/*
|
||||
* This stage separates the already valid glyph codes from the unicode values
|
||||
* that need special handling - the rawGlyphCodes array is no longer used
|
||||
* after this stage.
|
||||
*/
|
||||
static void
|
||||
CGGI_CreateGlyphsAndScanForComplexities(jlong *glyphInfos,
|
||||
const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
jint rawGlyphCodes[],
|
||||
UnicodeScalarValue uniChars[], CGGlyph glyphs[],
|
||||
CGSize advances[], CGRect bboxes[],
|
||||
const CFIndex len)
|
||||
CGGI_CreateGlyphs(jlong *glyphInfos,
|
||||
const AWTStrike *strike,
|
||||
const CGGI_RenderingMode *mode,
|
||||
jint rawGlyphCodes[],
|
||||
CGGlyph glyphs[],
|
||||
CGSize advances[], CGRect bboxes[],
|
||||
const CFIndex len)
|
||||
{
|
||||
CFIndex i;
|
||||
for (i = 0; i < len; i++) {
|
||||
jint code = rawGlyphCodes[i];
|
||||
if (code < 0) {
|
||||
glyphs[i] = 0;
|
||||
uniChars[i] = -code;
|
||||
} else {
|
||||
glyphs[i] = code;
|
||||
uniChars[i] = 0;
|
||||
}
|
||||
glyphs[i] = rawGlyphCodes[i];
|
||||
}
|
||||
|
||||
CGGI_CreateGlyphInfos(glyphInfos, strike, mode,
|
||||
uniChars, glyphs, advances, bboxes, len);
|
||||
glyphs, advances, bboxes, len);
|
||||
|
||||
#ifdef CGGI_DEBUG_HIT_COUNT
|
||||
static size_t hitCount = 0;
|
||||
@@ -1023,31 +925,29 @@ CGGlyphImages_GetGlyphImagePtrs(jlong glyphInfos[],
|
||||
CGRect bboxes[len];
|
||||
CGSize advances[len];
|
||||
CGGlyph glyphs[len];
|
||||
UnicodeScalarValue uniChars[len];
|
||||
|
||||
CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
|
||||
rawGlyphCodes, uniChars, glyphs,
|
||||
advances, bboxes, len);
|
||||
CGGI_CreateGlyphs(glyphInfos, strike, &mode,
|
||||
rawGlyphCodes, glyphs,
|
||||
advances, bboxes, len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// just do one malloc, and carve it up for all the buffers
|
||||
void *buffer = malloc(sizeof(CGRect) * sizeof(CGSize) *
|
||||
sizeof(CGGlyph) * sizeof(UnicodeScalarValue) * len);
|
||||
void *buffer = malloc((sizeof(CGRect) + sizeof(CGSize) + sizeof(CGGlyph)) *
|
||||
len);
|
||||
if (buffer == NULL) {
|
||||
[[NSException exceptionWithName:NSMallocException
|
||||
reason:@"Failed to allocate memory for the temporary glyph strike and measurement buffers." userInfo:nil] raise];
|
||||
}
|
||||
|
||||
CGRect *bboxes = (CGRect *)(buffer);
|
||||
CGSize *advances = (CGSize *)(bboxes + sizeof(CGRect) * len);
|
||||
CGGlyph *glyphs = (CGGlyph *)(advances + sizeof(CGGlyph) * len);
|
||||
UnicodeScalarValue *uniChars = (UnicodeScalarValue *)(glyphs + sizeof(UnicodeScalarValue) * len);
|
||||
CGSize *advances = (CGSize *)(bboxes + len);
|
||||
CGGlyph *glyphs = (CGGlyph *)(advances + len);
|
||||
|
||||
CGGI_CreateGlyphsAndScanForComplexities(glyphInfos, strike, &mode,
|
||||
rawGlyphCodes, uniChars, glyphs,
|
||||
advances, bboxes, len);
|
||||
CGGI_CreateGlyphs(glyphInfos, strike, &mode,
|
||||
rawGlyphCodes, glyphs,
|
||||
advances, bboxes, len);
|
||||
|
||||
free(buffer);
|
||||
}
|
||||
|
||||
@@ -31,37 +31,13 @@
|
||||
|
||||
#pragma mark --- CoreText Support ---
|
||||
|
||||
#define HI_SURROGATE_START 0xD800
|
||||
#define HI_SURROGATE_END 0xDBFF
|
||||
#define LO_SURROGATE_START 0xDC00
|
||||
#define LO_SURROGATE_END 0xDFFF
|
||||
|
||||
/*
|
||||
* Transform Unicode characters into glyphs.
|
||||
*
|
||||
* Fills the "glyphsAsInts" array with the glyph codes for the current font,
|
||||
* or the negative unicode value if we know the character can be hot-substituted.
|
||||
*
|
||||
* This is the heart of "Universal Font Substitution" in Java.
|
||||
* Fills the "glyphsAsInts" array with the glyph codes for the current font.
|
||||
*/
|
||||
void CTS_GetGlyphsAsIntsForCharacters(const AWTFont *font, const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[], const size_t count);
|
||||
|
||||
// Translates a Java glyph code int (might be a negative unicode value) into a CGGlyph/CTFontRef pair
|
||||
// Returns the substituted font, and places the appropriate glyph into "glyph"
|
||||
CTFontRef CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(const AWTFont *font, const jint glyphCode, CGGlyph *glyphRef);
|
||||
|
||||
// Translates a Unicode into a CGGlyph/CTFontRef pair
|
||||
// Returns the substituted font, and places the appropriate glyph into "glyphRef"
|
||||
CTFontRef CTS_CopyCTFallbackFontAndGlyphForUnicode(const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count);
|
||||
|
||||
// Transform a single Unicode character code into glyph code.
|
||||
// Names of the relevant font are also returned, if the substitution is used.
|
||||
// Non-null components of fontNames array should always be released by the calling code, regardless of the returned value.
|
||||
CGGlyph CTS_CopyGlyphAndFontNamesForCodePoint(const AWTFont *font, const UnicodeScalarValue codePoint, CFStringRef fontNames[]);
|
||||
|
||||
// Breakup a 32 bit unicode value into the component surrogate pairs
|
||||
void CTS_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]);
|
||||
|
||||
|
||||
// Basic struct that holds everything CoreText is interested in
|
||||
typedef struct CTS_ProviderStruct {
|
||||
|
||||
@@ -88,161 +88,18 @@ ReleaseCTStateDictionary(CFDictionaryRef ctStateDict)
|
||||
CFRelease(ctStateDict); // GC
|
||||
}
|
||||
|
||||
void GetFontsAndGlyphsForCharacters(CTFontRef font, CTFontRef fallbackBase,
|
||||
const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[],
|
||||
CTFontRef actualFonts[], const size_t count)
|
||||
{
|
||||
CTFontGetGlyphsForCharacters(font, unicodes, glyphs, count);
|
||||
if (!fallbackBase) fallbackBase = font;
|
||||
size_t i;
|
||||
for (i = 0; i < count; i++) {
|
||||
UniChar unicode = unicodes[i];
|
||||
UniChar nextUnicode = (i+1) < count ? unicodes[i+1] : 0;
|
||||
bool surrogatePair = unicode >= HI_SURROGATE_START && unicode <= HI_SURROGATE_END
|
||||
&& nextUnicode >= LO_SURROGATE_START && nextUnicode <= LO_SURROGATE_END;
|
||||
|
||||
CGGlyph glyph = glyphs[i];
|
||||
if (glyph > 0) {
|
||||
glyphsAsInts[i] = glyph;
|
||||
if (surrogatePair) i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters(fallbackBase, &unicodes[i], surrogatePair ? 2 : 1);
|
||||
if (fallback) {
|
||||
CTFontGetGlyphsForCharacters(fallback, &unicodes[i], &glyphs[i], surrogatePair ? 2 : 1);
|
||||
glyph = glyphs[i];
|
||||
if (actualFonts && glyph > 0) {
|
||||
actualFonts[i] = fallback;
|
||||
} else {
|
||||
CFRelease(fallback);
|
||||
}
|
||||
}
|
||||
|
||||
if (glyph > 0) {
|
||||
int codePoint = surrogatePair ? (((int)(unicode - HI_SURROGATE_START)) << 10)
|
||||
+ nextUnicode - LO_SURROGATE_START + 0x10000 : unicode;
|
||||
glyphsAsInts[i] = -codePoint; // set the glyph code to the negative unicode value
|
||||
} else {
|
||||
glyphsAsInts[i] = 0; // CoreText couldn't find a glyph for this character either
|
||||
}
|
||||
if (surrogatePair) i++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Transform Unicode characters into glyphs.
|
||||
*
|
||||
* Fills the "glyphsAsInts" array with the glyph codes for the current font,
|
||||
* or the negative unicode value if we know the character can be hot-substituted.
|
||||
*
|
||||
* This is the heart of "Universal Font Substitution" in Java.
|
||||
* Fills the "glyphsAsInts" array with the glyph codes for the current font.
|
||||
*/
|
||||
void CTS_GetGlyphsAsIntsForCharacters
|
||||
(const AWTFont *font, const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[], const size_t count)
|
||||
{
|
||||
GetFontsAndGlyphsForCharacters((CTFontRef)font->fFont, (CTFontRef)font->fFallbackBase,
|
||||
unicodes, glyphs, glyphsAsInts, NULL, count);
|
||||
}
|
||||
CTFontGetGlyphsForCharacters((CTFontRef)font->fFont, unicodes, glyphs, count);
|
||||
|
||||
/*
|
||||
* Returns glyph code for a given Unicode character.
|
||||
* Names of the corresponding substituted font are also returned if substitution is performed.
|
||||
*/
|
||||
CGGlyph CTS_CopyGlyphAndFontNamesForCodePoint
|
||||
(const AWTFont *font, const UnicodeScalarValue codePoint, CFStringRef fontNames[])
|
||||
{
|
||||
CTFontRef fontRef = (CTFontRef)font->fFont;
|
||||
CTFontRef fallbackBase = (CTFontRef)font->fFallbackBase;
|
||||
int count = codePoint >= 0x10000 ? 2 : 1;
|
||||
UTF16Char unicodes[count];
|
||||
if (count == 1) {
|
||||
unicodes[0] = (UTF16Char)codePoint;
|
||||
} else {
|
||||
CTS_BreakupUnicodeIntoSurrogatePairs(codePoint, unicodes);
|
||||
}
|
||||
CGGlyph glyphs[count];
|
||||
jint glyphsAsInts[count];
|
||||
CTFontRef actualFonts[count];
|
||||
GetFontsAndGlyphsForCharacters(fontRef, fallbackBase, unicodes, glyphs, glyphsAsInts, actualFonts, count);
|
||||
CGGlyph glyph = glyphs[0];
|
||||
bool substitutionHappened = glyphsAsInts[0] < 0;
|
||||
if (glyph > 0 && substitutionHappened) {
|
||||
CTFontRef actualFont = actualFonts[0];
|
||||
CFStringRef fontName = CTFontCopyPostScriptName(actualFont);
|
||||
CFStringRef familyName = CTFontCopyFamilyName(actualFont);
|
||||
CFRelease(actualFont);
|
||||
fontNames[0] = fontName;
|
||||
fontNames[1] = familyName;
|
||||
if (!fontName || !familyName) glyph = 0;
|
||||
}
|
||||
return glyph;
|
||||
}
|
||||
|
||||
/*
|
||||
* Translates a Unicode into a CGGlyph/CTFontRef pair
|
||||
* Returns the substituted font, and places the appropriate glyph into "glyphRef"
|
||||
*/
|
||||
CTFontRef CTS_CopyCTFallbackFontAndGlyphForUnicode
|
||||
(const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count) {
|
||||
CTFontRef primary = (CTFontRef)font->fFont;
|
||||
CTFontRef fallbackBase = (CTFontRef)font->fFallbackBase;
|
||||
if (fallbackBase) {
|
||||
CTFontGetGlyphsForCharacters(primary, charRef, glyphRef, count);
|
||||
if (glyphRef[0] > 0) {
|
||||
CFRetain(primary);
|
||||
return primary;
|
||||
}
|
||||
} else {
|
||||
fallbackBase = primary;
|
||||
}
|
||||
CTFontRef fallback = JRSFontCreateFallbackFontForCharacters(fallbackBase, charRef, count);
|
||||
if (fallback == NULL)
|
||||
{
|
||||
// use the original font if we somehow got duped into trying to fallback something we can't
|
||||
fallback = (CTFontRef)font->fFont;
|
||||
CFRetain(fallback);
|
||||
}
|
||||
|
||||
CTFontGetGlyphsForCharacters(fallback, charRef, glyphRef, count);
|
||||
return fallback;
|
||||
}
|
||||
|
||||
/*
|
||||
* Translates a Java glyph code int (might be a negative unicode value) into a CGGlyph/CTFontRef pair
|
||||
* Returns the substituted font, and places the appropriate glyph into "glyphRef"
|
||||
*/
|
||||
CTFontRef CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode
|
||||
(const AWTFont *font, const jint glyphCode, CGGlyph *glyphRef)
|
||||
{
|
||||
// negative glyph codes are really unicodes, which were placed there by the mapper
|
||||
// to indicate we should use CoreText to substitute the character
|
||||
if (glyphCode >= 0)
|
||||
{
|
||||
*glyphRef = glyphCode;
|
||||
CFRetain(font->fFont);
|
||||
return (CTFontRef)font->fFont;
|
||||
}
|
||||
|
||||
int codePoint = -glyphCode;
|
||||
if (codePoint >= 0x10000) {
|
||||
UTF16Char chars[2];
|
||||
CGGlyph glyphs[2];
|
||||
CTS_BreakupUnicodeIntoSurrogatePairs(codePoint, chars);
|
||||
CTFontRef result = CTS_CopyCTFallbackFontAndGlyphForUnicode(font, chars, glyphs, 2);
|
||||
*glyphRef = glyphs[0];
|
||||
return result;
|
||||
} else {
|
||||
UTF16Char character = codePoint;
|
||||
return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
|
||||
size_t i;
|
||||
for (i = 0; i < count; i++) {
|
||||
glyphsAsInts[i] = glyphs[i];
|
||||
}
|
||||
}
|
||||
|
||||
// Breakup a 32 bit unicode value into the component surrogate pairs
|
||||
void CTS_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]) {
|
||||
int value = uniChar - 0x10000;
|
||||
UTF16Char low_surrogate = (value & 0x3FF) | LO_SURROGATE_START;
|
||||
UTF16Char high_surrogate = (((int)(value & 0xFFC00)) >> 10) | HI_SURROGATE_START;
|
||||
charRef[0] = high_surrogate;
|
||||
charRef[1] = low_surrogate;
|
||||
}
|
||||
|
||||
@@ -67,6 +67,7 @@ import sun.font.FontDesignMetrics;
|
||||
import sun.font.FontLineMetrics;
|
||||
import sun.font.FontManager;
|
||||
import sun.font.FontManagerFactory;
|
||||
import sun.font.FontSubstitution;
|
||||
import sun.font.FontUtilities;
|
||||
import sun.font.GlyphLayout;
|
||||
import sun.font.StandardGlyphVector;
|
||||
@@ -266,6 +267,11 @@ public class Font implements java.io.Serializable
|
||||
return font.getFont2D();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Font2D getFont2DWithSubstitution(Font font) {
|
||||
return font.getFont2DWithSubstitution();
|
||||
}
|
||||
|
||||
public void setFont2D(Font font, Font2DHandle handle) {
|
||||
font.font2DHandle = handle;
|
||||
}
|
||||
@@ -537,6 +543,11 @@ public class Font implements java.io.Serializable
|
||||
return font2DHandle.font2D;
|
||||
}
|
||||
|
||||
private Font2D getFont2DWithSubstitution() {
|
||||
Font2D font2D = getFont2D();
|
||||
return font2D instanceof FontSubstitution ? ((FontSubstitution) font2D).getCompositeFont2D() : font2D;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@code Font} from the specified name, style and
|
||||
* point size.
|
||||
@@ -2223,7 +2234,7 @@ public class Font implements java.io.Serializable
|
||||
* @since 1.2
|
||||
*/
|
||||
public boolean canDisplay(char c){
|
||||
return getFont2D().canDisplay(c);
|
||||
return getFont2DWithSubstitution().canDisplay(c);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2244,7 +2255,7 @@ public class Font implements java.io.Serializable
|
||||
throw new IllegalArgumentException("invalid code point: " +
|
||||
Integer.toHexString(codePoint));
|
||||
}
|
||||
return getFont2D().canDisplay(codePoint);
|
||||
return getFont2DWithSubstitution().canDisplay(codePoint);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2265,7 +2276,7 @@ public class Font implements java.io.Serializable
|
||||
* @since 1.2
|
||||
*/
|
||||
public int canDisplayUpTo(String str) {
|
||||
Font2D font2d = getFont2D();
|
||||
Font2D font2d = getFont2DWithSubstitution();
|
||||
int len = str.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = str.charAt(i);
|
||||
@@ -2303,7 +2314,7 @@ public class Font implements java.io.Serializable
|
||||
* @since 1.2
|
||||
*/
|
||||
public int canDisplayUpTo(char[] text, int start, int limit) {
|
||||
Font2D font2d = getFont2D();
|
||||
Font2D font2d = getFont2DWithSubstitution();
|
||||
for (int i = start; i < limit; i++) {
|
||||
char c = text[i];
|
||||
if (font2d.canDisplay(c)) {
|
||||
@@ -2338,7 +2349,7 @@ public class Font implements java.io.Serializable
|
||||
* @since 1.2
|
||||
*/
|
||||
public int canDisplayUpTo(CharacterIterator iter, int start, int limit) {
|
||||
Font2D font2d = getFont2D();
|
||||
Font2D font2d = getFont2DWithSubstitution();
|
||||
char c = iter.setIndex(start);
|
||||
for (int i = start; i < limit; i++, c = iter.next()) {
|
||||
if (font2d.canDisplay(c)) {
|
||||
|
||||
@@ -38,7 +38,7 @@ import java.awt.Font;
|
||||
* But its probably OK to include it so long as only composites include
|
||||
* fallbacks. If physicals do then it would be really confusing ..
|
||||
*/
|
||||
public class CompositeFont extends Font2D {
|
||||
public final class CompositeFont extends Font2D {
|
||||
|
||||
private boolean[] deferredInitialisation;
|
||||
String[] componentFileNames;
|
||||
|
||||
@@ -108,7 +108,7 @@ public class CompositeGlyphMapper extends CharToGlyphMapper {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
protected int convertToGlyph(int unicode) {
|
||||
private int convertToGlyph(int unicode) {
|
||||
|
||||
for (int slot = 0; slot < font.numSlots; slot++) {
|
||||
if (!hasExcludes || !font.isExcludedChar(slot, unicode)) {
|
||||
|
||||
@@ -335,7 +335,7 @@ public abstract class Font2D {
|
||||
return getStrike(desc, true);
|
||||
}
|
||||
|
||||
FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
|
||||
private FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
|
||||
/* Before looking in the map, see if the descriptor matches the
|
||||
* last strike returned from this Font2D. This should often be a win
|
||||
* since its common for the same font, in the same size to be
|
||||
|
||||
@@ -43,6 +43,7 @@ public abstract class FontAccess {
|
||||
}
|
||||
|
||||
public abstract Font2D getFont2D(Font f);
|
||||
public abstract Font2D getFont2DWithSubstitution(Font f);
|
||||
public abstract void setFont2D(Font f, Font2DHandle h);
|
||||
public abstract void setCreatedFont(Font f);
|
||||
public abstract boolean isCreatedFont(Font f);
|
||||
|
||||
@@ -356,7 +356,7 @@ public final class FontDesignMetrics extends FontMetrics {
|
||||
|
||||
private void initMatrixAndMetrics() {
|
||||
|
||||
Font2D font2D = FontUtilities.getFont2D(font);
|
||||
Font2D font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
fontStrike = font2D.getStrike(font, frc);
|
||||
StrikeMetrics metrics = fontStrike.getFontMetrics();
|
||||
this.ascent = metrics.getAscent();
|
||||
|
||||
@@ -266,12 +266,12 @@ public class FontFamily {
|
||||
doSetFont(fontAndStyle.font, fontAndStyle.style);
|
||||
}
|
||||
if (italic == null && plain instanceof FontWithDerivedItalic) {
|
||||
italic = ((FontWithDerivedItalic)plain).createItalic();
|
||||
italic = ((FontWithDerivedItalic)plain).createItalicVariant();
|
||||
}
|
||||
if (bolditalic == null) {
|
||||
Font2D boldItalicPrototype = bold != null ? bold : plain;
|
||||
if (boldItalicPrototype instanceof FontWithDerivedItalic) {
|
||||
bolditalic = ((FontWithDerivedItalic)boldItalicPrototype).createItalic();
|
||||
bolditalic = ((FontWithDerivedItalic)boldItalicPrototype).createItalicVariant();
|
||||
}
|
||||
}
|
||||
fontSequence.clear();
|
||||
|
||||
@@ -168,6 +168,10 @@ public final class FontUtilities {
|
||||
return FontAccess.getFontAccess().getFont2D(font);
|
||||
}
|
||||
|
||||
public static Font2D getFont2DWithSubstitution(Font font) {
|
||||
return FontAccess.getFontAccess().getFont2DWithSubstitution(font);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if there any characters which would trigger layout.
|
||||
* This method considers supplementary characters to be simple,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package sun.font;
|
||||
|
||||
interface FontWithDerivedItalic {
|
||||
Font2D createItalic();
|
||||
Font2D createItalicVariant();
|
||||
}
|
||||
@@ -410,10 +410,7 @@ public final class GlyphLayout {
|
||||
|
||||
int lang = -1; // default for now
|
||||
|
||||
Font2D font2D = FontUtilities.getFont2D(font);
|
||||
if (font2D instanceof FontSubstitution) {
|
||||
font2D = ((FontSubstitution)font2D).getCompositeFont2D();
|
||||
}
|
||||
Font2D font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
|
||||
_textRecord.init(text, offset, lim, min, max);
|
||||
int start = offset;
|
||||
|
||||
@@ -197,8 +197,7 @@ public class StandardGlyphVector extends GlyphVector {
|
||||
|
||||
// how do we know its a base glyph
|
||||
// for now, it is if the natural advance of the glyph is non-zero
|
||||
Font2D f2d = FontUtilities.getFont2D(font);
|
||||
FontStrike strike = f2d.getStrike(font, frc);
|
||||
FontStrike strike = font2D.getStrike(font, frc);
|
||||
|
||||
float[] deltas = { trackPt.x, trackPt.y };
|
||||
for (int j = 0; j < deltas.length; ++j) {
|
||||
@@ -1106,10 +1105,7 @@ public class StandardGlyphVector extends GlyphVector {
|
||||
}
|
||||
|
||||
private void initFontData() {
|
||||
font2D = FontUtilities.getFont2D(font);
|
||||
if (font2D instanceof FontSubstitution) {
|
||||
font2D = ((FontSubstitution)font2D).getCompositeFont2D();
|
||||
}
|
||||
font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
float s = font.getSize2D();
|
||||
if (font.isTransformed()) {
|
||||
ftx = font.getTransform();
|
||||
@@ -1728,12 +1724,7 @@ public class StandardGlyphVector extends GlyphVector {
|
||||
aa, fm);
|
||||
// Get the strike via the handle. Shouldn't matter
|
||||
// if we've invalidated the font but its an extra precaution.
|
||||
// do we want the CompFont from CFont here ?
|
||||
Font2D f2d = sgv.font2D;
|
||||
if (f2d instanceof FontSubstitution) {
|
||||
f2d = ((FontSubstitution)f2d).getCompositeFont2D();
|
||||
}
|
||||
FontStrike strike = f2d.handle.font2D.getStrike(desc); // !!! getStrike(desc, false)
|
||||
FontStrike strike = sgv.font2D.handle.font2D.getStrike(desc); // !!! getStrike(desc, false)
|
||||
|
||||
return new GlyphStrike(sgv, strike, dx, dy);
|
||||
}
|
||||
|
||||
@@ -670,7 +670,7 @@ public final class SunGraphics2D
|
||||
info.nonInvertibleTx =
|
||||
(Math.abs(textAt.getDeterminant()) <= Double.MIN_VALUE);
|
||||
|
||||
info.font2D = FontUtilities.getFont2D(font);
|
||||
info.font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
|
||||
int fmhint = fractionalMetricsHint;
|
||||
if (fmhint == SunHints.INTVAL_FRACTIONALMETRICS_DEFAULT) {
|
||||
|
||||
@@ -698,7 +698,7 @@ public abstract class PathGraphics extends ProxyGraphics2D {
|
||||
}
|
||||
|
||||
Font font = g.getFont();
|
||||
Font2D font2D = FontUtilities.getFont2D(font);
|
||||
Font2D font2D = FontUtilities.getFont2DWithSubstitution(font);
|
||||
if (font2D.handle.font2D != font2D) {
|
||||
/* suspicious, may be a bad font. lets bail */
|
||||
return false;
|
||||
|
||||
Reference in New Issue
Block a user