<http://webkit.org/b/91015> Remove BUILDING_ON / TARGETING macros in favor of system...
[WebKit-https.git] / Source / WebCore / platform / graphics / mac / SimpleFontDataMac.mm
1 /*
2  * Copyright (C) 2005, 2006, 2010, 2011 Apple Inc. All rights reserved.
3  * Copyright (C) 2006 Alexey Proskuryakov
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24  * THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #import "config.h"
28 #import "SimpleFontData.h"
29
30 #import "BlockExceptions.h"
31 #import "Color.h"
32 #import "FloatRect.h"
33 #import "Font.h"
34 #import "FontCache.h"
35 #import "FontDescription.h"
36 #import "SharedBuffer.h"
37 #import "WebCoreSystemInterface.h"
38 #import <AppKit/AppKit.h>
39 #import <ApplicationServices/ApplicationServices.h>
40 #import <float.h>
41 #import <unicode/uchar.h>
42 #import <wtf/Assertions.h>
43 #import <wtf/StdLibExtras.h>
44 #import <wtf/RetainPtr.h>
45 #import <wtf/UnusedParam.h>
46
47 @interface NSFont (WebAppKitSecretAPI)
48 - (BOOL)_isFakeFixedPitch;
49 @end
50
51 using namespace std;
52
53 namespace WebCore {
54   
55 const float smallCapsFontSizeMultiplier = 0.7f;
56
57 static bool fontHasVerticalGlyphs(CTFontRef ctFont)
58 {
59     // The check doesn't look neat but this is what AppKit does for vertical writing...
60     RetainPtr<CFArrayRef> tableTags(AdoptCF, CTFontCopyAvailableTables(ctFont, kCTFontTableOptionNoOptions));
61     CFIndex numTables = CFArrayGetCount(tableTags.get());
62     for (CFIndex index = 0; index < numTables; ++index) {
63         CTFontTableTag tag = (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(tableTags.get(), index);
64         if (tag == kCTFontTableVhea || tag == kCTFontTableVORG)
65             return true;
66     }
67     return false;
68 }
69
70 static bool initFontData(SimpleFontData* fontData)
71 {
72     if (!fontData->platformData().cgFont())
73         return false;
74
75     return true;
76 }
77
78 static NSString *webFallbackFontFamily(void)
79 {
80     DEFINE_STATIC_LOCAL(RetainPtr<NSString>, webFallbackFontFamily, ([[NSFont systemFontOfSize:16.0f] familyName]));
81     return webFallbackFontFamily.get();
82 }
83
84 #if !ERROR_DISABLED
85 #if defined(__LP64__) || __MAC_OS_X_VERSION_MIN_REQUIRED >= 1070
86 static NSString* pathFromFont(NSFont*)
87 {
88     // FMGetATSFontRefFromFont is not available. As pathFromFont is only used for debugging purposes,
89     // returning nil is acceptable.
90     return nil;
91 }
92 #else
93 static NSString* pathFromFont(NSFont *font)
94 {
95     ATSFontRef atsFont = FMGetATSFontRefFromFont(CTFontGetPlatformFont(toCTFontRef(font), 0));
96     FSRef fileRef;
97
98     OSStatus status = ATSFontGetFileReference(atsFont, &fileRef);
99     if (status != noErr)
100         return nil;
101
102     UInt8 filePathBuffer[PATH_MAX];
103     status = FSRefMakePath(&fileRef, filePathBuffer, PATH_MAX);
104     if (status == noErr)
105         return [NSString stringWithUTF8String:(const char*)filePathBuffer];
106
107     return nil;
108 }
109 #endif // __LP64__
110 #endif // !ERROR_DISABLED
111
112 const SimpleFontData* SimpleFontData::getCompositeFontReferenceFontData(NSFont *key) const
113 {
114     if (key && !CFEqual(RetainPtr<CFStringRef>(AdoptCF, CTFontCopyPostScriptName(CTFontRef(key))).get(), CFSTR("LastResort"))) {
115         if (!m_derivedFontData)
116             m_derivedFontData = DerivedFontData::create(isCustomFont());
117         if (!m_derivedFontData->compositeFontReferences)
118             m_derivedFontData->compositeFontReferences.adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, NULL));
119         else {
120             const SimpleFontData* found = static_cast<const SimpleFontData*>(CFDictionaryGetValue(m_derivedFontData->compositeFontReferences.get(), static_cast<const void *>(key)));
121             if (found)
122                 return found;
123         }
124         if (CFMutableDictionaryRef dictionary = m_derivedFontData->compositeFontReferences.get()) {
125             bool isUsingPrinterFont = platformData().isPrinterFont();
126             NSFont *substituteFont = isUsingPrinterFont ? [key printerFont] : [key screenFont];
127
128             CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(substituteFont));
129             bool syntheticBold = platformData().syntheticBold() && !(traits & kCTFontBoldTrait);
130             bool syntheticOblique = platformData().syntheticOblique() && !(traits & kCTFontItalicTrait);
131
132             FontPlatformData substitutePlatform(substituteFont, platformData().size(), isUsingPrinterFont, syntheticBold, syntheticOblique, platformData().orientation(), platformData().textOrientation(), platformData().widthVariant());
133             SimpleFontData* value = new SimpleFontData(substitutePlatform, isCustomFont());
134             if (value) {
135                 CFDictionaryAddValue(dictionary, key, value);
136                 return value;
137             }
138         }
139     }
140     return 0;
141 }
142
143 void SimpleFontData::platformInit()
144 {
145 #if USE(ATSUI)
146     m_ATSUMirrors = false;
147     m_checkedShapesArabic = false;
148     m_shapesArabic = false;
149 #endif
150
151     m_syntheticBoldOffset = m_platformData.m_syntheticBold ? 1.0f : 0.f;
152
153     bool failedSetup = false;
154     if (!initFontData(this)) {
155         // Ack! Something very bad happened, like a corrupt font.
156         // Try looking for an alternate 'base' font for this renderer.
157
158         // Special case hack to use "Times New Roman" in place of "Times".
159         // "Times RO" is a common font whose family name is "Times".
160         // It overrides the normal "Times" family font.
161         // It also appears to have a corrupt regular variant.
162         NSString *fallbackFontFamily;
163         if ([[m_platformData.font() familyName] isEqual:@"Times"])
164             fallbackFontFamily = @"Times New Roman";
165         else
166             fallbackFontFamily = webFallbackFontFamily();
167         
168         // Try setting up the alternate font.
169         // This is a last ditch effort to use a substitute font when something has gone wrong.
170 #if !ERROR_DISABLED
171         RetainPtr<NSFont> initialFont = m_platformData.font();
172 #endif
173         if (m_platformData.font())
174             m_platformData.setFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toFamily:fallbackFontFamily]);
175         else
176             m_platformData.setFont([NSFont fontWithName:fallbackFontFamily size:m_platformData.size()]);
177 #if !ERROR_DISABLED
178         NSString *filePath = pathFromFont(initialFont.get());
179         if (!filePath)
180             filePath = @"not known";
181 #endif
182         if (!initFontData(this)) {
183             if ([fallbackFontFamily isEqual:@"Times New Roman"]) {
184                 // OK, couldn't setup Times New Roman as an alternate to Times, fallback
185                 // on the system font.  If this fails we have no alternative left.
186                 m_platformData.setFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toFamily:webFallbackFontFamily()]);
187                 if (!initFontData(this)) {
188                     // We tried, Times, Times New Roman, and the system font. No joy. We have to give up.
189                     LOG_ERROR("unable to initialize with font %@ at %@", initialFont.get(), filePath);
190                     failedSetup = true;
191                 }
192             } else {
193                 // We tried the requested font and the system font. No joy. We have to give up.
194                 LOG_ERROR("unable to initialize with font %@ at %@", initialFont.get(), filePath);
195                 failedSetup = true;
196             }
197         }
198
199         // Report the problem.
200         LOG_ERROR("Corrupt font detected, using %@ in place of %@ located at \"%@\".",
201             [m_platformData.font() familyName], [initialFont.get() familyName], filePath);
202     }
203
204     // If all else fails, try to set up using the system font.
205     // This is probably because Times and Times New Roman are both unavailable.
206     if (failedSetup) {
207         m_platformData.setFont([NSFont systemFontOfSize:[m_platformData.font() pointSize]]);
208         LOG_ERROR("failed to set up font, using system font %s", m_platformData.font());
209         initFontData(this);
210     }
211     
212     int iAscent;
213     int iDescent;
214     int iLineGap;
215     unsigned unitsPerEm;
216     iAscent = CGFontGetAscent(m_platformData.cgFont());
217     // Some fonts erroneously specify a positive descender value. We follow Core Text in assuming that
218     // such fonts meant the same distance, but in the reverse direction.
219     iDescent = -abs(CGFontGetDescent(m_platformData.cgFont()));
220     iLineGap = CGFontGetLeading(m_platformData.cgFont());
221     unitsPerEm = CGFontGetUnitsPerEm(m_platformData.cgFont());
222
223     float pointSize = m_platformData.m_size;
224     float ascent = scaleEmToUnits(iAscent, unitsPerEm) * pointSize;
225     float descent = -scaleEmToUnits(iDescent, unitsPerEm) * pointSize;
226     float lineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize;
227
228     // We need to adjust Times, Helvetica, and Courier to closely match the
229     // vertical metrics of their Microsoft counterparts that are the de facto
230     // web standard. The AppKit adjustment of 20% is too big and is
231     // incorrectly added to line spacing, so we use a 15% adjustment instead
232     // and add it to the ascent.
233     NSString *familyName = [m_platformData.font() familyName];
234     if ([familyName isEqualToString:@"Times"] || [familyName isEqualToString:@"Helvetica"] || [familyName isEqualToString:@"Courier"])
235         ascent += floorf(((ascent + descent) * 0.15f) + 0.5f);
236 #if __MAC_OS_X_VERSION_MIN_REQUIRED == 1050
237     else if ([familyName isEqualToString:@"Geeza Pro"]) {
238         // Geeza Pro has glyphs that draw slightly above the ascent or far below the descent. Adjust
239         // those vertical metrics to better match reality, so that diacritics at the bottom of one line
240         // do not overlap diacritics at the top of the next line.
241         ascent *= 1.08f;
242         descent *= 2.f;
243     }
244 #endif
245
246     // Compute and store line spacing, before the line metrics hacks are applied.
247     m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap));
248
249     // Hack Hiragino line metrics to allow room for marked text underlines.
250     // <rdar://problem/5386183>
251     if (descent < 3 && lineGap >= 3 && [familyName hasPrefix:@"Hiragino"]) {
252         lineGap -= 3 - descent;
253         descent = 3;
254     }
255     
256     if (platformData().orientation() == Vertical && !isTextOrientationFallback())
257         m_hasVerticalGlyphs = fontHasVerticalGlyphs(m_platformData.ctFont());
258
259     float xHeight;
260
261     if (platformData().orientation() == Horizontal) {
262         // Measure the actual character "x", since it's possible for it to extend below the baseline, and we need the
263         // reported x-height to only include the portion of the glyph that is above the baseline.
264         GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
265         NSGlyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0;
266         if (xGlyph)
267             xHeight = -CGRectGetMinY(platformBoundsForGlyph(xGlyph));
268         else
269             xHeight = scaleEmToUnits(CGFontGetXHeight(m_platformData.cgFont()), unitsPerEm) * pointSize;
270     } else
271         xHeight = verticalRightOrientationFontData()->fontMetrics().xHeight();
272
273     m_fontMetrics.setUnitsPerEm(unitsPerEm);
274     m_fontMetrics.setAscent(ascent);
275     m_fontMetrics.setDescent(descent);
276     m_fontMetrics.setLineGap(lineGap);
277     m_fontMetrics.setXHeight(xHeight);
278 }
279
280 static CFDataRef copyFontTableForTag(FontPlatformData& platformData, FourCharCode tableName)
281 {
282     return CGFontCopyTableForTag(platformData.cgFont(), tableName);
283 }
284
285 void SimpleFontData::platformCharWidthInit()
286 {
287     m_avgCharWidth = 0;
288     m_maxCharWidth = 0;
289     
290     RetainPtr<CFDataRef> os2Table(AdoptCF, copyFontTableForTag(m_platformData, 'OS/2'));
291     if (os2Table && CFDataGetLength(os2Table.get()) >= 4) {
292         const UInt8* os2 = CFDataGetBytePtr(os2Table.get());
293         SInt16 os2AvgCharWidth = os2[2] * 256 + os2[3];
294         m_avgCharWidth = scaleEmToUnits(os2AvgCharWidth, m_fontMetrics.unitsPerEm()) * m_platformData.m_size;
295     }
296
297     RetainPtr<CFDataRef> headTable(AdoptCF, copyFontTableForTag(m_platformData, 'head'));
298     if (headTable && CFDataGetLength(headTable.get()) >= 42) {
299         const UInt8* head = CFDataGetBytePtr(headTable.get());
300         ushort uxMin = head[36] * 256 + head[37];
301         ushort uxMax = head[40] * 256 + head[41];
302         SInt16 xMin = static_cast<SInt16>(uxMin);
303         SInt16 xMax = static_cast<SInt16>(uxMax);
304         float diff = static_cast<float>(xMax - xMin);
305         m_maxCharWidth = scaleEmToUnits(diff, m_fontMetrics.unitsPerEm()) * m_platformData.m_size;
306     }
307
308     // Fallback to a cross-platform estimate, which will populate these values if they are non-positive.
309     initCharWidths();
310 }
311
312 void SimpleFontData::platformDestroy()
313 {
314     if (!isCustomFont() && m_derivedFontData) {
315         // These come from the cache.
316         if (m_derivedFontData->smallCaps)
317             fontCache()->releaseFontData(m_derivedFontData->smallCaps.leakPtr());
318
319         if (m_derivedFontData->emphasisMark)
320             fontCache()->releaseFontData(m_derivedFontData->emphasisMark.leakPtr());
321     }
322
323 #if USE(ATSUI)
324     HashMap<unsigned, ATSUStyle>::iterator end = m_ATSUStyleMap.end();
325     for (HashMap<unsigned, ATSUStyle>::iterator it = m_ATSUStyleMap.begin(); it != end; ++it)
326         ATSUDisposeStyle(it->second);
327 #endif
328 }
329
330 PassOwnPtr<SimpleFontData> SimpleFontData::createScaledFontData(const FontDescription& fontDescription, float scaleFactor) const
331 {
332     if (isCustomFont()) {
333         FontPlatformData scaledFontData(m_platformData);
334         scaledFontData.m_size = scaledFontData.m_size * scaleFactor;
335         return adoptPtr(new SimpleFontData(scaledFontData, true, false));
336     }
337
338     BEGIN_BLOCK_OBJC_EXCEPTIONS;
339     float size = m_platformData.size() * scaleFactor;
340     FontPlatformData scaledFontData([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toSize:size], size, m_platformData.isPrinterFont(), false, false, m_platformData.orientation());
341
342     // AppKit resets the type information (screen/printer) when you convert a font to a different size.
343     // We have to fix up the font that we're handed back.
344     scaledFontData.setFont(fontDescription.usePrinterFont() ? [scaledFontData.font() printerFont] : [scaledFontData.font() screenFont]);
345
346     if (scaledFontData.font()) {
347         NSFontManager *fontManager = [NSFontManager sharedFontManager];
348         NSFontTraitMask fontTraits = [fontManager traitsOfFont:m_platformData.font()];
349
350         if (m_platformData.m_syntheticBold)
351             fontTraits |= NSBoldFontMask;
352         if (m_platformData.m_syntheticOblique)
353             fontTraits |= NSItalicFontMask;
354
355         NSFontTraitMask scaledFontTraits = [fontManager traitsOfFont:scaledFontData.font()];
356         scaledFontData.m_syntheticBold = (fontTraits & NSBoldFontMask) && !(scaledFontTraits & NSBoldFontMask);
357         scaledFontData.m_syntheticOblique = (fontTraits & NSItalicFontMask) && !(scaledFontTraits & NSItalicFontMask);
358
359         // SimpleFontData::platformDestroy() takes care of not deleting the cached font data twice.
360         return adoptPtr(fontCache()->getCachedFontData(&scaledFontData));
361     }
362     END_BLOCK_OBJC_EXCEPTIONS;
363
364     return nullptr;
365 }
366
367 SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
368 {
369     if (!m_derivedFontData)
370         m_derivedFontData = DerivedFontData::create(isCustomFont());
371     if (!m_derivedFontData->smallCaps)
372         m_derivedFontData->smallCaps = createScaledFontData(fontDescription, smallCapsFontSizeMultiplier);
373
374     return m_derivedFontData->smallCaps.get();
375 }
376
377 SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
378 {
379     if (!m_derivedFontData)
380         m_derivedFontData = DerivedFontData::create(isCustomFont());
381     if (!m_derivedFontData->emphasisMark)
382         m_derivedFontData->emphasisMark = createScaledFontData(fontDescription, .5f);
383
384     return m_derivedFontData->emphasisMark.get();
385 }
386
387 bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
388 {
389     NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<unichar*>(characters) length:length freeWhenDone:NO];
390     NSCharacterSet *set = [[m_platformData.font() coveredCharacterSet] invertedSet];
391     bool result = set && [string rangeOfCharacterFromSet:set].location == NSNotFound;
392     [string release];
393     return result;
394 }
395
396 void SimpleFontData::determinePitch()
397 {
398     NSFont* f = m_platformData.font();
399     // Special case Osaka-Mono.
400     // According to <rdar://problem/3999467>, we should treat Osaka-Mono as fixed pitch.
401     // Note that the AppKit does not report Osaka-Mono as fixed pitch.
402
403     // Special case MS-PGothic.
404     // According to <rdar://problem/4032938>, we should not treat MS-PGothic as fixed pitch.
405     // Note that AppKit does report MS-PGothic as fixed pitch.
406
407     // Special case MonotypeCorsiva
408     // According to <rdar://problem/5454704>, we should not treat MonotypeCorsiva as fixed pitch.
409     // Note that AppKit does report MonotypeCorsiva as fixed pitch.
410
411     NSString *name = [f fontName];
412     m_treatAsFixedPitch = ([f isFixedPitch] || [f _isFakeFixedPitch] ||
413            [name caseInsensitiveCompare:@"Osaka-Mono"] == NSOrderedSame) &&
414            [name caseInsensitiveCompare:@"MS-PGothic"] != NSOrderedSame &&
415            [name caseInsensitiveCompare:@"MonotypeCorsiva"] != NSOrderedSame;
416 }
417
418 FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const
419 {
420     FloatRect boundingBox;
421     boundingBox = CTFontGetBoundingRectsForGlyphs(m_platformData.ctFont(), platformData().orientation() == Vertical ? kCTFontVerticalOrientation : kCTFontHorizontalOrientation, &glyph, 0, 1);
422     boundingBox.setY(-boundingBox.maxY());
423     if (m_syntheticBoldOffset)
424         boundingBox.setWidth(boundingBox.width() + m_syntheticBoldOffset);
425
426     return boundingBox;
427 }
428
429 float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
430 {
431     CGSize advance = CGSizeZero;
432     if (platformData().orientation() == Horizontal || m_isBrokenIdeographFallback) {
433         NSFont *font = platformData().font();
434         if (font && platformData().isColorBitmapFont())
435             advance = NSSizeToCGSize([font advancementForGlyph:glyph]);
436         else {
437             float pointSize = platformData().m_size;
438             CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
439             if (!wkGetGlyphTransformedAdvances(platformData().cgFont(), font, &m, &glyph, &advance)) {
440                 LOG_ERROR("Unable to cache glyph widths for %@ %f", [font displayName], pointSize);
441                 advance.width = 0;
442             }
443         }
444     } else
445         CTFontGetAdvancesForGlyphs(m_platformData.ctFont(), kCTFontVerticalOrientation, &glyph, &advance, 1);
446
447     return advance.width + m_syntheticBoldOffset;
448 }
449
450 struct ProviderInfo {
451     const UChar* characters;
452     size_t length;
453     CFDictionaryRef attributes;
454 };
455
456 static const UniChar* provideStringAndAttributes(CFIndex stringIndex, CFIndex* count, CFDictionaryRef* attributes, void* context)
457 {
458     ProviderInfo* info = static_cast<struct ProviderInfo*>(context);
459     if (stringIndex < 0 || static_cast<size_t>(stringIndex) >= info->length)
460         return 0;
461
462     *count = info->length - stringIndex;
463     *attributes = info->attributes;
464     return info->characters + stringIndex;
465 }
466
467 bool SimpleFontData::canRenderCombiningCharacterSequence(const UChar* characters, size_t length) const
468 {
469     ASSERT(isMainThread());
470
471     if (!m_combiningCharacterSequenceSupport)
472         m_combiningCharacterSequenceSupport = adoptPtr(new HashMap<String, bool>);
473
474     WTF::HashMap<String, bool>::AddResult addResult = m_combiningCharacterSequenceSupport->add(String(characters, length), false);
475     if (!addResult.isNewEntry)
476         return addResult.iterator->second;
477
478     RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(platformData().ctFont(), 0));
479
480     ProviderInfo info = { characters, length, getCFStringAttributes(0, platformData().orientation()) };
481     RetainPtr<CTLineRef> line(AdoptCF, wkCreateCTLineWithUniCharProvider(&provideStringAndAttributes, 0, &info));
482
483     CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
484     CFIndex runCount = CFArrayGetCount(runArray);
485
486     for (CFIndex r = 0; r < runCount; r++) {
487         CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
488         ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());
489         CFDictionaryRef runAttributes = CTRunGetAttributes(ctRun);
490         CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(runAttributes, kCTFontAttributeName));
491         RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont, 0));
492         if (!CFEqual(runCGFont.get(), cgFont.get()))
493             return false;
494     }
495
496     addResult.iterator->second = true;
497     return true;
498 }
499
500 } // namespace WebCore