/*
* Copyright (c) 2011, 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.
*/
#import <AppKit/AppKit.h>
#import "CoreTextSupport.h"
/*
* 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.
*/
const UniChar *
CTS_Provider(CFIndex stringIndex, CFIndex *charCount,
CFDictionaryRef *attributes, void *refCon)
{
// if we have a zero length string we can just return NULL for the string
// or if the index anything other than 0 we are not using core text
// correctly since we only have one run.
if (stringIndex != 0) {
return NULL;
}
CTS_ProviderStruct *ctps = (CTS_ProviderStruct *)refCon;
*charCount = ctps->length;
*attributes = ctps->attributes;
return ctps->unicodes;
}
#pragma mark --- Retain/Release CoreText State Dictionary ---
/*
* Gets a Dictionary filled with common details we want to use for CoreText
* when we are interacting with it from Java.
*/
static inline CFMutableDictionaryRef
GetCTStateDictionaryFor(const NSFont *font, BOOL useFractionalMetrics)
{
NSNumber *gZeroNumber = [NSNumber numberWithInt:0];
NSNumber *gOneNumber = [NSNumber numberWithInt:1];
CFMutableDictionaryRef dictRef = (CFMutableDictionaryRef)
[[NSMutableDictionary alloc] initWithObjectsAndKeys:
font, NSFontAttributeName,
// TODO(cpc): following attribute is private...
//gOneNumber, (id)kCTForegroundColorFromContextAttributeName,
// force integer hack in CoreText to help with Java integer assumptions
useFractionalMetrics ? gZeroNumber : gOneNumber, @"CTIntegerMetrics",
gZeroNumber, NSLigatureAttributeName,
gZeroNumber, NSKernAttributeName,
NULL];
CFRetain(dictRef); // GC
[(id)dictRef release];
return dictRef;
}
/*
* Releases the CoreText Dictionary - in the future we should hold on
* to these to improve performance.
*/
static inline void
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)
{
CTFontGetGlyphsForCharacters((CTFontRef)font->fFont, unicodes, glyphs, count);
size_t i;
for (i = 0; i < count; i++) {
CGGlyph glyph = glyphs[i];
if (glyph > 0) {
glyphsAsInts[i] = glyph;
continue;
}
UniChar unicode = unicodes[i];
const CTFontRef fallback = JRSFontCreateFallbackFontForCharacters((CTFontRef)font->fFont, &unicode, 1);
if (fallback) {
CTFontGetGlyphsForCharacters(fallback, &unicode, &glyph, 1);
CFRelease(fallback);
}
if (glyph > 0) {
glyphsAsInts[i] = -unicode; // set the glyph code to the negative unicode value
} else {
glyphsAsInts[i] = 0; // CoreText couldn't find a glyph for this character either
}
}
}
/*
* 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 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 "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;
}
UTF16Char character = -glyphCode;
return CTS_CopyCTFallbackFontAndGlyphForUnicode(font, &character, glyphRef, 1);
}
// 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;
}