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 |