1/* 2 * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26#import <AppKit/AppKit.h> 27#import "CoreTextSupport.h" 28 29 30/* 31 * Callback for CoreText which uses the CoreTextProviderStruct to 32 * feed CT UniChars. We only use it for one-off lines, and don't 33 * attempt to fragment our strings. 34 */ 35const UniChar * 36CTS_Provider(CFIndex stringIndex, CFIndex *charCount, 37 CFDictionaryRef *attributes, void *refCon) 38{ 39 // if we have a zero length string we can just return NULL for the string 40 // or if the index anything other than 0 we are not using core text 41 // correctly since we only have one run. 42 if (stringIndex != 0) { 43 return NULL; 44 } 45 46 CTS_ProviderStruct *ctps = (CTS_ProviderStruct *)refCon; 47 *charCount = ctps->length; 48 *attributes = ctps->attributes; 49 return ctps->unicodes; 50} 51 52 53#pragma mark --- Retain/Release CoreText State Dictionary --- 54 55/* 56 * Gets a Dictionary filled with common details we want to use for CoreText 57 * when we are interacting with it from Java. 58 */ 59static inline CFMutableDictionaryRef 60GetCTStateDictionaryFor(const NSFont *font, BOOL useFractionalMetrics) 61{ 62 NSNumber *gZeroNumber = [NSNumber numberWithInt:0]; 63 NSNumber *gOneNumber = [NSNumber numberWithInt:1]; 64 65 CFMutableDictionaryRef dictRef = (CFMutableDictionaryRef) 66 [[NSMutableDictionary alloc] initWithObjectsAndKeys: 67 font, NSFontAttributeName, 68 // TODO(cpc): following attribute is private... 69 //gOneNumber, (id)kCTForegroundColorFromContextAttributeName, 70 // force integer hack in CoreText to help with Java integer assumptions 71 useFractionalMetrics ? gZeroNumber : gOneNumber, @"CTIntegerMetrics", 72 gZeroNumber, NSLigatureAttributeName, 73 gZeroNumber, NSKernAttributeName, 74 NULL]; 75 CFRetain(dictRef); // GC 76 [(id)dictRef release]; 77 78 return dictRef; 79} 80 81/* 82 * Releases the CoreText Dictionary - in the future we should hold on 83 * to these to improve performance. 84 */ 85static inline void 86ReleaseCTStateDictionary(CFDictionaryRef ctStateDict) 87{ 88 CFRelease(ctStateDict); // GC 89} 90 91/* 92 * Transform Unicode characters into glyphs. 93 * 94 * Fills the "glyphsAsInts" array with the glyph codes for the current font, 95 * or the negative unicode value if we know the character can be hot-substituted. 96 * 97 * This is the heart of "Universal Font Substitution" in Java. 98 */ 99void CTS_GetGlyphsAsIntsForCharacters 100(const AWTFont *font, const UniChar unicodes[], CGGlyph glyphs[], jint glyphsAsInts[], const size_t count) 101{ 102 CTFontGetGlyphsForCharacters((CTFontRef)font->fFont, unicodes, glyphs, count); 103 104 size_t i; 105 for (i = 0; i < count; i++) { 106 UniChar unicode = unicodes[i]; 107 UniChar nextUnicode = (i+1) < count ? unicodes[i+1] : 0; 108 bool surrogatePair = unicode >= HI_SURROGATE_START && unicode <= HI_SURROGATE_END 109 && nextUnicode >= LO_SURROGATE_START && nextUnicode <= LO_SURROGATE_END; 110 111 CGGlyph glyph = glyphs[i]; 112 if (glyph > 0) { 113 glyphsAsInts[i] = glyph; 114 if (surrogatePair) i++; 115 continue; 116 } 117 118 const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, &unicodes[i], 119 surrogatePair ? 2 : 1); 120 if (fallback) { 121 CTFontGetGlyphsForCharacters(fallback, &unicodes[i], &glyphs[i], surrogatePair ? 2 : 1); 122 glyph = glyphs[i]; 123 CFRelease(fallback); 124 } 125 126 if (glyph > 0) { 127 int codePoint = surrogatePair ? (((int)(unicode - HI_SURROGATE_START)) << 10) 128 + nextUnicode - LO_SURROGATE_START + 0x10000 : unicode; 129 glyphsAsInts[i] = -codePoint; // set the glyph code to the negative unicode value 130 } else { 131 glyphsAsInts[i] = 0; // CoreText couldn't find a glyph for this character either 132 } 133 if (surrogatePair) i++; 134 } 135} 136 137/* 138 * Translates a Unicode into a CGGlyph/CTFontRef pair 139 * Returns the substituted font, and places the appropriate glyph into "glyphRef" 140 */ 141CTFontRef CTS_CopyCTFallbackFontAndGlyphForUnicode 142(const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count) { 143 CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, charRef, count); 144 if (fallback == NULL) 145 { 146 // use the original font if we somehow got duped into trying to fallback something we can't 147 fallback = (CTFontRef)font->fFont; 148 CFRetain(fallback); 149 } 150 151 CTFontGetGlyphsForCharacters(fallback, charRef, glyphRef, count); 152 return fallback; 153} 154 155/* 156 * Translates a Java glyph code int (might be a negative unicode value) into a CGGlyph/CTFontRef pair 157 * Returns the substituted font, and places the appropriate glyph into "glyphRef" 158 */ 159CTFontRef CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode 160(const AWTFont *font, const jint glyphCode, CGGlyph *glyphRef) 161{ 162 // negative glyph codes are really unicodes, which were placed there by the mapper 163 // to indicate we should use CoreText to substitute the character 164 if (glyphCode >= 0) 165 { 166 *glyphRef = glyphCode; 167 CFRetain(font->fFont); 168 return (CTFontRef)font->fFont; 169 } 170 171 int codePoint = -glyphCode; 172 if (codePoint >= 0x10000) { 173 UTF16Char chars[2]; 174 CGGlyph glyphs[2]; 175 CTS_BreakupUnicodeIntoSurrogatePairs(codePoint, chars); 176 CTFontRef result = CTS_CopyCTFallbackFontAndGlyphForUnicode(font, chars, glyphs, 2); 177 *glyphRef = glyphs[0]; 178 return result; 179 } else { 180 UTF16Char character = codePoint; 181 return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1); 182 } 183} 184 185// Breakup a 32 bit unicode value into the component surrogate pairs 186void CTS_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]) { 187 int value = uniChar - 0x10000; 188 UTF16Char low_surrogate = (value & 0x3FF) | LO_SURROGATE_START; 189 UTF16Char high_surrogate = (((int)(value & 0xFFC00)) >> 10) | HI_SURROGATE_START; 190 charRef[0] = high_surrogate; 191 charRef[1] = low_surrogate; 192} 193