mirror of
https://github.com/JetBrains/JetBrainsRuntime.git
synced 2025-12-06 09:29:38 +01:00
reimplement JDK-7162125 to fix JDK-8147002
port commit ba38e5c4 from JBR 9 port from JBR 11 to JBR 15(cherry picked from commita949f9d220) cherry-picked from commitf309844f75
This commit is contained in:
committed by
alexey.ushakov@jetbrains.com
parent
105d5ce04c
commit
89814023a1
81
src/java.desktop/macosx/classes/sun/font/CCompositeFont.java
Normal file
81
src/java.desktop/macosx/classes/sun/font/CCompositeFont.java
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* 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++;
|
||||
}
|
||||
}
|
||||
@@ -25,131 +25,50 @@
|
||||
|
||||
package sun.font;
|
||||
|
||||
import java.awt.*;
|
||||
|
||||
public final class CCompositeGlyphMapper extends CompositeGlyphMapper {
|
||||
|
||||
private CompositeFont font;
|
||||
private CharToGlyphMapper[] slotMappers;
|
||||
|
||||
public CCompositeGlyphMapper(CompositeFont compFont) {
|
||||
public CCompositeGlyphMapper(CCompositeFont compFont) {
|
||||
super(compFont);
|
||||
font = compFont;
|
||||
slotMappers = new CharToGlyphMapper[font.numSlots];
|
||||
missingGlyph = 0;
|
||||
}
|
||||
|
||||
private CharToGlyphMapper getSlotMapper(int slot) {
|
||||
CharToGlyphMapper mapper = slotMappers[slot];
|
||||
if (mapper == null) {
|
||||
mapper = font.getSlotFont(slot).getMapper();
|
||||
slotMappers[slot] = mapper;
|
||||
@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) {
|
||||
return missingGlyph;
|
||||
}
|
||||
return mapper;
|
||||
}
|
||||
|
||||
public boolean canDisplay(char ch) {
|
||||
int glyph = charToGlyph(ch);
|
||||
return glyph != missingGlyph;
|
||||
}
|
||||
|
||||
private int convertToGlyph(int unicode) {
|
||||
for (int slot = 0; slot < font.numSlots; slot++) {
|
||||
CharToGlyphMapper mapper = getSlotMapper(slot);
|
||||
int glyphCode = mapper.charToGlyph(unicode);
|
||||
// The CFont Mappers will return a negative code
|
||||
// for fonts that will fill the glyph from fallbacks
|
||||
// - cascading font in OSX-speak. But we need to be
|
||||
// know here that only the codes > 0 are really present.
|
||||
if (glyphCode > 0) {
|
||||
glyphCode = compositeGlyphCode(slot, glyphCode);
|
||||
return glyphCode;
|
||||
}
|
||||
}
|
||||
return missingGlyph;
|
||||
}
|
||||
|
||||
public int getNumGlyphs() {
|
||||
int numGlyphs = 0;
|
||||
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 charToGlyph(int unicode) {
|
||||
return convertToGlyph(unicode);
|
||||
}
|
||||
|
||||
public int charToGlyph(char unicode) {
|
||||
return convertToGlyph(unicode);
|
||||
}
|
||||
|
||||
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] = convertToGlyph(code);
|
||||
|
||||
if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
|
||||
continue;
|
||||
}
|
||||
else if (FontUtilities.isComplexCharCode(code)) {
|
||||
return true;
|
||||
}
|
||||
else if (code >= 0x10000) {
|
||||
i += 1; // Empty glyph slot after surrogate
|
||||
continue;
|
||||
}
|
||||
String fallbackFontName = fallbackFontInfo[0];
|
||||
String fallbackFontFamilyName = fallbackFontInfo[1];
|
||||
if (fallbackFontName == null || fallbackFontFamilyName == null) {
|
||||
return compositeGlyphCode(0, glyphCode);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
int slot = compositeFont.findSlot(fallbackFontName);
|
||||
|
||||
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] = convertToGlyph(code);
|
||||
i += 1; // Empty glyph slot after surrogate
|
||||
glyphs[i] = INVISIBLE_GLYPH_ID;
|
||||
continue;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
glyphs[i] = convertToGlyph(code);
|
||||
if (mainFont.isFakeItalic()) fallbackFont = ((CFont)fallbackFont).createItalicVariant(false);
|
||||
|
||||
slot = compositeFont.addSlot((CFont) fallbackFont);
|
||||
}
|
||||
|
||||
return compositeGlyphCode(slot, glyphCode);
|
||||
}
|
||||
|
||||
public void charsToGlyphs(int count, int[] unicodes, int[] glyphs) {
|
||||
for (int i=0; i<count; i++) {
|
||||
glyphs[i] = convertToGlyph(unicodes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// 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,7 +31,6 @@ import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.GeneralPath;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.util.ArrayList;
|
||||
|
||||
// Right now this class is final to avoid a problem with native code.
|
||||
// For some reason the JNI IsInstanceOf was not working correctly
|
||||
@@ -174,12 +173,14 @@ public final class CFont extends PhysicalFont implements FontSubstitution {
|
||||
isFakeItalic = other.isFakeItalic;
|
||||
}
|
||||
|
||||
public CFont createItalicVariant() {
|
||||
public CFont createItalicVariant(boolean updateStyle) {
|
||||
CFont font = new CFont(this, familyName);
|
||||
font.nativeFontName = fullName;
|
||||
font.fullName =
|
||||
fullName + (style == Font.BOLD ? "" : "-") + "Italic-Derived";
|
||||
font.style |= Font.ITALIC;
|
||||
if (updateStyle) {
|
||||
font.style |= Font.ITALIC;
|
||||
}
|
||||
font.isFakeItalic = true;
|
||||
return font;
|
||||
}
|
||||
@@ -198,51 +199,11 @@ public final class CFont extends PhysicalFont implements FontSubstitution {
|
||||
return getCGFontPtrNative(getNativeFontPtr());
|
||||
}
|
||||
|
||||
static native void getCascadeList(long nativeFontPtr, ArrayList<String> listOfString);
|
||||
|
||||
private CompositeFont createCompositeFont() {
|
||||
ArrayList<String> listOfString = new ArrayList<String>();
|
||||
getCascadeList(nativeFontPtr, listOfString);
|
||||
|
||||
// In some italic cases the standard Mac cascade list is missing Arabic.
|
||||
listOfString.add("GeezaPro");
|
||||
CFontManager fm = (CFontManager) FontManagerFactory.getInstance();
|
||||
int numFonts = 1 + listOfString.size();
|
||||
PhysicalFont[] fonts = new PhysicalFont[numFonts];
|
||||
fonts[0] = this;
|
||||
int idx = 1;
|
||||
if (FontUtilities.isLogging()) {
|
||||
FontUtilities.logInfo("Cascading list for " + this + " :");
|
||||
}
|
||||
for (String s : listOfString) {
|
||||
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);
|
||||
}
|
||||
CompositeFont compFont = new CompositeFont(fonts);
|
||||
compFont.mapper = new CCompositeGlyphMapper(compFont);
|
||||
return compFont;
|
||||
}
|
||||
|
||||
private CompositeFont compFont;
|
||||
|
||||
public CompositeFont getCompositeFont2D() {
|
||||
if (compFont == null) {
|
||||
compFont = createCompositeFont();
|
||||
compFont = new CCompositeFont(this);
|
||||
}
|
||||
return compFont;
|
||||
}
|
||||
@@ -270,6 +231,14 @@ public final class CFont extends PhysicalFont implements FontSubstitution {
|
||||
return new CStrike(this, desc);
|
||||
}
|
||||
|
||||
boolean isFakeItalic() {
|
||||
return isFakeItalic;
|
||||
}
|
||||
|
||||
String getNativeFontName() {
|
||||
return nativeFontName;
|
||||
}
|
||||
|
||||
// <rdar://problem/5321707> sun.font.Font2D caches the last used strike,
|
||||
// but does not check if the properties of the strike match the properties
|
||||
// of the incoming java.awt.Font object (size, style, etc).
|
||||
|
||||
@@ -34,9 +34,7 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.swing.plaf.FontUIResource;
|
||||
|
||||
@@ -46,7 +44,6 @@ import sun.lwawt.macosx.*;
|
||||
|
||||
public final class CFontManager extends SunFontManager {
|
||||
private static Hashtable<String, Font2D> genericFonts = new Hashtable<String, Font2D>();
|
||||
private final Map<String, Font2D> fallbackFonts = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
protected FontConfiguration createFontConfiguration() {
|
||||
@@ -210,10 +207,10 @@ public final class CFontManager extends SunFontManager {
|
||||
if (plain == null && bold == null) continue;
|
||||
if (italic != null && boldItalic != null) continue;
|
||||
if (plain != null && italic == null) {
|
||||
registerGenericFont(plain.createItalicVariant(), true);
|
||||
registerGenericFont(plain.createItalicVariant(true), true);
|
||||
}
|
||||
if (bold != null && boldItalic == null) {
|
||||
registerGenericFont(bold.createItalicVariant(), true);
|
||||
registerGenericFont(bold.createItalicVariant(true), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -340,17 +337,4 @@ 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) {}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1232,7 +1232,7 @@ static NSDictionary* prebuiltFamilyNames() {
|
||||
@"Wingdings3" : @"Wingdings 3",
|
||||
@"ZapfDingbatsITC" : @"Zapf Dingbats",
|
||||
@"Zapfino" : @"Zapfino",
|
||||
|
||||
|
||||
// JetBrains fonts
|
||||
@"DroidSans" : @"Droid Sans",
|
||||
@"DroidSans-Bold" : @"Droid Sans",
|
||||
@@ -1580,55 +1580,6 @@ Java_sun_awt_FontDescriptor_initIDs
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Class: sun_awt_FontDescriptor
|
||||
* Method: initIDs
|
||||
* Signature: ()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;
|
||||
CTFontRef font = (CTFontRef)nsFont;
|
||||
CFArrayRef codes = CFLocaleCopyISOLanguageCodes();
|
||||
|
||||
#ifdef DEBUG
|
||||
CFStringRef base = CTFontCopyFullName(font);
|
||||
NSLog(@"BaseFont is : %@", (NSString*)base);
|
||||
CFRelease(base);
|
||||
#endif
|
||||
CFArrayRef fds = CTFontCopyDefaultCascadeListForLanguages(font, codes);
|
||||
CFRelease(codes);
|
||||
CFIndex cnt = CFArrayGetCount(fds);
|
||||
for (i=0; i<cnt; i++) {
|
||||
CTFontDescriptorRef ref = CFArrayGetValueAtIndex(fds, i);
|
||||
CFStringRef 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)
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#import "CoreTextSupport.h"
|
||||
|
||||
#import "sun_font_CCharToGlyphMapper.h"
|
||||
#import "sun_font_CCompositeGlyphMapper.h"
|
||||
|
||||
/*
|
||||
* Class: sun_font_CCharToGlyphMapper
|
||||
@@ -113,3 +114,28 @@ 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);
|
||||
}
|
||||
|
||||
@@ -54,6 +54,11 @@ CTFontRef CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode(const AWTFont *font, co
|
||||
// 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[]);
|
||||
|
||||
|
||||
@@ -88,18 +88,10 @@ ReleaseCTStateDictionary(CFDictionaryRef ctStateDict)
|
||||
CFRelease(ctStateDict); // GC
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void CTS_GetGlyphsAsIntsForCharacters
|
||||
(const AWTFont *font, const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[], const size_t count)
|
||||
void GetFontsAndGlyphsForCharacters(CTFontRef font, const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[],
|
||||
CTFontRef actualFonts[], const size_t count)
|
||||
{
|
||||
CTFontGetGlyphsForCharacters((CTFontRef)font->fFont, unicodes, glyphs, count);
|
||||
CTFontGetGlyphsForCharacters(font, unicodes, glyphs, count);
|
||||
|
||||
size_t i;
|
||||
for (i = 0; i < count; i++) {
|
||||
@@ -115,12 +107,15 @@ void CTS_GetGlyphsAsIntsForCharacters
|
||||
continue;
|
||||
}
|
||||
|
||||
const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, &unicodes[i],
|
||||
surrogatePair ? 2 : 1);
|
||||
const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters(font, &unicodes[i], surrogatePair ? 2 : 1);
|
||||
if (fallback) {
|
||||
CTFontGetGlyphsForCharacters(fallback, &unicodes[i], &glyphs[i], surrogatePair ? 2 : 1);
|
||||
glyph = glyphs[i];
|
||||
CFRelease(fallback);
|
||||
if (actualFonts && glyph > 0) {
|
||||
actualFonts[i] = fallback;
|
||||
} else {
|
||||
CFRelease(fallback);
|
||||
}
|
||||
}
|
||||
|
||||
if (glyph > 0) {
|
||||
@@ -134,6 +129,53 @@ void CTS_GetGlyphsAsIntsForCharacters
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
void CTS_GetGlyphsAsIntsForCharacters
|
||||
(const AWTFont *font, const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[], const size_t count)
|
||||
{
|
||||
GetFontsAndGlyphsForCharacters((CTFontRef)font->fFont, unicodes, glyphs, glyphsAsInts, NULL, 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;
|
||||
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, 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"
|
||||
|
||||
@@ -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 final class CompositeFont extends Font2D {
|
||||
public class CompositeFont extends Font2D {
|
||||
|
||||
private boolean[] deferredInitialisation;
|
||||
String[] componentFileNames;
|
||||
|
||||
@@ -117,7 +117,7 @@ public class CompositeGlyphMapper extends CharToGlyphMapper {
|
||||
return mapper;
|
||||
}
|
||||
|
||||
private int convertToGlyph(int unicode) {
|
||||
protected 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);
|
||||
}
|
||||
|
||||
private FontStrike getStrike(FontStrikeDesc desc, boolean copy) {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user