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