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 |