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#if USE(APPKIT)
39#import <AppKit/AppKit.h>
40#import <ApplicationServices/ApplicationServices.h>
41#else
42#import <CoreText/CoreText.h>
43#endif
44#import <float.h>
45#import <unicode/uchar.h>
46#import <wtf/Assertions.h>
47#import <wtf/StdLibExtras.h>
48#import <wtf/RetainPtr.h>
49
50#if defined(__has_include) && __has_include(<CoreText/CTFontDescriptorPriv.h>)
51#import <CoreText/CTFontDescriptorPriv.h>
52#endif
53extern "C" bool CTFontDescriptorIsSystemUIFont(CTFontDescriptorRef);
54
55#if defined(__has_include) && __has_include(<CoreGraphics/CGFontGlyphSupport.h>)
56#import <CoreGraphics/CGFontGlyphSupport.h>
57#endif
58extern "C" bool CGFontGetGlyphAdvancesForStyle(CGFontRef font,
59    const CGAffineTransform *t, CGFontRenderingStyle style,
60    const CGGlyph glyphs[], size_t count, CGSize advances[]);
61
62#if !PLATFORM(IOS)
63@interface NSFont (WebAppKitSecretAPI)
64- (BOOL)_isFakeFixedPitch;
65@end
66#endif
67
68namespace WebCore {
69
70#if USE(APPKIT)
71static bool fontHasVerticalGlyphs(CTFontRef ctFont)
72{
73    // The check doesn't look neat but this is what AppKit does for vertical writing...
74    RetainPtr<CFArrayRef> tableTags = adoptCF(CTFontCopyAvailableTables(ctFont, kCTFontTableOptionNoOptions));
75    CFIndex numTables = CFArrayGetCount(tableTags.get());
76    for (CFIndex index = 0; index < numTables; ++index) {
77        CTFontTableTag tag = (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(tableTags.get(), index);
78        if (tag == kCTFontTableVhea || tag == kCTFontTableVORG)
79            return true;
80    }
81    return false;
82}
83
84static bool initFontData(SimpleFontData* fontData)
85{
86    if (!fontData->platformData().cgFont())
87        return false;
88
89    return true;
90}
91
92static NSString *webFallbackFontFamily(void)
93{
94    static NSString *webFallbackFontFamily = [[[NSFont systemFontOfSize:16.0f] familyName] retain];
95    return webFallbackFontFamily;
96}
97
98const SimpleFontData* SimpleFontData::getCompositeFontReferenceFontData(NSFont *key) const
99{
100    if (key && !CFEqual(adoptCF(CTFontCopyPostScriptName(CTFontRef(key))).get(), CFSTR("LastResort"))) {
101        if (!m_derivedFontData)
102            m_derivedFontData = DerivedFontData::create(isCustomFont());
103        if (!m_derivedFontData->compositeFontReferences)
104            m_derivedFontData->compositeFontReferences = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, NULL));
105        else {
106            const SimpleFontData* found = static_cast<const SimpleFontData*>(CFDictionaryGetValue(m_derivedFontData->compositeFontReferences.get(), static_cast<const void *>(key)));
107            if (found)
108                return found;
109        }
110        if (CFMutableDictionaryRef dictionary = m_derivedFontData->compositeFontReferences.get()) {
111            bool isUsingPrinterFont = platformData().isPrinterFont();
112            NSFont *substituteFont = isUsingPrinterFont ? [key printerFont] : [key screenFont];
113
114            CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(substituteFont));
115            bool syntheticBold = platformData().syntheticBold() && !(traits & kCTFontBoldTrait);
116            bool syntheticOblique = platformData().syntheticOblique() && !(traits & kCTFontItalicTrait);
117
118            FontPlatformData substitutePlatform(substituteFont, platformData().size(), isUsingPrinterFont, syntheticBold, syntheticOblique, platformData().orientation(), platformData().widthVariant());
119            if (RefPtr<SimpleFontData> value = adoptRef(new SimpleFontData(substitutePlatform, isCustomFont()))) {
120                SimpleFontData* valuePtr = value.get();
121                CFDictionaryAddValue(dictionary, key, value.release().leakRef());
122                return valuePtr;
123            }
124        }
125    }
126    return 0;
127}
128
129void SimpleFontData::platformInit()
130{
131    m_syntheticBoldOffset = m_platformData.m_syntheticBold ? 1.0f : 0.f;
132
133    bool failedSetup = false;
134    if (!initFontData(this)) {
135        // Ack! Something very bad happened, like a corrupt font.
136        // Try looking for an alternate 'base' font for this renderer.
137
138        // Special case hack to use "Times New Roman" in place of "Times".
139        // "Times RO" is a common font whose family name is "Times".
140        // It overrides the normal "Times" family font.
141        // It also appears to have a corrupt regular variant.
142        NSString *fallbackFontFamily;
143        if ([[m_platformData.font() familyName] isEqual:@"Times"])
144            fallbackFontFamily = @"Times New Roman";
145        else
146            fallbackFontFamily = webFallbackFontFamily();
147
148        // Try setting up the alternate font.
149        // This is a last ditch effort to use a substitute font when something has gone wrong.
150#if !ERROR_DISABLED
151        RetainPtr<NSFont> initialFont = m_platformData.font();
152#endif
153        if (m_platformData.font())
154            m_platformData.setFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toFamily:fallbackFontFamily]);
155        else
156            m_platformData.setFont([NSFont fontWithName:fallbackFontFamily size:m_platformData.size()]);
157        if (!initFontData(this)) {
158            if ([fallbackFontFamily isEqual:@"Times New Roman"]) {
159                // OK, couldn't setup Times New Roman as an alternate to Times, fallback
160                // on the system font.  If this fails we have no alternative left.
161                m_platformData.setFont([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toFamily:webFallbackFontFamily()]);
162                if (!initFontData(this)) {
163                    // We tried, Times, Times New Roman, and the system font. No joy. We have to give up.
164                    LOG_ERROR("unable to initialize with font %@", initialFont.get());
165                    failedSetup = true;
166                }
167            } else {
168                // We tried the requested font and the system font. No joy. We have to give up.
169                LOG_ERROR("unable to initialize with font %@", initialFont.get());
170                failedSetup = true;
171            }
172        }
173
174        // Report the problem.
175        LOG_ERROR("Corrupt font detected, using %@ in place of %@.",
176            [m_platformData.font() familyName], [initialFont.get() familyName]);
177    }
178
179    // If all else fails, try to set up using the system font.
180    // This is probably because Times and Times New Roman are both unavailable.
181    if (failedSetup) {
182        m_platformData.setFont([NSFont systemFontOfSize:[m_platformData.font() pointSize]]);
183        LOG_ERROR("failed to set up font, using system font %s", m_platformData.font());
184        initFontData(this);
185    }
186
187    int iAscent;
188    int iDescent;
189    int iLineGap;
190    unsigned unitsPerEm;
191    iAscent = CGFontGetAscent(m_platformData.cgFont());
192    // Some fonts erroneously specify a positive descender value. We follow Core Text in assuming that
193    // such fonts meant the same distance, but in the reverse direction.
194    iDescent = -abs(CGFontGetDescent(m_platformData.cgFont()));
195    iLineGap = CGFontGetLeading(m_platformData.cgFont());
196    unitsPerEm = CGFontGetUnitsPerEm(m_platformData.cgFont());
197
198    float pointSize = m_platformData.m_size;
199    float ascent = scaleEmToUnits(iAscent, unitsPerEm) * pointSize;
200    float descent = -scaleEmToUnits(iDescent, unitsPerEm) * pointSize;
201    float lineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize;
202
203    // We need to adjust Times, Helvetica, and Courier to closely match the
204    // vertical metrics of their Microsoft counterparts that are the de facto
205    // web standard. The AppKit adjustment of 20% is too big and is
206    // incorrectly added to line spacing, so we use a 15% adjustment instead
207    // and add it to the ascent.
208    NSString *familyName = [m_platformData.font() familyName];
209    if ([familyName isEqualToString:@"Times"] || [familyName isEqualToString:@"Helvetica"] || [familyName isEqualToString:@"Courier"])
210        ascent += floorf(((ascent + descent) * 0.15f) + 0.5f);
211
212    // Compute and store line spacing, before the line metrics hacks are applied.
213    m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap));
214
215    // Hack Hiragino line metrics to allow room for marked text underlines.
216    // <rdar://problem/5386183>
217    if (descent < 3 && lineGap >= 3 && [familyName hasPrefix:@"Hiragino"]) {
218        lineGap -= 3 - descent;
219        descent = 3;
220    }
221
222    if (platformData().orientation() == Vertical && !isTextOrientationFallback())
223        m_hasVerticalGlyphs = fontHasVerticalGlyphs(m_platformData.ctFont());
224
225    float xHeight;
226
227    if (platformData().orientation() == Horizontal) {
228        // Measure the actual character "x", since it's possible for it to extend below the baseline, and we need the
229        // reported x-height to only include the portion of the glyph that is above the baseline.
230        GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
231        NSGlyph xGlyph = glyphPageZero ? glyphPageZero->glyphDataForCharacter('x').glyph : 0;
232        if (xGlyph)
233            xHeight = -CGRectGetMinY(platformBoundsForGlyph(xGlyph));
234        else
235            xHeight = scaleEmToUnits(CGFontGetXHeight(m_platformData.cgFont()), unitsPerEm) * pointSize;
236    } else
237        xHeight = verticalRightOrientationFontData()->fontMetrics().xHeight();
238
239    m_fontMetrics.setUnitsPerEm(unitsPerEm);
240    m_fontMetrics.setAscent(ascent);
241    m_fontMetrics.setDescent(descent);
242    m_fontMetrics.setLineGap(lineGap);
243    m_fontMetrics.setXHeight(xHeight);
244}
245
246static CFDataRef copyFontTableForTag(FontPlatformData& platformData, FourCharCode tableName)
247{
248    return CGFontCopyTableForTag(platformData.cgFont(), tableName);
249}
250
251void SimpleFontData::platformCharWidthInit()
252{
253    m_avgCharWidth = 0;
254    m_maxCharWidth = 0;
255
256    RetainPtr<CFDataRef> os2Table = adoptCF(copyFontTableForTag(m_platformData, 'OS/2'));
257    if (os2Table && CFDataGetLength(os2Table.get()) >= 4) {
258        const UInt8* os2 = CFDataGetBytePtr(os2Table.get());
259        SInt16 os2AvgCharWidth = os2[2] * 256 + os2[3];
260        m_avgCharWidth = scaleEmToUnits(os2AvgCharWidth, m_fontMetrics.unitsPerEm()) * m_platformData.m_size;
261    }
262
263    RetainPtr<CFDataRef> headTable = adoptCF(copyFontTableForTag(m_platformData, 'head'));
264    if (headTable && CFDataGetLength(headTable.get()) >= 42) {
265        const UInt8* head = CFDataGetBytePtr(headTable.get());
266        ushort uxMin = head[36] * 256 + head[37];
267        ushort uxMax = head[40] * 256 + head[41];
268        SInt16 xMin = static_cast<SInt16>(uxMin);
269        SInt16 xMax = static_cast<SInt16>(uxMax);
270        float diff = static_cast<float>(xMax - xMin);
271        m_maxCharWidth = scaleEmToUnits(diff, m_fontMetrics.unitsPerEm()) * m_platformData.m_size;
272    }
273
274    // Fallback to a cross-platform estimate, which will populate these values if they are non-positive.
275    initCharWidths();
276}
277#endif // USE(APPKIT)
278
279void SimpleFontData::platformDestroy()
280{
281    if (!isCustomFont() && m_derivedFontData) {
282        // These come from the cache.
283        if (m_derivedFontData->smallCaps)
284            fontCache().releaseFontData(m_derivedFontData->smallCaps.get());
285
286        if (m_derivedFontData->emphasisMark)
287            fontCache().releaseFontData(m_derivedFontData->emphasisMark.get());
288    }
289}
290
291#if !PLATFORM(IOS)
292PassRefPtr<SimpleFontData> SimpleFontData::platformCreateScaledFontData(const FontDescription& fontDescription, float scaleFactor) const
293{
294    if (isCustomFont()) {
295        FontPlatformData scaledFontData(m_platformData);
296        scaledFontData.m_size = scaledFontData.m_size * scaleFactor;
297        return SimpleFontData::create(scaledFontData, true, false);
298    }
299
300    BEGIN_BLOCK_OBJC_EXCEPTIONS;
301    float size = m_platformData.size() * scaleFactor;
302    FontPlatformData scaledFontData([[NSFontManager sharedFontManager] convertFont:m_platformData.font() toSize:size], size, m_platformData.isPrinterFont(), false, false, m_platformData.orientation());
303
304    // AppKit resets the type information (screen/printer) when you convert a font to a different size.
305    // We have to fix up the font that we're handed back.
306    scaledFontData.setFont(fontDescription.usePrinterFont() ? [scaledFontData.font() printerFont] : [scaledFontData.font() screenFont]);
307
308    if (scaledFontData.font()) {
309        NSFontManager *fontManager = [NSFontManager sharedFontManager];
310        NSFontTraitMask fontTraits = [fontManager traitsOfFont:m_platformData.font()];
311
312        if (m_platformData.m_syntheticBold)
313            fontTraits |= NSBoldFontMask;
314        if (m_platformData.m_syntheticOblique)
315            fontTraits |= NSItalicFontMask;
316
317        NSFontTraitMask scaledFontTraits = [fontManager traitsOfFont:scaledFontData.font()];
318        scaledFontData.m_syntheticBold = (fontTraits & NSBoldFontMask) && !(scaledFontTraits & NSBoldFontMask);
319        scaledFontData.m_syntheticOblique = (fontTraits & NSItalicFontMask) && !(scaledFontTraits & NSItalicFontMask);
320
321        // SimpleFontData::platformDestroy() takes care of not deleting the cached font data twice.
322        return fontCache().getCachedFontData(&scaledFontData);
323    }
324    END_BLOCK_OBJC_EXCEPTIONS;
325
326    return 0;
327}
328#endif // !PLATFORM(IOS)
329
330#if !PLATFORM(IOS)
331bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
332{
333    NSString *string = [[NSString alloc] initWithCharactersNoCopy:const_cast<unichar*>(characters) length:length freeWhenDone:NO];
334    NSCharacterSet *set = [[m_platformData.font() coveredCharacterSet] invertedSet];
335    bool result = set && [string rangeOfCharacterFromSet:set].location == NSNotFound;
336    [string release];
337    return result;
338}
339
340void SimpleFontData::determinePitch()
341{
342    NSFont* f = m_platformData.font();
343    // Special case Osaka-Mono.
344    // According to <rdar://problem/3999467>, we should treat Osaka-Mono as fixed pitch.
345    // Note that the AppKit does not report Osaka-Mono as fixed pitch.
346
347    // Special case MS-PGothic.
348    // According to <rdar://problem/4032938>, we should not treat MS-PGothic as fixed pitch.
349    // Note that AppKit does report MS-PGothic as fixed pitch.
350
351    // Special case MonotypeCorsiva
352    // According to <rdar://problem/5454704>, we should not treat MonotypeCorsiva as fixed pitch.
353    // Note that AppKit does report MonotypeCorsiva as fixed pitch.
354
355    NSString *name = [f fontName];
356    m_treatAsFixedPitch = ([f isFixedPitch] || [f _isFakeFixedPitch] ||
357           [name caseInsensitiveCompare:@"Osaka-Mono"] == NSOrderedSame) &&
358           [name caseInsensitiveCompare:@"MS-PGothic"] != NSOrderedSame &&
359           [name caseInsensitiveCompare:@"MonotypeCorsiva"] != NSOrderedSame;
360}
361#endif // !PLATFORM(IOS)
362
363FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const
364{
365    FloatRect boundingBox;
366    boundingBox = CTFontGetBoundingRectsForGlyphs(m_platformData.ctFont(), platformData().orientation() == Vertical ? kCTFontVerticalOrientation : kCTFontHorizontalOrientation, &glyph, 0, 1);
367    boundingBox.setY(-boundingBox.maxY());
368    if (m_syntheticBoldOffset)
369        boundingBox.setWidth(boundingBox.width() + m_syntheticBoldOffset);
370
371    return boundingBox;
372}
373
374#if PLATFORM(MAC)
375inline CGFontRenderingStyle SimpleFontData::renderingStyle() const
376{
377    CGFontRenderingStyle style = kCGFontRenderingStyleAntialiasing | kCGFontRenderingStyleSubpixelPositioning | kCGFontRenderingStyleSubpixelQuantization;
378    NSFont *font = platformData().font();
379    if (font) {
380        switch ([font renderingMode]) {
381        case NSFontIntegerAdvancementsRenderingMode:
382            style = 0;
383            break;
384        case NSFontAntialiasedIntegerAdvancementsRenderingMode:
385            style = kCGFontRenderingStyleAntialiasing;
386            break;
387        default:
388            break;
389        }
390    }
391    return style;
392}
393
394inline bool SimpleFontData::advanceForColorBitmapFont(Glyph glyph, CGSize& advance) const
395{
396    NSFont *font = platformData().font();
397    if (!font || !platformData().isColorBitmapFont())
398        return false;
399    advance = NSSizeToCGSize([font advancementForGlyph:glyph]);
400    return true;
401}
402#endif
403
404static bool hasCustomTracking(CTFontRef font)
405{
406#if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 1090
407    UNUSED_PARAM(font);
408    return false;
409#else
410    return CTFontDescriptorIsSystemUIFont(adoptCF(CTFontCopyFontDescriptor(font)).get());
411#endif
412}
413
414static inline bool isEmoji(const FontPlatformData& platformData)
415{
416#if PLATFORM(IOS)
417    return platformData.m_isEmoji;
418#else
419    UNUSED_PARAM(platformData);
420    return false;
421#endif
422}
423
424inline bool SimpleFontData::canUseFastGlyphAdvanceGetter(Glyph glyph, CGSize& advance, bool& populatedAdvance) const
425{
426    // Fast getter doesn't take custom tracking into account
427    if (hasCustomTracking(platformData().ctFont()))
428        return false;
429    // Fast getter doesn't work for emoji
430    if (isEmoji(platformData()))
431        return false;
432    // ... or for any bitmap fonts in general
433    if (advanceForColorBitmapFont(glyph, advance)) {
434        populatedAdvance = true;
435        return false;
436    }
437    return true;
438}
439
440float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
441{
442    CGSize advance = CGSizeZero;
443    bool horizontal = platformData().orientation() == Horizontal;
444    bool populatedAdvance = false;
445    if ((horizontal || m_isBrokenIdeographFallback) && canUseFastGlyphAdvanceGetter(glyph, advance, populatedAdvance)) {
446        float pointSize = platformData().m_size;
447        CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSize);
448        if (!CGFontGetGlyphAdvancesForStyle(platformData().cgFont(), &m, renderingStyle(), &glyph, 1, &advance)) {
449            RetainPtr<CFStringRef> fullName = adoptCF(CGFontCopyFullName(platformData().cgFont()));
450            LOG_ERROR("Unable to cache glyph widths for %@ %f", fullName.get(), pointSize);
451            advance.width = 0;
452        }
453    } else if (!populatedAdvance)
454        CTFontGetAdvancesForGlyphs(m_platformData.ctFont(), horizontal ? kCTFontHorizontalOrientation : kCTFontVerticalOrientation, &glyph, &advance, 1);
455
456    return advance.width + m_syntheticBoldOffset;
457}
458
459struct ProviderInfo {
460    const UChar* characters;
461    size_t length;
462    CFDictionaryRef attributes;
463};
464
465static const UniChar* provideStringAndAttributes(CFIndex stringIndex, CFIndex* count, CFDictionaryRef* attributes, void* context)
466{
467    ProviderInfo* info = static_cast<struct ProviderInfo*>(context);
468    if (stringIndex < 0 || static_cast<size_t>(stringIndex) >= info->length)
469        return 0;
470
471    *count = info->length - stringIndex;
472    *attributes = info->attributes;
473    return info->characters + stringIndex;
474}
475
476bool SimpleFontData::canRenderCombiningCharacterSequence(const UChar* characters, size_t length) const
477{
478    ASSERT(isMainThread());
479
480    if (!m_combiningCharacterSequenceSupport)
481        m_combiningCharacterSequenceSupport = adoptPtr(new HashMap<String, bool>);
482
483    WTF::HashMap<String, bool>::AddResult addResult = m_combiningCharacterSequenceSupport->add(String(characters, length), false);
484    if (!addResult.isNewEntry)
485        return addResult.iterator->value;
486
487    RetainPtr<CGFontRef> cgFont = adoptCF(CTFontCopyGraphicsFont(platformData().ctFont(), 0));
488
489    ProviderInfo info = { characters, length, getCFStringAttributes(0, platformData().orientation()) };
490    RetainPtr<CTLineRef> line = adoptCF(wkCreateCTLineWithUniCharProvider(&provideStringAndAttributes, 0, &info));
491
492    CFArrayRef runArray = CTLineGetGlyphRuns(line.get());
493    CFIndex runCount = CFArrayGetCount(runArray);
494
495    for (CFIndex r = 0; r < runCount; r++) {
496        CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray, r));
497        ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID());
498        CFDictionaryRef runAttributes = CTRunGetAttributes(ctRun);
499        CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(runAttributes, kCTFontAttributeName));
500        RetainPtr<CGFontRef> runCGFont = adoptCF(CTFontCopyGraphicsFont(runFont, 0));
501        if (!CFEqual(runCGFont.get(), cgFont.get()))
502            return false;
503    }
504
505    addResult.iterator->value = true;
506    return true;
507}
508
509} // namespace WebCore
510