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 |