OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | |
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | |
4 * (C) 2000 Dirk Mueller (mueller@kde.org) | |
5 * Copyright (C) 2003, 2006, 2010, 2011 Apple Inc. All rights reserved. | |
6 * | |
7 * This library is free software; you can redistribute it and/or | |
8 * modify it under the terms of the GNU Library General Public | |
9 * License as published by the Free Software Foundation; either | |
10 * version 2 of the License, or (at your option) any later version. | |
11 * | |
12 * This library is distributed in the hope that it will be useful, | |
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Library General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Library General Public License | |
18 * along with this library; see the file COPYING.LIB. If not, write to | |
19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
20 * Boston, MA 02110-1301, USA. | |
21 * | |
22 */ | |
23 | |
24 #include "config.h" | |
25 #include "core/platform/graphics/Font.h" | |
26 | |
27 #include "core/platform/graphics/WidthIterator.h" | |
28 #include "platform/geometry/FloatRect.h" | |
29 #include "platform/graphics/TextRun.h" | |
30 #include "wtf/MainThread.h" | |
31 #include "wtf/StdLibExtras.h" | |
32 #include "wtf/UnusedParam.h" | |
33 #include "wtf/text/StringBuilder.h" | |
34 | |
35 using namespace WTF; | |
36 using namespace Unicode; | |
37 | |
38 namespace WTF { | |
39 | |
40 // allow compilation of OwnPtr<TextLayout> in source files that don't have acces
s to the TextLayout class definition | |
41 void OwnedPtrDeleter<WebCore::TextLayout>::deletePtr(WebCore::TextLayout* ptr) | |
42 { | |
43 WebCore::Font::deleteLayout(ptr); | |
44 } | |
45 | |
46 } | |
47 | |
48 namespace WebCore { | |
49 | |
50 const uint8_t Font::s_roundingHackCharacterTable[256] = { | |
51 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*\t*/, 1 /*\n*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
52 1 /*space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*-*/, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 /*?*/, | |
53 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, 0, 0, 0, | |
54 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, 0, 0, 0, | |
55 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, 0, 0, 0, | |
56 1 /*no-break space*/, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
57 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, 0, 0, 0, | |
58 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
, 0, 0, 0, 0, 0, 0 | |
59 }; | |
60 | |
61 static const UChar32 cjkIsolatedSymbolsArray[] = { | |
62 // 0x2C7 Caron, Mandarin Chinese 3rd Tone | |
63 0x2C7, | |
64 // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone | |
65 0x2CA, | |
66 // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone | |
67 0x2CB, | |
68 // 0x2D9 Dot Above, Mandarin Chinese 5th Tone | |
69 0x2D9, | |
70 0x2020, 0x2021, 0x2030, 0x203B, 0x203C, 0x2042, 0x2047, 0x2048, 0x2049, 0x20
51, | |
71 0x20DD, 0x20DE, 0x2100, 0x2103, 0x2105, 0x2109, 0x210A, 0x2113, 0x2116, 0x21
21, | |
72 0x212B, 0x213B, 0x2150, 0x2151, 0x2152, 0x217F, 0x2189, 0x2307, 0x2312, 0x23
CE, | |
73 0x2423, 0x25A0, 0x25A1, 0x25A2, 0x25AA, 0x25AB, 0x25B1, 0x25B2, 0x25B3, 0x25
B6, | |
74 0x25B7, 0x25BC, 0x25BD, 0x25C0, 0x25C1, 0x25C6, 0x25C7, 0x25C9, 0x25CB, 0x25
CC, | |
75 0x25EF, 0x2605, 0x2606, 0x260E, 0x2616, 0x2617, 0x2640, 0x2642, 0x26A0, 0x26
BD, | |
76 0x26BE, 0x2713, 0x271A, 0x273F, 0x2740, 0x2756, 0x2B1A, 0xFE10, 0xFE11, 0xFE
12, | |
77 0xFE19, 0xFF1D, | |
78 // Emoji. | |
79 0x1F100 | |
80 }; | |
81 | |
82 Font::CodePath Font::s_codePath = Auto; | |
83 | |
84 TypesettingFeatures Font::s_defaultTypesettingFeatures = 0; | |
85 | |
86 // =============================================================================
=============== | |
87 // Font Implementation (Cross-Platform Portion) | |
88 // =============================================================================
=============== | |
89 | |
90 Font::Font() | |
91 : m_letterSpacing(0) | |
92 , m_wordSpacing(0) | |
93 , m_isPlatformFont(false) | |
94 , m_typesettingFeatures(0) | |
95 { | |
96 } | |
97 | |
98 Font::Font(const FontDescription& fd, float letterSpacing, float wordSpacing) | |
99 : m_fontDescription(fd) | |
100 , m_letterSpacing(letterSpacing) | |
101 , m_wordSpacing(wordSpacing) | |
102 , m_isPlatformFont(false) | |
103 , m_typesettingFeatures(computeTypesettingFeatures()) | |
104 { | |
105 } | |
106 | |
107 Font::Font(const FontPlatformData& fontData, bool isPrinterFont, FontSmoothingMo
de fontSmoothingMode) | |
108 : m_fontFallbackList(FontFallbackList::create()) | |
109 , m_letterSpacing(0) | |
110 , m_wordSpacing(0) | |
111 , m_isPlatformFont(true) | |
112 , m_typesettingFeatures(computeTypesettingFeatures()) | |
113 { | |
114 m_fontDescription.setUsePrinterFont(isPrinterFont); | |
115 m_fontDescription.setFontSmoothing(fontSmoothingMode); | |
116 m_fontFallbackList->setPlatformFont(fontData); | |
117 } | |
118 | |
119 Font::Font(const Font& other) | |
120 : m_fontDescription(other.m_fontDescription) | |
121 , m_fontFallbackList(other.m_fontFallbackList) | |
122 , m_letterSpacing(other.m_letterSpacing) | |
123 , m_wordSpacing(other.m_wordSpacing) | |
124 , m_isPlatformFont(other.m_isPlatformFont) | |
125 , m_typesettingFeatures(computeTypesettingFeatures()) | |
126 { | |
127 } | |
128 | |
129 Font& Font::operator=(const Font& other) | |
130 { | |
131 m_fontDescription = other.m_fontDescription; | |
132 m_fontFallbackList = other.m_fontFallbackList; | |
133 m_letterSpacing = other.m_letterSpacing; | |
134 m_wordSpacing = other.m_wordSpacing; | |
135 m_isPlatformFont = other.m_isPlatformFont; | |
136 m_typesettingFeatures = other.m_typesettingFeatures; | |
137 return *this; | |
138 } | |
139 | |
140 bool Font::operator==(const Font& other) const | |
141 { | |
142 // Our FontData don't have to be checked, since checking the font descriptio
n will be fine. | |
143 // FIXME: This does not work if the font was made with the FontPlatformData
constructor. | |
144 if (loadingCustomFonts() || other.loadingCustomFonts()) | |
145 return false; | |
146 | |
147 FontSelector* first = m_fontFallbackList ? m_fontFallbackList->fontSelector(
) : 0; | |
148 FontSelector* second = other.m_fontFallbackList ? other.m_fontFallbackList->
fontSelector() : 0; | |
149 | |
150 return first == second | |
151 && m_fontDescription == other.m_fontDescription | |
152 && m_letterSpacing == other.m_letterSpacing | |
153 && m_wordSpacing == other.m_wordSpacing | |
154 && (m_fontFallbackList ? m_fontFallbackList->fontSelectorVersion() : 0)
== (other.m_fontFallbackList ? other.m_fontFallbackList->fontSelectorVersion() :
0) | |
155 && (m_fontFallbackList ? m_fontFallbackList->generation() : 0) == (other
.m_fontFallbackList ? other.m_fontFallbackList->generation() : 0); | |
156 } | |
157 | |
158 void Font::update(PassRefPtr<FontSelector> fontSelector) const | |
159 { | |
160 // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr,
but it ends up | |
161 // being reasonably safe (because inherited fonts in the render tree pick up
the new | |
162 // style anyway. Other copies are transient, e.g., the state in the Graphics
Context, and | |
163 // won't stick around long enough to get you in trouble). Still, this is pre
tty disgusting, | |
164 // and could eventually be rectified by using RefPtrs for Fonts themselves. | |
165 if (!m_fontFallbackList) | |
166 m_fontFallbackList = FontFallbackList::create(); | |
167 m_fontFallbackList->invalidate(fontSelector); | |
168 m_typesettingFeatures = computeTypesettingFeatures(); | |
169 } | |
170 | |
171 void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, c
onst FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction) const | |
172 { | |
173 // Don't draw anything while we are using custom fonts that are in the proce
ss of loading, | |
174 // except if the 'force' argument is set to true (in which case it will use
a fallback | |
175 // font). | |
176 if (loadingCustomFonts() && customFontNotReadyAction == DoNotPaintIfFontNotR
eady) | |
177 return; | |
178 | |
179 CodePath codePathToUse = codePath(runInfo.run); | |
180 // FIXME: Use the fast code path once it handles partial runs with kerning a
nd ligatures. See http://webkit.org/b/100050 | |
181 if (codePathToUse != Complex && typesettingFeatures() && (runInfo.from || ru
nInfo.to != runInfo.run.length())) | |
182 codePathToUse = Complex; | |
183 | |
184 if (codePathToUse != Complex) | |
185 return drawSimpleText(context, runInfo, point); | |
186 | |
187 return drawComplexText(context, runInfo, point); | |
188 } | |
189 | |
190 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& r
unInfo, const AtomicString& mark, const FloatPoint& point) const | |
191 { | |
192 if (loadingCustomFonts()) | |
193 return; | |
194 | |
195 CodePath codePathToUse = codePath(runInfo.run); | |
196 // FIXME: Use the fast code path once it handles partial runs with kerning a
nd ligatures. See http://webkit.org/b/100050 | |
197 if (codePathToUse != Complex && typesettingFeatures() && (runInfo.from || ru
nInfo.to != runInfo.run.length())) | |
198 codePathToUse = Complex; | |
199 | |
200 if (codePathToUse != Complex) | |
201 drawEmphasisMarksForSimpleText(context, runInfo, mark, point); | |
202 else | |
203 drawEmphasisMarksForComplexText(context, runInfo, mark, point); | |
204 } | |
205 | |
206 float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFo
nts, GlyphOverflow* glyphOverflow) const | |
207 { | |
208 CodePath codePathToUse = codePath(run); | |
209 if (codePathToUse != Complex) { | |
210 // The complex path is more restrictive about returning fallback fonts t
han the simple path, so we need an explicit test to make their behaviors match. | |
211 if (!canReturnFallbackFontsForComplexText()) | |
212 fallbackFonts = 0; | |
213 // The simple path can optimize the case where glyph overflow is not obs
ervable. | |
214 if (codePathToUse != SimpleWithGlyphOverflow && (glyphOverflow && !glyph
Overflow->computeBounds)) | |
215 glyphOverflow = 0; | |
216 } | |
217 | |
218 bool hasKerningOrLigatures = typesettingFeatures() & (Kerning | Ligatures); | |
219 bool hasWordSpacingOrLetterSpacing = wordSpacing() || letterSpacing(); | |
220 float* cacheEntry = m_fontFallbackList->widthCache().add(run, std::numeric_l
imits<float>::quiet_NaN(), hasKerningOrLigatures, hasWordSpacingOrLetterSpacing,
glyphOverflow); | |
221 if (cacheEntry && !std::isnan(*cacheEntry)) | |
222 return *cacheEntry; | |
223 | |
224 float result; | |
225 if (codePathToUse == Complex) | |
226 result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow); | |
227 else | |
228 result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow); | |
229 | |
230 if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty())) | |
231 *cacheEntry = result; | |
232 return result; | |
233 } | |
234 | |
235 float Font::width(const TextRun& run, int& charsConsumed, String& glyphName) con
st | |
236 { | |
237 #if ENABLE(SVG_FONTS) | |
238 if (TextRun::RenderingContext* renderingContext = run.renderingContext()) | |
239 return renderingContext->floatWidthUsingSVGFont(*this, run, charsConsume
d, glyphName); | |
240 #endif | |
241 | |
242 charsConsumed = run.length(); | |
243 glyphName = ""; | |
244 return width(run); | |
245 } | |
246 | |
247 #if !OS(MACOSX) | |
248 | |
249 PassOwnPtr<TextLayout> Font::createLayoutForMacComplexText(const TextRun&, unsig
ned, float, bool) const | |
250 { | |
251 ASSERT_NOT_REACHED(); | |
252 return nullptr; | |
253 } | |
254 | |
255 void Font::deleteLayout(TextLayout*) | |
256 { | |
257 } | |
258 | |
259 float Font::width(TextLayout&, unsigned, unsigned, HashSet<const SimpleFontData*
>*) | |
260 { | |
261 ASSERT_NOT_REACHED(); | |
262 return 0; | |
263 } | |
264 | |
265 #endif | |
266 | |
267 FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point
, int h, int from, int to) const | |
268 { | |
269 to = (to == -1 ? run.length() : to); | |
270 | |
271 CodePath codePathToUse = codePath(run); | |
272 // FIXME: Use the fast code path once it handles partial runs with kerning a
nd ligatures. See http://webkit.org/b/100050 | |
273 if (codePathToUse != Complex && typesettingFeatures() && (from || to != run.
length())) | |
274 codePathToUse = Complex; | |
275 | |
276 if (codePathToUse != Complex) | |
277 return selectionRectForSimpleText(run, point, h, from, to); | |
278 | |
279 return selectionRectForComplexText(run, point, h, from, to); | |
280 } | |
281 | |
282 int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyp
hs) const | |
283 { | |
284 // FIXME: Use the fast code path once it handles partial runs with kerning a
nd ligatures. See http://webkit.org/b/100050 | |
285 if (codePath(run) != Complex && !typesettingFeatures()) | |
286 return offsetForPositionForSimpleText(run, x, includePartialGlyphs); | |
287 | |
288 return offsetForPositionForComplexText(run, x, includePartialGlyphs); | |
289 } | |
290 | |
291 template <typename CharacterType> | |
292 static inline String normalizeSpacesInternal(const CharacterType* characters, un
signed length) | |
293 { | |
294 StringBuilder normalized; | |
295 normalized.reserveCapacity(length); | |
296 | |
297 for (unsigned i = 0; i < length; ++i) | |
298 normalized.append(Font::normalizeSpaces(characters[i])); | |
299 | |
300 return normalized.toString(); | |
301 } | |
302 | |
303 String Font::normalizeSpaces(const LChar* characters, unsigned length) | |
304 { | |
305 return normalizeSpacesInternal(characters, length); | |
306 } | |
307 | |
308 String Font::normalizeSpaces(const UChar* characters, unsigned length) | |
309 { | |
310 return normalizeSpacesInternal(characters, length); | |
311 } | |
312 | |
313 static bool shouldUseFontSmoothing = true; | |
314 | |
315 void Font::setShouldUseSmoothing(bool shouldUseSmoothing) | |
316 { | |
317 ASSERT(isMainThread()); | |
318 shouldUseFontSmoothing = shouldUseSmoothing; | |
319 } | |
320 | |
321 bool Font::shouldUseSmoothing() | |
322 { | |
323 return shouldUseFontSmoothing; | |
324 } | |
325 | |
326 void Font::setCodePath(CodePath p) | |
327 { | |
328 s_codePath = p; | |
329 } | |
330 | |
331 Font::CodePath Font::codePath() | |
332 { | |
333 return s_codePath; | |
334 } | |
335 | |
336 void Font::setDefaultTypesettingFeatures(TypesettingFeatures typesettingFeatures
) | |
337 { | |
338 s_defaultTypesettingFeatures = typesettingFeatures; | |
339 } | |
340 | |
341 TypesettingFeatures Font::defaultTypesettingFeatures() | |
342 { | |
343 return s_defaultTypesettingFeatures; | |
344 } | |
345 | |
346 Font::CodePath Font::codePath(const TextRun& run) const | |
347 { | |
348 if (s_codePath != Auto) | |
349 return s_codePath; | |
350 | |
351 #if ENABLE(SVG_FONTS) | |
352 if (run.renderingContext()) | |
353 return Simple; | |
354 #endif | |
355 | |
356 if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings
()->size() > 0) | |
357 return Complex; | |
358 | |
359 if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this)) | |
360 return Complex; | |
361 | |
362 if (!run.characterScanForCodePath()) | |
363 return Simple; | |
364 | |
365 if (run.is8Bit()) | |
366 return Simple; | |
367 | |
368 // Start from 0 since drawing and highlighting also measure the characters b
efore run->from. | |
369 return characterRangeCodePath(run.characters16(), run.length()); | |
370 } | |
371 | |
372 static inline UChar keyExtractorUChar(const UChar* value) | |
373 { | |
374 return *value; | |
375 } | |
376 | |
377 static inline UChar32 keyExtractorUChar32(const UChar32* value) | |
378 { | |
379 return *value; | |
380 } | |
381 | |
382 Font::CodePath Font::characterRangeCodePath(const UChar* characters, unsigned le
n) | |
383 { | |
384 static const UChar complexCodePathRanges[] = { | |
385 // U+02E5 through U+02E9 (Modifier Letters : Tone letters) | |
386 0x2E5, 0x2E9, | |
387 // U+0300 through U+036F Combining diacritical marks | |
388 0x300, 0x36F, | |
389 // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, ... | |
390 0x0591, 0x05BD, | |
391 // ... Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha | |
392 0x05BF, 0x05CF, | |
393 // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic
, | |
394 // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannad
a, | |
395 // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar | |
396 0x0600, 0x109F, | |
397 // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left | |
398 // here if you precompose; Modern Korean will be precomposed as a result
of step A) | |
399 0x1100, 0x11FF, | |
400 // U+135D through U+135F Ethiopic combining marks | |
401 0x135D, 0x135F, | |
402 // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongol
ian | |
403 0x1700, 0x18AF, | |
404 // U+1900 through U+194F Limbu (Unicode 4.0) | |
405 0x1900, 0x194F, | |
406 // U+1980 through U+19DF New Tai Lue | |
407 0x1980, 0x19DF, | |
408 // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Ve
dic | |
409 0x1A00, 0x1CFF, | |
410 // U+1DC0 through U+1DFF Comining diacritical mark supplement | |
411 0x1DC0, 0x1DFF, | |
412 // U+20D0 through U+20FF Combining marks for symbols | |
413 0x20D0, 0x20FF, | |
414 // U+2CEF through U+2CF1 Combining marks for Coptic | |
415 0x2CEF, 0x2CF1, | |
416 // U+302A through U+302F Ideographic and Hangul Tone marks | |
417 0x302A, 0x302F, | |
418 // U+A67C through U+A67D Combining marks for old Cyrillic | |
419 0xA67C, 0xA67D, | |
420 // U+A6F0 through U+A6F1 Combining mark for Bamum | |
421 0xA6F0, 0xA6F1, | |
422 // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extende
d, | |
423 // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Ma
yek | |
424 0xA800, 0xABFF, | |
425 // U+D7B0 through U+D7FF Hangul Jamo Ext. B | |
426 0xD7B0, 0xD7FF, | |
427 // U+FE00 through U+FE0F Unicode variation selectors | |
428 0xFE00, 0xFE0F, | |
429 // U+FE20 through U+FE2F Combining half marks | |
430 0xFE20, 0xFE2F | |
431 }; | |
432 static size_t complexCodePathRangesCount = WTF_ARRAY_LENGTH(complexCodePathR
anges); | |
433 | |
434 CodePath result = Simple; | |
435 for (unsigned i = 0; i < len; i++) { | |
436 const UChar c = characters[i]; | |
437 | |
438 // Shortcut for common case | |
439 if (c < 0x2E5) | |
440 continue; | |
441 | |
442 // U+1E00 through U+2000 characters with diacritics and stacked diacriti
cs | |
443 if (c >= 0x1E00 && c <= 0x2000) { | |
444 result = SimpleWithGlyphOverflow; | |
445 continue; | |
446 } | |
447 | |
448 // Surrogate pairs | |
449 if (c > 0xD7FF && c <= 0xDBFF) { | |
450 if (i == len - 1) | |
451 continue; | |
452 | |
453 UChar next = characters[++i]; | |
454 if (!U16_IS_TRAIL(next)) | |
455 continue; | |
456 | |
457 UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next); | |
458 | |
459 if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Reg
ional Indicator Symbols | |
460 continue; | |
461 if (supplementaryCharacter <= 0x1F1FF) | |
462 return Complex; | |
463 | |
464 if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Uni
code variation selectors. | |
465 continue; | |
466 if (supplementaryCharacter <= 0xE01EF) | |
467 return Complex; | |
468 | |
469 // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) a
nd other complex scripts | |
470 // in plane 1 or higher. | |
471 | |
472 continue; | |
473 } | |
474 | |
475 // Search for other Complex cases | |
476 UChar* boundingCharacter = approximateBinarySearch<UChar, UChar>( | |
477 (UChar*)complexCodePathRanges, complexCodePathRangesCount, c, keyExt
ractorUChar); | |
478 // Exact matches are complex | |
479 if (*boundingCharacter == c) | |
480 return Complex; | |
481 bool isEndOfRange = ((boundingCharacter - complexCodePathRanges) % 2); | |
482 if (*boundingCharacter < c) { | |
483 // Determine if we are in a range or out | |
484 if (!isEndOfRange) | |
485 return Complex; | |
486 continue; | |
487 } | |
488 ASSERT(*boundingCharacter > c); | |
489 // Determine if we are in a range or out - opposite condition to above | |
490 if (isEndOfRange) | |
491 return Complex; | |
492 } | |
493 | |
494 return result; | |
495 } | |
496 | |
497 bool Font::isCJKIdeograph(UChar32 c) | |
498 { | |
499 static const UChar32 cjkIdeographRanges[] = { | |
500 // CJK Radicals Supplement and Kangxi Radicals. | |
501 0x2E80, 0x2FDF, | |
502 // CJK Strokes. | |
503 0x31C0, 0x31EF, | |
504 // CJK Unified Ideographs Extension A. | |
505 0x3400, 0x4DBF, | |
506 // The basic CJK Unified Ideographs block. | |
507 0x4E00, 0x9FFF, | |
508 // CJK Compatibility Ideographs. | |
509 0xF900, 0xFAFF, | |
510 // CJK Unified Ideographs Extension B. | |
511 0x20000, 0x2A6DF, | |
512 // CJK Unified Ideographs Extension C. | |
513 // CJK Unified Ideographs Extension D. | |
514 0x2A700, 0x2B81F, | |
515 // CJK Compatibility Ideographs Supplement. | |
516 0x2F800, 0x2FA1F | |
517 }; | |
518 static size_t cjkIdeographRangesCount = WTF_ARRAY_LENGTH(cjkIdeographRanges)
; | |
519 | |
520 // Early out | |
521 if (c < cjkIdeographRanges[0] || c > cjkIdeographRanges[cjkIdeographRangesCo
unt - 1]) | |
522 return false; | |
523 | |
524 UChar32* boundingCharacter = approximateBinarySearch<UChar32, UChar32>( | |
525 (UChar32*)cjkIdeographRanges, cjkIdeographRangesCount, c, keyExtractorUC
har32); | |
526 // Exact matches are CJK | |
527 if (*boundingCharacter == c) | |
528 return true; | |
529 bool isEndOfRange = ((boundingCharacter - cjkIdeographRanges) % 2); | |
530 if (*boundingCharacter < c) | |
531 return !isEndOfRange; | |
532 return isEndOfRange; | |
533 } | |
534 | |
535 bool Font::isCJKIdeographOrSymbol(UChar32 c) | |
536 { | |
537 // Likely common case | |
538 if (c < 0x2C7) | |
539 return false; | |
540 | |
541 // Hash lookup for isolated symbols (those not part of a contiguous range) | |
542 static HashSet<UChar32>* cjkIsolatedSymbols = 0; | |
543 if (!cjkIsolatedSymbols) { | |
544 cjkIsolatedSymbols = new HashSet<UChar32>(); | |
545 for (size_t i = 0; i < WTF_ARRAY_LENGTH(cjkIsolatedSymbolsArray); ++i) | |
546 cjkIsolatedSymbols->add(cjkIsolatedSymbolsArray[i]); | |
547 } | |
548 if (cjkIsolatedSymbols->contains(c)) | |
549 return true; | |
550 | |
551 if (isCJKIdeograph(c)) | |
552 return true; | |
553 | |
554 static const UChar32 cjkSymbolRanges[] = { | |
555 0x2156, 0x215A, | |
556 0x2160, 0x216B, | |
557 0x2170, 0x217B, | |
558 0x23BE, 0x23CC, | |
559 0x2460, 0x2492, | |
560 0x249C, 0x24FF, | |
561 0x25CE, 0x25D3, | |
562 0x25E2, 0x25E6, | |
563 0x2600, 0x2603, | |
564 0x2660, 0x266F, | |
565 0x2672, 0x267D, | |
566 0x2776, 0x277F, | |
567 // Ideographic Description Characters, with CJK Symbols and Punctuation,
excluding 0x3030. | |
568 // Then Hiragana 0x3040 .. 0x309F, Katakana 0x30A0 .. 0x30FF, Bopomofo 0
x3100 .. 0x312F | |
569 0x2FF0, 0x302F, | |
570 0x3031, 0x312F, | |
571 // More Bopomofo and Bopomofo Extended 0x31A0 .. 0x31BF | |
572 0x3190, 0x31BF, | |
573 // Enclosed CJK Letters and Months (0x3200 .. 0x32FF). | |
574 // CJK Compatibility (0x3300 .. 0x33FF). | |
575 0x3200, 0x33FF, | |
576 0xF860, 0xF862, | |
577 // CJK Compatibility Forms. | |
578 0xFE30, 0xFE4F, | |
579 // Halfwidth and Fullwidth Forms | |
580 // Usually only used in CJK | |
581 0xFF00, 0xFF0C, | |
582 0xFF0E, 0xFF1A, | |
583 0xFF1F, 0xFFEF, | |
584 // Emoji. | |
585 0x1F110, 0x1F129, | |
586 0x1F130, 0x1F149, | |
587 0x1F150, 0x1F169, | |
588 0x1F170, 0x1F189, | |
589 0x1F200, 0x1F6FF | |
590 }; | |
591 static size_t cjkSymbolRangesCount = WTF_ARRAY_LENGTH(cjkSymbolRanges); | |
592 | |
593 UChar32* boundingCharacter = approximateBinarySearch<UChar32, UChar32>( | |
594 (UChar32*)cjkSymbolRanges, cjkSymbolRangesCount, c, keyExtractorUChar32)
; | |
595 // Exact matches are CJK Symbols | |
596 if (*boundingCharacter == c) | |
597 return true; | |
598 bool isEndOfRange = ((boundingCharacter - cjkSymbolRanges) % 2); | |
599 if (*boundingCharacter < c) | |
600 return !isEndOfRange; | |
601 return isEndOfRange; | |
602 } | |
603 | |
604 unsigned Font::expansionOpportunityCount(const LChar* characters, size_t length,
TextDirection direction, bool& isAfterExpansion) | |
605 { | |
606 unsigned count = 0; | |
607 if (direction == LTR) { | |
608 for (size_t i = 0; i < length; ++i) { | |
609 if (treatAsSpace(characters[i])) { | |
610 count++; | |
611 isAfterExpansion = true; | |
612 } else | |
613 isAfterExpansion = false; | |
614 } | |
615 } else { | |
616 for (size_t i = length; i > 0; --i) { | |
617 if (treatAsSpace(characters[i - 1])) { | |
618 count++; | |
619 isAfterExpansion = true; | |
620 } else | |
621 isAfterExpansion = false; | |
622 } | |
623 } | |
624 return count; | |
625 } | |
626 | |
627 unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length,
TextDirection direction, bool& isAfterExpansion) | |
628 { | |
629 static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText(
); | |
630 unsigned count = 0; | |
631 if (direction == LTR) { | |
632 for (size_t i = 0; i < length; ++i) { | |
633 UChar32 character = characters[i]; | |
634 if (treatAsSpace(character)) { | |
635 count++; | |
636 isAfterExpansion = true; | |
637 continue; | |
638 } | |
639 if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(charact
ers[i + 1])) { | |
640 character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]); | |
641 i++; | |
642 } | |
643 if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) { | |
644 if (!isAfterExpansion) | |
645 count++; | |
646 count++; | |
647 isAfterExpansion = true; | |
648 continue; | |
649 } | |
650 isAfterExpansion = false; | |
651 } | |
652 } else { | |
653 for (size_t i = length; i > 0; --i) { | |
654 UChar32 character = characters[i - 1]; | |
655 if (treatAsSpace(character)) { | |
656 count++; | |
657 isAfterExpansion = true; | |
658 continue; | |
659 } | |
660 if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2
])) { | |
661 character = U16_GET_SUPPLEMENTARY(characters[i - 2], character); | |
662 i--; | |
663 } | |
664 if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) { | |
665 if (!isAfterExpansion) | |
666 count++; | |
667 count++; | |
668 isAfterExpansion = true; | |
669 continue; | |
670 } | |
671 isAfterExpansion = false; | |
672 } | |
673 } | |
674 return count; | |
675 } | |
676 | |
677 bool Font::canReceiveTextEmphasis(UChar32 c) | |
678 { | |
679 CharCategory category = Unicode::category(c); | |
680 if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Oth
er_NotAssigned | Other_Control | Other_Format)) | |
681 return false; | |
682 | |
683 // Additional word-separator characters listed in CSS Text Level 3 Editor's
Draft 3 November 2010. | |
684 if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWor
dSeparatorDot | |
685 || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c =
= tibetanMarkDelimiterTshegBstar) | |
686 return false; | |
687 | |
688 return true; | |
689 } | |
690 | |
691 void Font::willUseFontData() const | |
692 { | |
693 const FontFamily& family = fontDescription().family(); | |
694 if (m_fontFallbackList && m_fontFallbackList->fontSelector() && !family.fami
lyIsEmpty()) | |
695 m_fontFallbackList->fontSelector()->willUseFontData(fontDescription(), f
amily.family()); | |
696 } | |
697 | |
698 } | |
OLD | NEW |