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  */
  35 const UniChar *
  36 CTS_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  */
  59 static inline CFMutableDictionaryRef
  60 GetCTStateDictionaryFor(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  */
  85 static inline void
  86 ReleaseCTStateDictionary(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  */
  99 void 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         CGGlyph glyph = glyphs[i];
 107         if (glyph > 0) {
 108             glyphsAsInts[i] = glyph;
 109             continue;
 110         }
 111 
 112         UniChar unicode = unicodes[i];
 113         const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, &unicode, 1);
 114         if (fallback) {
 115             CTFontGetGlyphsForCharacters(fallback, &unicode, &glyph, 1);
 116             CFRelease(fallback);
 117         }
 118 
 119         if (glyph > 0) {
 120             glyphsAsInts[i] = -unicode; // set the glyph code to the negative unicode value
 121         } else {
 122             glyphsAsInts[i] = 0; // CoreText couldn't find a glyph for this character either
 123         }
 124     }
 125 }
 126 
 127 /*
 128  * Translates a Unicode into a CGGlyph/CTFontRef pair
 129  * Returns the substituted font, and places the appropriate glyph into "glyphRef"
 130  */
 131 CTFontRef CTS_CopyCTFallbackFontAndGlyphForUnicode
 132 (const AWTFont *font, const UTF16Char *charRef, CGGlyph *glyphRef, int count) {
 133     CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, charRef, count);
 134     if (fallback == NULL)
 135     {
 136         // use the original font if we somehow got duped into trying to fallback something we can't
 137         fallback = (CTFontRef)font->fFont;
 138         CFRetain(fallback);
 139     }
 140 
 141     CTFontGetGlyphsForCharacters(fallback, charRef, glyphRef, count);
 142     return fallback;
 143 }
 144 
 145 /*
 146  * Translates a Java glyph code int (might be a negative unicode value) into a CGGlyph/CTFontRef pair
 147  * Returns the substituted font, and places the appropriate glyph into "glyphRef"
 148  */
 149 CTFontRef CTS_CopyCTFallbackFontAndGlyphForJavaGlyphCode
 150 (const AWTFont *font, const jint glyphCode, CGGlyph *glyphRef)
 151 {
 152     // negative glyph codes are really unicodes, which were placed there by the mapper
 153     // to indicate we should use CoreText to substitute the character
 154     if (glyphCode >= 0)
 155     {
 156         *glyphRef = glyphCode;
 157         CFRetain(font->fFont);
 158         return (CTFontRef)font->fFont;
 159     }
 160 
 161     UTF16Char character = -glyphCode;
 162     return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
 163 }
 164 
 165 // Breakup a 32 bit unicode value into the component surrogate pairs
 166 void CTS_BreakupUnicodeIntoSurrogatePairs(int uniChar, UTF16Char charRef[]) {
 167     int value = uniChar - 0x10000;
 168     UTF16Char low_surrogate = (value & 0x3FF) | LO_SURROGATE_START;
 169     UTF16Char high_surrogate = (((int)(value & 0xFFC00)) >> 10) | HI_SURROGATE_START;
 170     charRef[0] = high_surrogate;
 171     charRef[1] = low_surrogate;
 172 }