1 /* 2 * This file is part of the internal font implementation. 3 * 4 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. 5 * Copyright (c) 2010 Google Inc. All rights reserved. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 * 22 */ 23 24 #import "config.h" 25 #import "platform/fonts/FontPlatformData.h" 26 27 #import <AppKit/NSFont.h> 28 #import <AvailabilityMacros.h> 29 #import <wtf/text/WTFString.h> 30 31 #import "platform/fonts/harfbuzz/HarfBuzzFace.h" 32 #include "third_party/skia/include/ports/SkTypeface_mac.h" 33 34 namespace blink { 35 36 unsigned FontPlatformData::hash() const 37 { 38 ASSERT(m_font || !m_cgFont); 39 uintptr_t hashCodes[3] = { (uintptr_t)m_font, m_widthVariant, static_cast<uintptr_t>(m_isHashTableDeletedValue << 3 | m_orientation << 2 | m_syntheticBold << 1 | m_syntheticItalic) }; 40 return StringHasher::hashMemory<sizeof(hashCodes)>(hashCodes); 41 } 42 43 // These CoreText Text Spacing feature selectors are not defined in CoreText. 44 enum TextSpacingCTFeatureSelector { TextSpacingProportional, TextSpacingFullWidth, TextSpacingHalfWidth, TextSpacingThirdWidth, TextSpacingQuarterWidth }; 45 46 FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool syntheticBold, bool syntheticItalic, FontOrientation orientation, FontWidthVariant widthVariant) 47 : m_textSize(size) 48 , m_syntheticBold(syntheticBold) 49 , m_syntheticItalic(syntheticItalic) 50 , m_orientation(orientation) 51 , m_isColorBitmapFont(false) 52 , m_isCompositeFontReference(false) 53 , m_widthVariant(widthVariant) 54 , m_font(nsFont) 55 , m_isHashTableDeletedValue(false) 56 { 57 ASSERT_ARG(nsFont, nsFont); 58 59 CGFontRef cgFont = 0; 60 loadFont(nsFont, size, m_font, cgFont); 61 62 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 63 // FIXME: Chromium: The following code isn't correct for the Chromium port since the sandbox might 64 // have blocked font loading, in which case we'll only have the real loaded font file after the call to loadFont(). 65 { 66 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(m_font)); 67 m_isColorBitmapFont = traits & kCTFontColorGlyphsTrait; 68 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 69 m_isCompositeFontReference = traits & kCTFontCompositeTrait; 70 #endif 71 } 72 #endif 73 74 if (m_font) 75 CFRetain(m_font); 76 77 m_cgFont.adoptCF(cgFont); 78 } 79 80 void FontPlatformData::platformDataInit(const FontPlatformData& f) 81 { 82 m_font = f.m_font ? [f.m_font retain] : f.m_font; 83 84 m_cgFont = f.m_cgFont; 85 m_CTFont = f.m_CTFont; 86 87 m_inMemoryFont = f.m_inMemoryFont; 88 m_harfBuzzFace = f.m_harfBuzzFace; 89 m_typeface = f.m_typeface; 90 } 91 92 const FontPlatformData& FontPlatformData::platformDataAssign(const FontPlatformData& f) 93 { 94 m_cgFont = f.m_cgFont; 95 if (m_font == f.m_font) 96 return *this; 97 if (f.m_font) 98 CFRetain(f.m_font); 99 if (m_font) 100 CFRelease(m_font); 101 m_font = f.m_font; 102 m_CTFont = f.m_CTFont; 103 104 m_inMemoryFont = f.m_inMemoryFont; 105 m_harfBuzzFace = f.m_harfBuzzFace; 106 m_typeface = f.m_typeface; 107 108 return *this; 109 } 110 111 112 void FontPlatformData::setFont(NSFont *font) 113 { 114 ASSERT_ARG(font, font); 115 116 if (m_font == font) 117 return; 118 119 CFRetain(font); 120 if (m_font) 121 CFRelease(m_font); 122 m_font = font; 123 m_textSize = [font pointSize]; 124 125 CGFontRef cgFont = 0; 126 NSFont* loadedFont = 0; 127 loadFont(m_font, m_textSize, loadedFont, cgFont); 128 129 // If loadFont replaced m_font with a fallback font, then release the 130 // previous font to counter the retain above. Then retain the new font. 131 if (loadedFont != m_font) { 132 CFRelease(m_font); 133 CFRetain(loadedFont); 134 m_font = loadedFont; 135 } 136 137 m_cgFont.adoptCF(cgFont); 138 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 139 { 140 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(m_font)); 141 m_isColorBitmapFont = traits & kCTFontColorGlyphsTrait; 142 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 143 m_isCompositeFontReference = traits & kCTFontCompositeTrait; 144 #endif 145 } 146 #endif 147 m_CTFont = 0; 148 } 149 150 bool FontPlatformData::roundsGlyphAdvances() const 151 { 152 return [m_font renderingMode] == NSFontAntialiasedIntegerAdvancementsRenderingMode; 153 } 154 155 bool FontPlatformData::allowsLigatures() const 156 { 157 return ![[m_font coveredCharacterSet] characterIsMember:'a']; 158 } 159 160 inline int mapFontWidthVariantToCTFeatureSelector(FontWidthVariant variant) 161 { 162 switch(variant) { 163 case RegularWidth: 164 return TextSpacingProportional; 165 166 case HalfWidth: 167 return TextSpacingHalfWidth; 168 169 case ThirdWidth: 170 return TextSpacingThirdWidth; 171 172 case QuarterWidth: 173 return TextSpacingQuarterWidth; 174 } 175 176 ASSERT_NOT_REACHED(); 177 return TextSpacingProportional; 178 } 179 180 static CFDictionaryRef createFeatureSettingDictionary(int featureTypeIdentifier, int featureSelectorIdentifier) 181 { 182 RetainPtr<CFNumberRef> featureTypeIdentifierNumber(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeIdentifier)); 183 RetainPtr<CFNumberRef> featureSelectorIdentifierNumber(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorIdentifier)); 184 185 const void* settingKeys[] = { kCTFontFeatureTypeIdentifierKey, kCTFontFeatureSelectorIdentifierKey }; 186 const void* settingValues[] = { featureTypeIdentifierNumber.get(), featureSelectorIdentifierNumber.get() }; 187 188 return CFDictionaryCreate(kCFAllocatorDefault, settingKeys, settingValues, WTF_ARRAY_LENGTH(settingKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 189 } 190 191 static CTFontDescriptorRef cascadeToLastResortFontDescriptor() 192 { 193 static CTFontDescriptorRef descriptor; 194 if (descriptor) 195 return descriptor; 196 197 const void* keys[] = { kCTFontCascadeListAttribute }; 198 const void* descriptors[] = { CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0) }; 199 const void* values[] = { CFArrayCreate(kCFAllocatorDefault, descriptors, WTF_ARRAY_LENGTH(descriptors), &kCFTypeArrayCallBacks) }; 200 RetainPtr<CFDictionaryRef> attributes(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); 201 202 descriptor = CTFontDescriptorCreateWithAttributes(attributes.get()); 203 204 return descriptor; 205 } 206 207 static CTFontDescriptorRef cascadeToLastResortAndDisableSwashesFontDescriptor() 208 { 209 static CTFontDescriptorRef descriptor; 210 if (descriptor) 211 return descriptor; 212 213 RetainPtr<CFDictionaryRef> lineInitialSwashesOffSetting(AdoptCF, createFeatureSettingDictionary(kSmartSwashType, kLineInitialSwashesOffSelector)); 214 RetainPtr<CFDictionaryRef> lineFinalSwashesOffSetting(AdoptCF, createFeatureSettingDictionary(kSmartSwashType, kLineFinalSwashesOffSelector)); 215 216 const void* settingDictionaries[] = { lineInitialSwashesOffSetting.get(), lineFinalSwashesOffSetting.get() }; 217 RetainPtr<CFArrayRef> featureSettings(AdoptCF, CFArrayCreate(kCFAllocatorDefault, settingDictionaries, WTF_ARRAY_LENGTH(settingDictionaries), &kCFTypeArrayCallBacks)); 218 219 const void* keys[] = { kCTFontFeatureSettingsAttribute }; 220 const void* values[] = { featureSettings.get() }; 221 RetainPtr<CFDictionaryRef> attributes(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); 222 223 descriptor = CTFontDescriptorCreateCopyWithAttributes(cascadeToLastResortFontDescriptor(), attributes.get()); 224 225 return descriptor; 226 } 227 228 CTFontRef FontPlatformData::ctFont() const 229 { 230 if (m_CTFont) 231 return m_CTFont.get(); 232 233 if (m_inMemoryFont) { 234 m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_inMemoryFont->cgFont(), m_textSize, 0, cascadeToLastResortFontDescriptor())); 235 return m_CTFont.get(); 236 } 237 238 m_CTFont = toCTFontRef(m_font); 239 if (m_CTFont) { 240 CTFontDescriptorRef fontDescriptor; 241 RetainPtr<CFStringRef> postScriptName(AdoptCF, CTFontCopyPostScriptName(m_CTFont.get())); 242 // Hoefler Text Italic has line-initial and -final swashes enabled by default, so disable them. 243 if (CFEqual(postScriptName.get(), CFSTR("HoeflerText-Italic")) || CFEqual(postScriptName.get(), CFSTR("HoeflerText-BlackItalic"))) 244 fontDescriptor = cascadeToLastResortAndDisableSwashesFontDescriptor(); 245 else 246 fontDescriptor = cascadeToLastResortFontDescriptor(); 247 m_CTFont.adoptCF(CTFontCreateCopyWithAttributes(m_CTFont.get(), m_textSize, 0, fontDescriptor)); 248 } else 249 m_CTFont.adoptCF(CTFontCreateWithGraphicsFont(m_cgFont.get(), m_textSize, 0, cascadeToLastResortFontDescriptor())); 250 251 if (m_widthVariant != RegularWidth) { 252 int featureTypeValue = kTextSpacingType; 253 int featureSelectorValue = mapFontWidthVariantToCTFeatureSelector(m_widthVariant); 254 RetainPtr<CTFontDescriptorRef> sourceDescriptor(AdoptCF, CTFontCopyFontDescriptor(m_CTFont.get())); 255 RetainPtr<CFNumberRef> featureType(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeValue)); 256 RetainPtr<CFNumberRef> featureSelector(AdoptCF, CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorValue)); 257 RetainPtr<CTFontDescriptorRef> newDescriptor(AdoptCF, CTFontDescriptorCreateCopyWithFeature(sourceDescriptor.get(), featureType.get(), featureSelector.get())); 258 RetainPtr<CTFontRef> newFont(AdoptCF, CTFontCreateWithFontDescriptor(newDescriptor.get(), m_textSize, 0)); 259 260 if (newFont) 261 m_CTFont = newFont; 262 } 263 264 return m_CTFont.get(); 265 } 266 267 bool FontPlatformData::isAATFont(CTFontRef ctFont) const 268 { 269 CFDataRef table = CTFontCopyTable(ctFont, kCTFontTableMort, 0); 270 if (table) { 271 CFRelease(table); 272 return true; 273 } 274 table = CTFontCopyTable(ctFont, kCTFontTableMorx, 0); 275 if (table) { 276 CFRelease(table); 277 return true; 278 } 279 return false; 280 } 281 282 } // namespace blink 283