| OLD | NEW |
| (Empty) |
| 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 "platform/fonts/SimpleFontData.h" | |
| 29 | |
| 30 #import <AppKit/AppKit.h> | |
| 31 #import <ApplicationServices/ApplicationServices.h> | |
| 32 #import <float.h> | |
| 33 #import <unicode/uchar.h> | |
| 34 #import "platform/LayoutTestSupport.h" | |
| 35 #import "platform/RuntimeEnabledFeatures.h" | |
| 36 #import "platform/SharedBuffer.h" | |
| 37 #import "platform/fonts/Font.h" | |
| 38 #import "platform/fonts/FontCache.h" | |
| 39 #import "platform/fonts/FontDescription.h" | |
| 40 #import "platform/geometry/FloatRect.h" | |
| 41 #import "platform/graphics/Color.h" | |
| 42 #import "platform/mac/BlockExceptions.h" | |
| 43 #import <wtf/Assertions.h> | |
| 44 #import <wtf/RetainPtr.h> | |
| 45 #import <wtf/StdLibExtras.h> | |
| 46 | |
| 47 @interface NSFont (WebAppKitSecretAPI) | |
| 48 - (BOOL)_isFakeFixedPitch; | |
| 49 @end | |
| 50 | |
| 51 // The names of these constants were taken from history | |
| 52 // /trunk/WebKit/WebCoreSupport.subproj/WebTextRenderer.m@9311. The values | |
| 53 // were derived from the assembly of libWebKitSystemInterfaceLeopard.a. | |
| 54 enum CGFontRenderingMode { | |
| 55 kCGFontRenderingMode1BitPixelAligned = 0x0, | |
| 56 kCGFontRenderingModeAntialiasedPixelAligned = 0x1, | |
| 57 kCGFontRenderingModeAntialiased = 0xd | |
| 58 }; | |
| 59 | |
| 60 // Forward declare Mac SPIs. | |
| 61 extern "C" { | |
| 62 // Request for public API: rdar://13803586 | |
| 63 bool CGFontGetGlyphAdvancesForStyle(CGFontRef font, CGAffineTransform* transform
, CGFontRenderingMode renderingMode, ATSGlyphRef* glyph, size_t count, CGSize* a
dvance); | |
| 64 | |
| 65 // Request for public API: rdar://13803619 | |
| 66 CTLineRef CTLineCreateWithUniCharProvider(const UniChar* (*provide)(CFIndex stri
ngIndex, CFIndex* charCount, CFDictionaryRef* attributes, void* context), void (
*dispose)(const UniChar* chars, void* context), void* context); | |
| 67 } | |
| 68 | |
| 69 static CGFontRenderingMode cgFontRenderingModeForNSFont(NSFont* font) { | |
| 70 if (!font) | |
| 71 return kCGFontRenderingModeAntialiasedPixelAligned; | |
| 72 | |
| 73 switch ([font renderingMode]) { | |
| 74 case NSFontIntegerAdvancementsRenderingMode: return kCGFontRenderingMode
1BitPixelAligned; | |
| 75 case NSFontAntialiasedIntegerAdvancementsRenderingMode: return kCGFontRe
nderingModeAntialiasedPixelAligned; | |
| 76 default: return kCGFontRenderingModeAntialiased; | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 namespace blink { | |
| 81 | |
| 82 static bool fontHasVerticalGlyphs(CTFontRef ctFont) | |
| 83 { | |
| 84 // The check doesn't look neat but this is what AppKit does for vertical wri
ting... | |
| 85 RetainPtr<CFArrayRef> tableTags(AdoptCF, CTFontCopyAvailableTables(ctFont, k
CTFontTableOptionNoOptions)); | |
| 86 CFIndex numTables = CFArrayGetCount(tableTags.get()); | |
| 87 for (CFIndex index = 0; index < numTables; ++index) { | |
| 88 CTFontTableTag tag = (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(t
ableTags.get(), index); | |
| 89 if (tag == kCTFontTableVhea || tag == kCTFontTableVORG) | |
| 90 return true; | |
| 91 } | |
| 92 return false; | |
| 93 } | |
| 94 | |
| 95 static bool initFontData(SimpleFontData* fontData) | |
| 96 { | |
| 97 if (!fontData->platformData().cgFont()) | |
| 98 return false; | |
| 99 | |
| 100 return true; | |
| 101 } | |
| 102 | |
| 103 static NSString *webFallbackFontFamily(void) | |
| 104 { | |
| 105 DEFINE_STATIC_LOCAL(RetainPtr<NSString>, webFallbackFontFamily, ([[NSFont sy
stemFontOfSize:16.0f] familyName])); | |
| 106 return webFallbackFontFamily.get(); | |
| 107 } | |
| 108 | |
| 109 static bool useHinting() | |
| 110 { | |
| 111 // Enable hinting when subpixel font scaling is disabled or | |
| 112 // when running the set of standard non-subpixel layout tests, | |
| 113 // otherwise use subpixel glyph positioning. | |
| 114 return (LayoutTestSupport::isRunningLayoutTest() && !LayoutTestSupport::isFo
ntAntialiasingEnabledForTest()) || !RuntimeEnabledFeatures::subpixelFontScalingE
nabled(); | |
| 115 } | |
| 116 | |
| 117 const SimpleFontData* SimpleFontData::getCompositeFontReferenceFontData(NSFont *
key) const | |
| 118 { | |
| 119 if (key && !CFEqual(RetainPtr<CFStringRef>(AdoptCF, CTFontCopyPostScriptName
(CTFontRef(key))).get(), CFSTR("LastResort"))) { | |
| 120 if (!m_derivedFontData) | |
| 121 m_derivedFontData = DerivedFontData::create(isCustomFont()); | |
| 122 if (!m_derivedFontData->compositeFontReferences) | |
| 123 m_derivedFontData->compositeFontReferences.adoptCF(CFDictionaryCreat
eMutable(kCFAllocatorDefault, 1, &kCFTypeDictionaryKeyCallBacks, NULL)); | |
| 124 else { | |
| 125 const SimpleFontData* found = static_cast<const SimpleFontData*>(CFD
ictionaryGetValue(m_derivedFontData->compositeFontReferences.get(), static_cast<
const void *>(key))); | |
| 126 if (found) | |
| 127 return found; | |
| 128 } | |
| 129 if (CFMutableDictionaryRef dictionary = m_derivedFontData->compositeFont
References.get()) { | |
| 130 NSFont *substituteFont = [key printerFont]; | |
| 131 | |
| 132 CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(toCTFontRef(su
bstituteFont)); | |
| 133 bool syntheticBold = platformData().syntheticBold() && !(traits & kC
TFontBoldTrait); | |
| 134 bool syntheticItalic = platformData().syntheticItalic() && !(traits
& kCTFontItalicTrait); | |
| 135 | |
| 136 FontPlatformData substitutePlatform(substituteFont, platformData().s
ize(), syntheticBold, syntheticItalic, platformData().orientation(), platformDat
a().widthVariant()); | |
| 137 SimpleFontData* value = new SimpleFontData(substitutePlatform, isCus
tomFont() ? CustomFontData::create() : nullptr); | |
| 138 if (value) { | |
| 139 CFDictionaryAddValue(dictionary, key, value); | |
| 140 return value; | |
| 141 } | |
| 142 } | |
| 143 } | |
| 144 return 0; | |
| 145 } | |
| 146 | |
| 147 void SimpleFontData::platformInit() | |
| 148 { | |
| 149 m_syntheticBoldOffset = m_platformData.m_syntheticBold ? 1.0f : 0.f; | |
| 150 | |
| 151 bool failedSetup = false; | |
| 152 if (!initFontData(this)) { | |
| 153 // Ack! Something very bad happened, like a corrupt font. | |
| 154 // Try looking for an alternate 'base' font for this renderer. | |
| 155 | |
| 156 // Special case hack to use "Times New Roman" in place of "Times". | |
| 157 // "Times RO" is a common font whose family name is "Times". | |
| 158 // It overrides the normal "Times" family font. | |
| 159 // It also appears to have a corrupt regular variant. | |
| 160 NSString *fallbackFontFamily; | |
| 161 if ([[m_platformData.font() familyName] isEqual:@"Times"]) | |
| 162 fallbackFontFamily = @"Times New Roman"; | |
| 163 else | |
| 164 fallbackFontFamily = webFallbackFontFamily(); | |
| 165 | |
| 166 // Try setting up the alternate font. | |
| 167 // This is a last ditch effort to use a substitute font when something h
as gone wrong. | |
| 168 #if !ERROR_DISABLED | |
| 169 RetainPtr<NSFont> initialFont = m_platformData.font(); | |
| 170 #endif | |
| 171 if (m_platformData.font()) | |
| 172 m_platformData.setFont([[NSFontManager sharedFontManager] convertFon
t:m_platformData.font() toFamily:fallbackFontFamily]); | |
| 173 else | |
| 174 m_platformData.setFont([NSFont fontWithName:fallbackFontFamily size:
m_platformData.size()]); | |
| 175 | |
| 176 if (!initFontData(this)) { | |
| 177 if ([fallbackFontFamily isEqual:@"Times New Roman"]) { | |
| 178 // OK, couldn't setup Times New Roman as an alternate to Times,
fallback | |
| 179 // on the system font. If this fails we have no alternative lef
t. | |
| 180 m_platformData.setFont([[NSFontManager sharedFontManager] conver
tFont:m_platformData.font() toFamily:webFallbackFontFamily()]); | |
| 181 if (!initFontData(this)) { | |
| 182 // We tried, Times, Times New Roman, and the system font. No
joy. We have to give up. | |
| 183 WTF_LOG_ERROR("unable to initialize with font %@", initialFo
nt.get()); | |
| 184 failedSetup = true; | |
| 185 } | |
| 186 } else { | |
| 187 // We tried the requested font and the system font. No joy. We h
ave to give up. | |
| 188 WTF_LOG_ERROR("unable to initialize with font %@", initialFont.g
et()); | |
| 189 failedSetup = true; | |
| 190 } | |
| 191 } | |
| 192 | |
| 193 // Report the problem. | |
| 194 WTF_LOG_ERROR("Corrupt font detected, using %@ in place of %@.", | |
| 195 [m_platformData.font() familyName], [initialFont.get() familyName]); | |
| 196 } | |
| 197 | |
| 198 // If all else fails, try to set up using the system font. | |
| 199 // This is probably because Times and Times New Roman are both unavailable. | |
| 200 if (failedSetup) { | |
| 201 m_platformData.setFont([NSFont systemFontOfSize:[m_platformData.font() p
ointSize]]); | |
| 202 WTF_LOG_ERROR("failed to set up font, using system font %s", m_platformD
ata.font()); | |
| 203 initFontData(this); | |
| 204 } | |
| 205 | |
| 206 int iAscent; | |
| 207 int iDescent; | |
| 208 int iLineGap; | |
| 209 unsigned unitsPerEm; | |
| 210 | |
| 211 iAscent = CGFontGetAscent(m_platformData.cgFont()); | |
| 212 // Some fonts erroneously specify a positive descender value. We follow Core
Text in assuming that | |
| 213 // such fonts meant the same distance, but in the reverse direction. | |
| 214 iDescent = -abs(CGFontGetDescent(m_platformData.cgFont())); | |
| 215 iLineGap = CGFontGetLeading(m_platformData.cgFont()); | |
| 216 unitsPerEm = CGFontGetUnitsPerEm(m_platformData.cgFont()); | |
| 217 | |
| 218 float pointSize = m_platformData.m_textSize; | |
| 219 float ascent = scaleEmToUnits(iAscent, unitsPerEm) * pointSize; | |
| 220 float descent = -scaleEmToUnits(iDescent, unitsPerEm) * pointSize; | |
| 221 float lineGap = scaleEmToUnits(iLineGap, unitsPerEm) * pointSize; | |
| 222 float underlineThickness = CTFontGetUnderlineThickness(m_platformData.ctFont
()); | |
| 223 float underlinePosition = CTFontGetUnderlinePosition(m_platformData.ctFont()
); | |
| 224 | |
| 225 // We need to adjust Times, Helvetica, and Courier to closely match the | |
| 226 // vertical metrics of their Microsoft counterparts that are the de facto | |
| 227 // web standard. The AppKit adjustment of 20% is too big and is | |
| 228 // incorrectly added to line spacing, so we use a 15% adjustment instead | |
| 229 // and add it to the ascent. | |
| 230 NSString *familyName = [m_platformData.font() familyName]; | |
| 231 if ([familyName isEqualToString:@"Times"] || [familyName isEqualToString:@"H
elvetica"] || [familyName isEqualToString:@"Courier"]) | |
| 232 ascent += floorf(((ascent + descent) * 0.15f) + 0.5f); | |
| 233 | |
| 234 // Compute and store line spacing, before the line metrics hacks are applied
. | |
| 235 m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(li
neGap)); | |
| 236 | |
| 237 // Hack Hiragino line metrics to allow room for marked text underlines. | |
| 238 // <rdar://problem/5386183> | |
| 239 if (descent < 3 && lineGap >= 3 && [familyName hasPrefix:@"Hiragino"]) { | |
| 240 lineGap -= 3 - descent; | |
| 241 descent = 3; | |
| 242 } | |
| 243 | |
| 244 if (platformData().orientation() == Vertical && !isTextOrientationFallback()
) | |
| 245 m_hasVerticalGlyphs = fontHasVerticalGlyphs(m_platformData.ctFont()); | |
| 246 | |
| 247 float xHeight; | |
| 248 | |
| 249 if (platformData().orientation() == Horizontal) { | |
| 250 // Measure the actual character "x", since it's possible for it to exten
d below the baseline, and we need the | |
| 251 // reported x-height to only include the portion of the glyph that is ab
ove the baseline. | |
| 252 GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->pag
e(); | |
| 253 NSGlyph xGlyph = glyphPageZero ? glyphPageZero->glyphForCharacter('x') :
0; | |
| 254 if (xGlyph) | |
| 255 xHeight = -CGRectGetMinY(platformBoundsForGlyph(xGlyph)); | |
| 256 else | |
| 257 xHeight = scaleEmToUnits(CGFontGetXHeight(m_platformData.cgFont()),
unitsPerEm) * pointSize; | |
| 258 } else | |
| 259 xHeight = verticalRightOrientationFontData()->fontMetrics().xHeight(); | |
| 260 | |
| 261 m_fontMetrics.setUnitsPerEm(unitsPerEm); | |
| 262 m_fontMetrics.setAscent(ascent); | |
| 263 m_fontMetrics.setDescent(descent); | |
| 264 m_fontMetrics.setLineGap(lineGap); | |
| 265 m_fontMetrics.setXHeight(xHeight); | |
| 266 m_fontMetrics.setUnderlineThickness(underlineThickness); | |
| 267 m_fontMetrics.setUnderlinePosition(underlinePosition); | |
| 268 } | |
| 269 | |
| 270 static CFDataRef copyFontTableForTag(FontPlatformData& platformData, FourCharCod
e tableName) | |
| 271 { | |
| 272 return CGFontCopyTableForTag(platformData.cgFont(), tableName); | |
| 273 } | |
| 274 | |
| 275 void SimpleFontData::platformCharWidthInit() | |
| 276 { | |
| 277 m_avgCharWidth = 0; | |
| 278 m_maxCharWidth = 0; | |
| 279 | |
| 280 RetainPtr<CFDataRef> os2Table(AdoptCF, copyFontTableForTag(m_platformData, '
OS/2')); | |
| 281 if (os2Table && CFDataGetLength(os2Table.get()) >= 4) { | |
| 282 const UInt8* os2 = CFDataGetBytePtr(os2Table.get()); | |
| 283 SInt16 os2AvgCharWidth = os2[2] * 256 + os2[3]; | |
| 284 m_avgCharWidth = scaleEmToUnits(os2AvgCharWidth, m_fontMetrics.unitsPerE
m()) * m_platformData.m_textSize; | |
| 285 } | |
| 286 | |
| 287 RetainPtr<CFDataRef> headTable(AdoptCF, copyFontTableForTag(m_platformData,
'head')); | |
| 288 if (headTable && CFDataGetLength(headTable.get()) >= 42) { | |
| 289 const UInt8* head = CFDataGetBytePtr(headTable.get()); | |
| 290 ushort uxMin = head[36] * 256 + head[37]; | |
| 291 ushort uxMax = head[40] * 256 + head[41]; | |
| 292 SInt16 xMin = static_cast<SInt16>(uxMin); | |
| 293 SInt16 xMax = static_cast<SInt16>(uxMax); | |
| 294 float diff = static_cast<float>(xMax - xMin); | |
| 295 m_maxCharWidth = scaleEmToUnits(diff, m_fontMetrics.unitsPerEm()) * m_pl
atformData.m_textSize; | |
| 296 } | |
| 297 | |
| 298 // Fallback to a cross-platform estimate, which will populate these values i
f they are non-positive. | |
| 299 initCharWidths(); | |
| 300 } | |
| 301 | |
| 302 void SimpleFontData::platformDestroy() | |
| 303 { | |
| 304 if (!isCustomFont() && m_derivedFontData) { | |
| 305 // These come from the cache. | |
| 306 if (m_derivedFontData->smallCaps) | |
| 307 FontCache::fontCache()->releaseFontData(m_derivedFontData->smallCaps
.get()); | |
| 308 | |
| 309 if (m_derivedFontData->emphasisMark) | |
| 310 FontCache::fontCache()->releaseFontData(m_derivedFontData->emphasisM
ark.get()); | |
| 311 } | |
| 312 } | |
| 313 | |
| 314 PassRefPtr<SimpleFontData> SimpleFontData::platformCreateScaledFontData(const Fo
ntDescription& fontDescription, float scaleFactor) const | |
| 315 { | |
| 316 if (isCustomFont()) { | |
| 317 FontPlatformData scaledFontData(m_platformData); | |
| 318 scaledFontData.m_textSize = scaledFontData.m_textSize * scaleFactor; | |
| 319 return SimpleFontData::create(scaledFontData, CustomFontData::create()); | |
| 320 } | |
| 321 | |
| 322 BEGIN_BLOCK_OBJC_EXCEPTIONS; | |
| 323 float size = m_platformData.size() * scaleFactor; | |
| 324 FontPlatformData scaledFontData([[NSFontManager sharedFontManager] convertFo
nt:m_platformData.font() toSize:size], size, false, false, m_platformData.orient
ation()); | |
| 325 | |
| 326 // AppKit forgets about hinting property when scaling, so we have to remind
it. | |
| 327 scaledFontData.setFont(useHinting() ? [scaledFontData.font() screenFont] : [
scaledFontData.font() printerFont]); | |
| 328 | |
| 329 if (scaledFontData.font()) { | |
| 330 NSFontManager *fontManager = [NSFontManager sharedFontManager]; | |
| 331 NSFontTraitMask fontTraits = [fontManager traitsOfFont:m_platformData.fo
nt()]; | |
| 332 | |
| 333 if (m_platformData.m_syntheticBold) | |
| 334 fontTraits |= NSBoldFontMask; | |
| 335 if (m_platformData.m_syntheticItalic) | |
| 336 fontTraits |= NSItalicFontMask; | |
| 337 | |
| 338 NSFontTraitMask scaledFontTraits = [fontManager traitsOfFont:scaledFontD
ata.font()]; | |
| 339 scaledFontData.m_syntheticBold = (fontTraits & NSBoldFontMask) && !(scal
edFontTraits & NSBoldFontMask); | |
| 340 scaledFontData.m_syntheticItalic = (fontTraits & NSItalicFontMask) && !(
scaledFontTraits & NSItalicFontMask); | |
| 341 | |
| 342 // SimpleFontData::platformDestroy() takes care of not deleting the cach
ed font data twice. | |
| 343 return FontCache::fontCache()->fontDataFromFontPlatformData(&scaledFontD
ata); | |
| 344 } | |
| 345 END_BLOCK_OBJC_EXCEPTIONS; | |
| 346 | |
| 347 return nullptr; | |
| 348 } | |
| 349 | |
| 350 void SimpleFontData::determinePitch() | |
| 351 { | |
| 352 NSFont* f = m_platformData.font(); | |
| 353 // Special case Osaka-Mono. | |
| 354 // According to <rdar://problem/3999467>, we should treat Osaka-Mono as fixe
d pitch. | |
| 355 // Note that the AppKit does not report Osaka-Mono as fixed pitch. | |
| 356 | |
| 357 // Special case MS-PGothic. | |
| 358 // According to <rdar://problem/4032938>, we should not treat MS-PGothic as
fixed pitch. | |
| 359 // Note that AppKit does report MS-PGothic as fixed pitch. | |
| 360 | |
| 361 // Special case MonotypeCorsiva | |
| 362 // According to <rdar://problem/5454704>, we should not treat MonotypeCorsiv
a as fixed pitch. | |
| 363 // Note that AppKit does report MonotypeCorsiva as fixed pitch. | |
| 364 | |
| 365 NSString *name = [f fontName]; | |
| 366 m_treatAsFixedPitch = ([f isFixedPitch] || [f _isFakeFixedPitch] || | |
| 367 [name caseInsensitiveCompare:@"Osaka-Mono"] == NSOrderedSame) && | |
| 368 [name caseInsensitiveCompare:@"MS-PGothic"] != NSOrderedSame && | |
| 369 [name caseInsensitiveCompare:@"MonotypeCorsiva"] != NSOrderedSame; | |
| 370 } | |
| 371 | |
| 372 FloatRect SimpleFontData::platformBoundsForGlyph(Glyph glyph) const | |
| 373 { | |
| 374 FloatRect boundingBox; | |
| 375 boundingBox = CTFontGetBoundingRectsForGlyphs(m_platformData.ctFont(), platf
ormData().orientation() == Vertical ? kCTFontVerticalOrientation : kCTFontHorizo
ntalOrientation, &glyph, 0, 1); | |
| 376 boundingBox.setY(-boundingBox.maxY()); | |
| 377 if (m_syntheticBoldOffset) | |
| 378 boundingBox.setWidth(boundingBox.width() + m_syntheticBoldOffset); | |
| 379 | |
| 380 return boundingBox; | |
| 381 } | |
| 382 | |
| 383 float SimpleFontData::platformWidthForGlyph(Glyph glyph) const | |
| 384 { | |
| 385 CGSize advance = CGSizeZero; | |
| 386 if (platformData().orientation() == Horizontal || m_isBrokenIdeographFallbac
k) { | |
| 387 NSFont *font = platformData().font(); | |
| 388 if (font && platformData().isColorBitmapFont()) | |
| 389 advance = NSSizeToCGSize([font advancementForGlyph:glyph]); | |
| 390 else { | |
| 391 float pointSize = platformData().m_textSize; | |
| 392 CGAffineTransform m = CGAffineTransformMakeScale(pointSize, pointSiz
e); | |
| 393 if (!CGFontGetGlyphAdvancesForStyle(platformData().cgFont(), &m, cgF
ontRenderingModeForNSFont(font), &glyph, 1, &advance)) { | |
| 394 WTF_LOG_ERROR("Unable to cache glyph widths for %@ %f", [font di
splayName], pointSize); | |
| 395 advance.width = 0; | |
| 396 } | |
| 397 } | |
| 398 } else | |
| 399 CTFontGetAdvancesForGlyphs(m_platformData.ctFont(), kCTFontVerticalOrien
tation, &glyph, &advance, 1); | |
| 400 | |
| 401 return advance.width + m_syntheticBoldOffset; | |
| 402 } | |
| 403 | |
| 404 struct ProviderInfo { | |
| 405 const UChar* characters; | |
| 406 size_t length; | |
| 407 CFDictionaryRef attributes; | |
| 408 }; | |
| 409 | |
| 410 static const UniChar* provideStringAndAttributes(CFIndex stringIndex, CFIndex* c
ount, CFDictionaryRef* attributes, void* context) | |
| 411 { | |
| 412 ProviderInfo* info = static_cast<struct ProviderInfo*>(context); | |
| 413 if (stringIndex < 0 || static_cast<size_t>(stringIndex) >= info->length) | |
| 414 return 0; | |
| 415 | |
| 416 *count = info->length - stringIndex; | |
| 417 *attributes = info->attributes; | |
| 418 return info->characters + stringIndex; | |
| 419 } | |
| 420 | |
| 421 bool SimpleFontData::canRenderCombiningCharacterSequence(const UChar* characters
, size_t length) const | |
| 422 { | |
| 423 ASSERT(isMainThread()); | |
| 424 | |
| 425 if (!m_combiningCharacterSequenceSupport) | |
| 426 m_combiningCharacterSequenceSupport = adoptPtr(new HashMap<String, bool>
); | |
| 427 | |
| 428 WTF::HashMap<String, bool>::AddResult addResult = m_combiningCharacterSequen
ceSupport->add(String(characters, length), false); | |
| 429 if (!addResult.isNewEntry) | |
| 430 return addResult.storedValue->value; | |
| 431 | |
| 432 RetainPtr<CGFontRef> cgFont(AdoptCF, CTFontCopyGraphicsFont(platformData().c
tFont(), 0)); | |
| 433 | |
| 434 ProviderInfo info = { characters, length, getCFStringAttributes(0, platformD
ata().orientation()) }; | |
| 435 RetainPtr<CTLineRef> line(AdoptCF, CTLineCreateWithUniCharProvider(&provideS
tringAndAttributes, 0, &info)); | |
| 436 | |
| 437 CFArrayRef runArray = CTLineGetGlyphRuns(line.get()); | |
| 438 CFIndex runCount = CFArrayGetCount(runArray); | |
| 439 | |
| 440 for (CFIndex r = 0; r < runCount; r++) { | |
| 441 CTRunRef ctRun = static_cast<CTRunRef>(CFArrayGetValueAtIndex(runArray,
r)); | |
| 442 ASSERT(CFGetTypeID(ctRun) == CTRunGetTypeID()); | |
| 443 CFDictionaryRef runAttributes = CTRunGetAttributes(ctRun); | |
| 444 CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(runAttri
butes, kCTFontAttributeName)); | |
| 445 RetainPtr<CGFontRef> runCGFont(AdoptCF, CTFontCopyGraphicsFont(runFont,
0)); | |
| 446 if (!CFEqual(runCGFont.get(), cgFont.get())) | |
| 447 return false; | |
| 448 } | |
| 449 | |
| 450 addResult.storedValue->value = true; | |
| 451 return true; | |
| 452 } | |
| 453 | |
| 454 } // namespace blink | |
| OLD | NEW |