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