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