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 "FontPlatformData.h" 26 27#import "WebCoreSystemInterface.h" 28#import <AppKit/NSFont.h> 29#import <wtf/text/WTFString.h> 30 31namespace WebCore { 32 33// These CoreText Text Spacing feature selectors are not defined in CoreText. 34enum TextSpacingCTFeatureSelector { TextSpacingProportional, TextSpacingFullWidth, TextSpacingHalfWidth, TextSpacingThirdWidth, TextSpacingQuarterWidth }; 35 36#if PLATFORM(MAC) 37void FontPlatformData::loadFont(NSFont* nsFont, float, NSFont*& outNSFont, CGFontRef& cgFont) 38{ 39 outNSFont = nsFont; 40 cgFont = CTFontCopyGraphicsFont(toCTFontRef(nsFont), 0); 41} 42#endif // PLATFORM(MAC) 43 44FontPlatformData::FontPlatformData(NSFont *nsFont, float size, bool isPrinterFont, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, FontWidthVariant widthVariant) 45 : m_syntheticBold(syntheticBold) 46 , m_syntheticOblique(syntheticOblique) 47 , m_orientation(orientation) 48 , m_size(size) 49 , m_widthVariant(widthVariant) 50 , m_font(nsFont) 51 , m_isColorBitmapFont(false) 52 , m_isCompositeFontReference(false) 53 , m_isPrinterFont(isPrinterFont) 54{ 55 ASSERT_ARG(nsFont, nsFont); 56 57 CGFontRef cgFont = 0; 58 loadFont(nsFont, size, m_font, cgFont); 59 60#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 61 { 62 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(m_font)); 63 m_isColorBitmapFont = traits & kCTFontColorGlyphsTrait; 64#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 65 m_isCompositeFontReference = traits & kCTFontCompositeTrait; 66#endif 67 } 68#endif 69 70 if (m_font) 71 CFRetain(m_font); 72 73 m_cgFont = adoptCF(cgFont); 74} 75 76FontPlatformData:: ~FontPlatformData() 77{ 78 if (m_font && m_font != reinterpret_cast<NSFont *>(-1)) 79 CFRelease(m_font); 80} 81 82void FontPlatformData::platformDataInit(const FontPlatformData& f) 83{ 84 m_font = f.m_font && f.m_font != reinterpret_cast<NSFont *>(-1) ? const_cast<NSFont *>(static_cast<const NSFont *>(CFRetain(f.m_font))) : f.m_font; 85 86 m_cgFont = f.m_cgFont; 87 m_CTFont = f.m_CTFont; 88} 89 90const FontPlatformData& FontPlatformData::platformDataAssign(const FontPlatformData& f) 91{ 92 m_cgFont = f.m_cgFont; 93 if (m_font == f.m_font) 94 return *this; 95 if (f.m_font && f.m_font != reinterpret_cast<NSFont *>(-1)) 96 CFRetain(f.m_font); 97 if (m_font && m_font != reinterpret_cast<NSFont *>(-1)) 98 CFRelease(m_font); 99 m_font = f.m_font; 100 m_CTFont = f.m_CTFont; 101 return *this; 102} 103 104bool FontPlatformData::platformIsEqual(const FontPlatformData& other) const 105{ 106 if (m_font || other.m_font) 107 return m_font == other.m_font; 108 return m_cgFont == other.m_cgFont; 109} 110 111void FontPlatformData::setFont(NSFont *font) 112{ 113 ASSERT_ARG(font, font); 114 ASSERT(m_font != reinterpret_cast<NSFont *>(-1)); 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_size = [font pointSize]; 124 125 CGFontRef cgFont = 0; 126 NSFont* loadedFont = 0; 127 loadFont(m_font, m_size, loadedFont, cgFont); 128 129 m_cgFont = adoptCF(cgFont); 130#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070 131 { 132 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(m_font)); 133 m_isColorBitmapFont = traits & kCTFontColorGlyphsTrait; 134#if PLATFORM(IOS) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 135 m_isCompositeFontReference = traits & kCTFontCompositeTrait; 136#endif 137 } 138#endif 139 m_CTFont = 0; 140} 141 142bool FontPlatformData::roundsGlyphAdvances() const 143{ 144 return [m_font renderingMode] == NSFontAntialiasedIntegerAdvancementsRenderingMode; 145} 146 147bool FontPlatformData::allowsLigatures() const 148{ 149 return ![[m_font coveredCharacterSet] characterIsMember:'a']; 150} 151 152inline int mapFontWidthVariantToCTFeatureSelector(FontWidthVariant variant) 153{ 154 switch(variant) { 155 case RegularWidth: 156 return TextSpacingProportional; 157 158 case HalfWidth: 159 return TextSpacingHalfWidth; 160 161 case ThirdWidth: 162 return TextSpacingThirdWidth; 163 164 case QuarterWidth: 165 return TextSpacingQuarterWidth; 166 } 167 168 ASSERT_NOT_REACHED(); 169 return TextSpacingProportional; 170} 171 172static CFDictionaryRef createFeatureSettingDictionary(int featureTypeIdentifier, int featureSelectorIdentifier) 173{ 174 RetainPtr<CFNumberRef> featureTypeIdentifierNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeIdentifier)); 175 RetainPtr<CFNumberRef> featureSelectorIdentifierNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorIdentifier)); 176 177 const void* settingKeys[] = { kCTFontFeatureTypeIdentifierKey, kCTFontFeatureSelectorIdentifierKey }; 178 const void* settingValues[] = { featureTypeIdentifierNumber.get(), featureSelectorIdentifierNumber.get() }; 179 180 return CFDictionaryCreate(kCFAllocatorDefault, settingKeys, settingValues, WTF_ARRAY_LENGTH(settingKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 181} 182 183static CTFontDescriptorRef cascadeToLastResortFontDescriptor() 184{ 185 static CTFontDescriptorRef descriptor; 186 if (descriptor) 187 return descriptor; 188 189 const void* keys[] = { kCTFontCascadeListAttribute }; 190 const void* descriptors[] = { CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0) }; 191 const void* values[] = { CFArrayCreate(kCFAllocatorDefault, descriptors, WTF_ARRAY_LENGTH(descriptors), &kCFTypeArrayCallBacks) }; 192 RetainPtr<CFDictionaryRef> attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); 193 194 descriptor = CTFontDescriptorCreateWithAttributes(attributes.get()); 195 196 return descriptor; 197} 198 199static CTFontDescriptorRef cascadeToLastResortAndDisableSwashesFontDescriptor() 200{ 201 static CTFontDescriptorRef descriptor; 202 if (descriptor) 203 return descriptor; 204 205 RetainPtr<CFDictionaryRef> lineInitialSwashesOffSetting = adoptCF(createFeatureSettingDictionary(kSmartSwashType, kLineInitialSwashesOffSelector)); 206 RetainPtr<CFDictionaryRef> lineFinalSwashesOffSetting = adoptCF(createFeatureSettingDictionary(kSmartSwashType, kLineFinalSwashesOffSelector)); 207 208 const void* settingDictionaries[] = { lineInitialSwashesOffSetting.get(), lineFinalSwashesOffSetting.get() }; 209 RetainPtr<CFArrayRef> featureSettings = adoptCF(CFArrayCreate(kCFAllocatorDefault, settingDictionaries, WTF_ARRAY_LENGTH(settingDictionaries), &kCFTypeArrayCallBacks)); 210 211 const void* keys[] = { kCTFontFeatureSettingsAttribute }; 212 const void* values[] = { featureSettings.get() }; 213 RetainPtr<CFDictionaryRef> attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); 214 215 descriptor = CTFontDescriptorCreateCopyWithAttributes(cascadeToLastResortFontDescriptor(), attributes.get()); 216 217 return descriptor; 218} 219 220CTFontRef FontPlatformData::ctFont() const 221{ 222 if (m_CTFont) 223 return m_CTFont.get(); 224 225 m_CTFont = toCTFontRef(m_font); 226 if (m_CTFont) { 227 CTFontDescriptorRef fontDescriptor; 228 RetainPtr<CFStringRef> postScriptName = adoptCF(CTFontCopyPostScriptName(m_CTFont.get())); 229 // Hoefler Text Italic has line-initial and -final swashes enabled by default, so disable them. 230 if (CFEqual(postScriptName.get(), CFSTR("HoeflerText-Italic")) || CFEqual(postScriptName.get(), CFSTR("HoeflerText-BlackItalic"))) 231 fontDescriptor = cascadeToLastResortAndDisableSwashesFontDescriptor(); 232 else 233 fontDescriptor = cascadeToLastResortFontDescriptor(); 234 m_CTFont = adoptCF(CTFontCreateCopyWithAttributes(m_CTFont.get(), m_size, 0, fontDescriptor)); 235 } else 236 m_CTFont = adoptCF(CTFontCreateWithGraphicsFont(m_cgFont.get(), m_size, 0, cascadeToLastResortFontDescriptor())); 237 238 if (m_widthVariant != RegularWidth) { 239 int featureTypeValue = kTextSpacingType; 240 int featureSelectorValue = mapFontWidthVariantToCTFeatureSelector(m_widthVariant); 241 RetainPtr<CTFontDescriptorRef> sourceDescriptor = adoptCF(CTFontCopyFontDescriptor(m_CTFont.get())); 242 RetainPtr<CFNumberRef> featureType = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeValue)); 243 RetainPtr<CFNumberRef> featureSelector = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorValue)); 244 RetainPtr<CTFontDescriptorRef> newDescriptor = adoptCF(CTFontDescriptorCreateCopyWithFeature(sourceDescriptor.get(), featureType.get(), featureSelector.get())); 245 RetainPtr<CTFontRef> newFont = adoptCF(CTFontCreateWithFontDescriptor(newDescriptor.get(), m_size, 0)); 246 247 if (newFont) 248 m_CTFont = newFont; 249 } 250 251 return m_CTFont.get(); 252} 253 254#ifndef NDEBUG 255String FontPlatformData::description() const 256{ 257 RetainPtr<CFStringRef> cgFontDescription = adoptCF(CFCopyDescription(cgFont())); 258 return String(cgFontDescription.get()) + " " + String::number(m_size) 259 + (m_syntheticBold ? " synthetic bold" : "") + (m_syntheticOblique ? " synthetic oblique" : "") + (m_orientation ? " vertical orientation" : ""); 260} 261#endif 262 263} // namespace WebCore 264