2 * This file is part of the internal font implementation.
4 * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
5 * Copyright (c) 2010 Google Inc. All rights reserved.
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.
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.
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.
25 #import "FontPlatformData.h"
27 #import "CoreTextSPI.h"
28 #import "SharedBuffer.h"
29 #import "WebCoreSystemInterface.h"
30 #import <wtf/text/WTFString.h>
33 #import <AppKit/NSFont.h>
35 #import "CoreGraphicsSPI.h"
36 #import <CoreText/CoreText.h>
41 // These CoreText Text Spacing feature selectors are not defined in CoreText.
42 enum TextSpacingCTFeatureSelector { TextSpacingProportional, TextSpacingFullWidth, TextSpacingHalfWidth, TextSpacingThirdWidth, TextSpacingQuarterWidth };
44 FontPlatformData::FontPlatformData(CTFontRef font, float size, bool isPrinterFont, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, FontWidthVariant widthVariant)
45 : m_syntheticBold(syntheticBold)
46 , m_syntheticOblique(syntheticOblique)
47 , m_orientation(orientation)
49 , m_widthVariant(widthVariant)
51 , m_cgFont(adoptCF(CTFontCopyGraphicsFont(font, NULL)))
52 , m_isColorBitmapFont(CTFontGetSymbolicTraits(font) & kCTFontTraitColorGlyphs)
53 , m_isCompositeFontReference(CTFontGetSymbolicTraits(font) & kCTFontCompositeTrait)
54 , m_isPrinterFont(isPrinterFont)
56 ASSERT_ARG(font, font);
61 // FIXME: Remove this when all NSFont usage is removed.
62 FontPlatformData::FontPlatformData(NSFont *font, float size, bool isPrinterFont, bool syntheticBold, bool syntheticOblique, FontOrientation orientation, FontWidthVariant widthVariant)
63 : FontPlatformData((CTFontRef)font, size, isPrinterFont, syntheticBold, syntheticOblique, orientation, widthVariant)
68 FontPlatformData::~FontPlatformData()
70 if (m_font && m_font != reinterpret_cast<CTFontRef>(-1))
74 void FontPlatformData::platformDataInit(const FontPlatformData& f)
76 m_font = f.m_font && f.m_font != reinterpret_cast<CTFontRef>(-1) ? static_cast<CTFontRef>(const_cast<void *>(CFRetain(f.m_font))) : f.m_font;
79 m_isEmoji = f.m_isEmoji;
81 m_cgFont = f.m_cgFont;
82 m_ctFont = f.m_ctFont;
83 m_isPrinterFont = f.m_isPrinterFont;
86 const FontPlatformData& FontPlatformData::platformDataAssign(const FontPlatformData& f)
88 m_cgFont = f.m_cgFont;
90 m_isEmoji = f.m_isEmoji;
92 if (m_font && m_font != reinterpret_cast<CTFontRef>(-1) && f.m_font && f.m_font != reinterpret_cast<CTFontRef>(-1) && CFEqual(m_font, f.m_font))
94 if (f.m_font && f.m_font != reinterpret_cast<CTFontRef>(-1))
96 if (m_font && m_font != reinterpret_cast<CTFontRef>(-1))
99 m_ctFont = f.m_ctFont;
100 m_isPrinterFont = f.m_isPrinterFont;
105 bool FontPlatformData::platformIsEqual(const FontPlatformData& other) const
108 if (m_font || other.m_font) {
110 result = m_font && m_font != reinterpret_cast<CTFontRef>(-1) && other.m_font && other.m_font != reinterpret_cast<CTFontRef>(-1) && CFEqual(m_font, other.m_font);
113 ASSERT(m_isEmoji == other.m_isEmoji);
116 result = m_font == other.m_font;
117 #endif // PLATFORM(IOS)
122 if (m_cgFont == other.m_cgFont)
123 ASSERT(m_isEmoji == other.m_isEmoji);
125 #endif // PLATFORM(IOS)
126 return m_cgFont == other.m_cgFont;
129 void FontPlatformData::setFont(CTFontRef font)
131 ASSERT_ARG(font, font);
132 ASSERT(m_font != reinterpret_cast<CTFontRef>(-1));
141 m_size = CTFontGetSize(font);
142 m_cgFont = adoptCF(CTFontCopyGraphicsFont(font, nullptr));
144 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(m_font);
145 m_isColorBitmapFont = traits & kCTFontTraitColorGlyphs;
146 m_isCompositeFontReference = traits & kCTFontCompositeTrait;
151 bool FontPlatformData::roundsGlyphAdvances() const
154 return [(NSFont *)m_font renderingMode] == NSFontAntialiasedIntegerAdvancementsRenderingMode;
161 bool FontPlatformData::allowsLigatures() const
164 return ![[(NSFont *)m_font coveredCharacterSet] characterIsMember:'a'];
169 RetainPtr<CFCharacterSetRef> characterSet = adoptCF(CTFontCopyCharacterSet(ctFont()));
170 return !(characterSet.get() && CFCharacterSetIsCharacterMember(characterSet.get(), 'a'));
174 inline int mapFontWidthVariantToCTFeatureSelector(FontWidthVariant variant)
178 return TextSpacingProportional;
181 return TextSpacingHalfWidth;
184 return TextSpacingThirdWidth;
187 return TextSpacingQuarterWidth;
190 ASSERT_NOT_REACHED();
191 return TextSpacingProportional;
194 static CFDictionaryRef createFeatureSettingDictionary(int featureTypeIdentifier, int featureSelectorIdentifier)
196 RetainPtr<CFNumberRef> featureTypeIdentifierNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeIdentifier));
197 RetainPtr<CFNumberRef> featureSelectorIdentifierNumber = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorIdentifier));
199 const void* settingKeys[] = { kCTFontFeatureTypeIdentifierKey, kCTFontFeatureSelectorIdentifierKey };
200 const void* settingValues[] = { featureTypeIdentifierNumber.get(), featureSelectorIdentifierNumber.get() };
202 return CFDictionaryCreate(kCFAllocatorDefault, settingKeys, settingValues, WTF_ARRAY_LENGTH(settingKeys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
205 static CTFontDescriptorRef cascadeToLastResortFontDescriptor()
207 static CTFontDescriptorRef descriptor;
211 RetainPtr<CTFontDescriptorRef> lastResort = adoptCF(CTFontDescriptorCreateWithNameAndSize(CFSTR("LastResort"), 0));
213 const void* descriptors[] = { lastResort.get() };
214 RetainPtr<CFArrayRef> array = adoptCF(CFArrayCreate(kCFAllocatorDefault, descriptors, WTF_ARRAY_LENGTH(descriptors), &kCFTypeArrayCallBacks));
216 const void* keys[] = { kCTFontCascadeListAttribute };
217 const void* values[] = { array.get() };
218 RetainPtr<CFDictionaryRef> attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
220 descriptor = CTFontDescriptorCreateWithAttributes(attributes.get());
225 static CTFontDescriptorRef cascadeToLastResortAndDisableSwashesFontDescriptor()
227 static CTFontDescriptorRef descriptor;
231 RetainPtr<CFDictionaryRef> lineInitialSwashesOffSetting = adoptCF(createFeatureSettingDictionary(kSmartSwashType, kLineInitialSwashesOffSelector));
232 RetainPtr<CFDictionaryRef> lineFinalSwashesOffSetting = adoptCF(createFeatureSettingDictionary(kSmartSwashType, kLineFinalSwashesOffSelector));
234 const void* settingDictionaries[] = { lineInitialSwashesOffSetting.get(), lineFinalSwashesOffSetting.get() };
235 RetainPtr<CFArrayRef> featureSettings = adoptCF(CFArrayCreate(kCFAllocatorDefault, settingDictionaries, WTF_ARRAY_LENGTH(settingDictionaries), &kCFTypeArrayCallBacks));
237 const void* keys[] = { kCTFontFeatureSettingsAttribute };
238 const void* values[] = { featureSettings.get() };
239 RetainPtr<CFDictionaryRef> attributes = adoptCF(CFDictionaryCreate(kCFAllocatorDefault, keys, values, WTF_ARRAY_LENGTH(keys), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
241 descriptor = CTFontDescriptorCreateCopyWithAttributes(cascadeToLastResortFontDescriptor(), attributes.get());
246 CTFontRef FontPlatformData::ctFont() const
249 return m_ctFont.get();
251 ASSERT(m_cgFont.get());
255 CTFontDescriptorRef fontDescriptor;
256 RetainPtr<CFStringRef> postScriptName = adoptCF(CTFontCopyPostScriptName(m_ctFont.get()));
257 // Hoefler Text Italic has line-initial and -final swashes enabled by default, so disable them.
258 if (CFEqual(postScriptName.get(), CFSTR("HoeflerText-Italic")) || CFEqual(postScriptName.get(), CFSTR("HoeflerText-BlackItalic")))
259 fontDescriptor = cascadeToLastResortAndDisableSwashesFontDescriptor();
261 fontDescriptor = cascadeToLastResortFontDescriptor();
262 m_ctFont = adoptCF(CTFontCreateCopyWithAttributes(m_ctFont.get(), m_size, 0, fontDescriptor));
264 m_ctFont = adoptCF(CTFontCreateWithGraphicsFont(m_cgFont.get(), m_size, 0, cascadeToLastResortFontDescriptor()));
266 // Apple Color Emoji size is adjusted (and then re-adjusted by Core Text) and capped.
267 CGFloat size = !m_isEmoji ? m_size : m_size <= 15 ? 4 * (m_size + 2) / static_cast<CGFloat>(5) : 16;
268 CTFontDescriptorRef fontDescriptor;
269 const char* postScriptName = CGFontGetPostScriptName(m_cgFont.get());
270 if (postScriptName && (!strcmp(postScriptName, "HoeflerText-Italic") || !strcmp(postScriptName, "HoeflerText-BlackItalic")))
271 fontDescriptor = cascadeToLastResortAndDisableSwashesFontDescriptor();
273 fontDescriptor = cascadeToLastResortFontDescriptor();
274 m_ctFont = adoptCF(CTFontCreateWithGraphicsFont(m_cgFont.get(), size, 0, fontDescriptor));
275 #endif // !PLATFORM(IOS)
277 if (m_widthVariant != RegularWidth) {
278 int featureTypeValue = kTextSpacingType;
279 int featureSelectorValue = mapFontWidthVariantToCTFeatureSelector(m_widthVariant);
280 RetainPtr<CTFontDescriptorRef> sourceDescriptor = adoptCF(CTFontCopyFontDescriptor(m_ctFont.get()));
281 RetainPtr<CFNumberRef> featureType = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureTypeValue));
282 RetainPtr<CFNumberRef> featureSelector = adoptCF(CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &featureSelectorValue));
283 RetainPtr<CTFontDescriptorRef> newDescriptor = adoptCF(CTFontDescriptorCreateCopyWithFeature(sourceDescriptor.get(), featureType.get(), featureSelector.get()));
284 RetainPtr<CTFontRef> newFont = adoptCF(CTFontCreateWithFontDescriptor(newDescriptor.get(), m_size, 0));
290 return m_ctFont.get();
293 RetainPtr<CFTypeRef> FontPlatformData::objectForEqualityCheck(CTFontRef ctFont)
295 #if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED <= 80000) || (PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED <= 101000)
296 auto fontDescriptor = adoptCF(CTFontCopyFontDescriptor(ctFont));
297 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=138683 This is a shallow pointer compare for web fonts
298 // because the URL contains the address of the font. This means we might erroneously get false negatives.
299 RetainPtr<CFURLRef> url = adoptCF(static_cast<CFURLRef>(CTFontDescriptorCopyAttribute(fontDescriptor.get(), kCTFontReferenceURLAttribute)));
300 ASSERT(CFGetTypeID(url.get()) == CFURLGetTypeID());
303 return adoptCF(CTFontCopyGraphicsFont(ctFont, 0));
307 RetainPtr<CFTypeRef> FontPlatformData::objectForEqualityCheck() const
309 return objectForEqualityCheck(ctFont());
312 PassRefPtr<SharedBuffer> FontPlatformData::openTypeTable(uint32_t table) const
314 if (RetainPtr<CFDataRef> data = adoptCF(CGFontCopyTableForTag(cgFont(), table)))
315 return SharedBuffer::wrapCFData(data.get());
321 String FontPlatformData::description() const
323 RetainPtr<CFStringRef> cgFontDescription = adoptCF(CFCopyDescription(cgFont()));
324 return String(cgFontDescription.get()) + " " + String::number(m_size)
325 + (m_syntheticBold ? " synthetic bold" : "") + (m_syntheticOblique ? " synthetic oblique" : "") + (m_orientation ? " vertical orientation" : "");
329 } // namespace WebCore