Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / platform / fonts / Font.cpp
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 "platform/fonts/Font.h"
26
27 #include "platform/fonts/WidthIterator.h"
28 #include "platform/geometry/FloatRect.h"
29 #include "platform/text/TextRun.h"
30 #include "wtf/MainThread.h"
31 #include "wtf/StdLibExtras.h"
32 #include "wtf/text/StringBuilder.h"
33
34 using namespace WTF;
35 using namespace Unicode;
36
37 namespace WebCore {
38
39 const uint8_t Font::s_roundingHackCharacterTable[256] = {
40     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,
41     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 /*?*/,
42     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,
43     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,
44     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,
45     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,
46     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,
47     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
48 };
49
50 static const UChar32 cjkIsolatedSymbolsArray[] = {
51     // 0x2C7 Caron, Mandarin Chinese 3rd Tone
52     0x2C7,
53     // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
54     0x2CA,
55     // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone
56     0x2CB,
57     // 0x2D9 Dot Above, Mandarin Chinese 5th Tone
58     0x2D9,
59     0x2020, 0x2021, 0x2030, 0x203B, 0x203C, 0x2042, 0x2047, 0x2048, 0x2049, 0x2051,
60     0x20DD, 0x20DE, 0x2100, 0x2103, 0x2105, 0x2109, 0x210A, 0x2113, 0x2116, 0x2121,
61     0x212B, 0x213B, 0x2150, 0x2151, 0x2152, 0x217F, 0x2189, 0x2307, 0x2312, 0x23CE,
62     0x2423, 0x25A0, 0x25A1, 0x25A2, 0x25AA, 0x25AB, 0x25B1, 0x25B2, 0x25B3, 0x25B6,
63     0x25B7, 0x25BC, 0x25BD, 0x25C0, 0x25C1, 0x25C6, 0x25C7, 0x25C9, 0x25CB, 0x25CC,
64     0x25EF, 0x2605, 0x2606, 0x260E, 0x2616, 0x2617, 0x2640, 0x2642, 0x26A0, 0x26BD,
65     0x26BE, 0x2713, 0x271A, 0x273F, 0x2740, 0x2756, 0x2B1A, 0xFE10, 0xFE11, 0xFE12,
66     0xFE19, 0xFF1D,
67     // Emoji.
68     0x1F100
69 };
70
71 CodePath Font::s_codePath = AutoPath;
72
73 TypesettingFeatures Font::s_defaultTypesettingFeatures = 0;
74
75 // ============================================================================================
76 // Font Implementation (Cross-Platform Portion)
77 // ============================================================================================
78
79 Font::Font()
80     : m_letterSpacing(0)
81     , m_wordSpacing(0)
82     , m_typesettingFeatures(0)
83 {
84 }
85
86 Font::Font(const FontDescription& fd, float letterSpacing, float wordSpacing)
87     : m_fontDescription(fd)
88     , m_letterSpacing(letterSpacing)
89     , m_wordSpacing(wordSpacing)
90     , m_typesettingFeatures(computeTypesettingFeatures())
91 {
92 }
93
94 Font::Font(const Font& other)
95     : m_fontDescription(other.m_fontDescription)
96     , m_fontFallbackList(other.m_fontFallbackList)
97     , m_letterSpacing(other.m_letterSpacing)
98     , m_wordSpacing(other.m_wordSpacing)
99     , m_typesettingFeatures(computeTypesettingFeatures())
100 {
101 }
102
103 Font& Font::operator=(const Font& other)
104 {
105     m_fontDescription = other.m_fontDescription;
106     m_fontFallbackList = other.m_fontFallbackList;
107     m_letterSpacing = other.m_letterSpacing;
108     m_wordSpacing = other.m_wordSpacing;
109     m_typesettingFeatures = other.m_typesettingFeatures;
110     return *this;
111 }
112
113 bool Font::operator==(const Font& other) const
114 {
115     // Our FontData don't have to be checked, since checking the font description will be fine.
116     // FIXME: This does not work if the font was made with the FontPlatformData constructor.
117     if (loadingCustomFonts() || other.loadingCustomFonts())
118         return false;
119
120     FontSelector* first = m_fontFallbackList ? m_fontFallbackList->fontSelector() : 0;
121     FontSelector* second = other.m_fontFallbackList ? other.m_fontFallbackList->fontSelector() : 0;
122
123     return first == second
124         && m_fontDescription == other.m_fontDescription
125         && m_letterSpacing == other.m_letterSpacing
126         && m_wordSpacing == other.m_wordSpacing
127         && (m_fontFallbackList ? m_fontFallbackList->fontSelectorVersion() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->fontSelectorVersion() : 0)
128         && (m_fontFallbackList ? m_fontFallbackList->generation() : 0) == (other.m_fontFallbackList ? other.m_fontFallbackList->generation() : 0);
129 }
130
131 void Font::update(PassRefPtr<FontSelector> fontSelector) const
132 {
133     // FIXME: It is pretty crazy that we are willing to just poke into a RefPtr, but it ends up
134     // being reasonably safe (because inherited fonts in the render tree pick up the new
135     // style anyway. Other copies are transient, e.g., the state in the GraphicsContext, and
136     // won't stick around long enough to get you in trouble). Still, this is pretty disgusting,
137     // and could eventually be rectified by using RefPtrs for Fonts themselves.
138     if (!m_fontFallbackList)
139         m_fontFallbackList = FontFallbackList::create();
140     m_fontFallbackList->invalidate(fontSelector);
141     m_typesettingFeatures = computeTypesettingFeatures();
142 }
143
144 void Font::drawText(GraphicsContext* context, const TextRunPaintInfo& runInfo, const FloatPoint& point, CustomFontNotReadyAction customFontNotReadyAction) const
145 {
146     // Don't draw anything while we are using custom fonts that are in the process of loading,
147     // except if the 'force' argument is set to true (in which case it will use a fallback
148     // font).
149     if (loadingCustomFonts() && customFontNotReadyAction == DoNotPaintIfFontNotReady)
150         return;
151
152     CodePath codePathToUse = codePath(runInfo.run);
153     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
154     if (codePathToUse != ComplexPath && typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length()))
155         codePathToUse = ComplexPath;
156
157     if (codePathToUse != ComplexPath)
158         return drawSimpleText(context, runInfo, point);
159
160     return drawComplexText(context, runInfo, point);
161 }
162
163 void Font::drawEmphasisMarks(GraphicsContext* context, const TextRunPaintInfo& runInfo, const AtomicString& mark, const FloatPoint& point) const
164 {
165     if (loadingCustomFonts())
166         return;
167
168     CodePath codePathToUse = codePath(runInfo.run);
169     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
170     if (codePathToUse != ComplexPath && typesettingFeatures() && (runInfo.from || runInfo.to != runInfo.run.length()))
171         codePathToUse = ComplexPath;
172
173     if (codePathToUse != ComplexPath)
174         drawEmphasisMarksForSimpleText(context, runInfo, mark, point);
175     else
176         drawEmphasisMarksForComplexText(context, runInfo, mark, point);
177 }
178
179 float Font::width(const TextRun& run, HashSet<const SimpleFontData*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
180 {
181     CodePath codePathToUse = codePath(run);
182     if (codePathToUse != ComplexPath) {
183         // The complex path is more restrictive about returning fallback fonts than the simple path, so we need an explicit test to make their behaviors match.
184         if (!canReturnFallbackFontsForComplexText())
185             fallbackFonts = 0;
186         // The simple path can optimize the case where glyph overflow is not observable.
187         if (codePathToUse != SimpleWithGlyphOverflowPath && (glyphOverflow && !glyphOverflow->computeBounds))
188             glyphOverflow = 0;
189     }
190
191     bool hasKerningOrLigatures = typesettingFeatures() & (Kerning | Ligatures);
192     bool hasWordSpacingOrLetterSpacing = wordSpacing() || letterSpacing();
193     float* cacheEntry = m_fontFallbackList->widthCache().add(run, std::numeric_limits<float>::quiet_NaN(), hasKerningOrLigatures, hasWordSpacingOrLetterSpacing, glyphOverflow);
194     if (cacheEntry && !std::isnan(*cacheEntry))
195         return *cacheEntry;
196
197     float result;
198     if (codePathToUse == ComplexPath)
199         result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
200     else
201         result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow);
202
203     if (cacheEntry && (!fallbackFonts || fallbackFonts->isEmpty()))
204         *cacheEntry = result;
205     return result;
206 }
207
208 float Font::width(const TextRun& run, int& charsConsumed, String& glyphName) const
209 {
210 #if ENABLE(SVG_FONTS)
211     if (TextRun::RenderingContext* renderingContext = run.renderingContext())
212         return renderingContext->floatWidthUsingSVGFont(*this, run, charsConsumed, glyphName);
213 #endif
214
215     charsConsumed = run.length();
216     glyphName = "";
217     return width(run);
218 }
219
220 FloatRect Font::selectionRectForText(const TextRun& run, const FloatPoint& point, int h, int from, int to) const
221 {
222     to = (to == -1 ? run.length() : to);
223
224     CodePath codePathToUse = codePath(run);
225     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
226     if (codePathToUse != ComplexPath && typesettingFeatures() && (from || to != run.length()))
227         codePathToUse = ComplexPath;
228
229     if (codePathToUse != ComplexPath)
230         return selectionRectForSimpleText(run, point, h, from, to);
231
232     return selectionRectForComplexText(run, point, h, from, to);
233 }
234
235 int Font::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
236 {
237     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
238     if (codePath(run) != ComplexPath && !typesettingFeatures())
239         return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
240
241     return offsetForPositionForComplexText(run, x, includePartialGlyphs);
242 }
243
244 template <typename CharacterType>
245 static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length)
246 {
247     StringBuilder normalized;
248     normalized.reserveCapacity(length);
249
250     for (unsigned i = 0; i < length; ++i)
251         normalized.append(Font::normalizeSpaces(characters[i]));
252
253     return normalized.toString();
254 }
255
256 String Font::normalizeSpaces(const LChar* characters, unsigned length)
257 {
258     return normalizeSpacesInternal(characters, length);
259 }
260
261 String Font::normalizeSpaces(const UChar* characters, unsigned length)
262 {
263     return normalizeSpacesInternal(characters, length);
264 }
265
266 static bool shouldUseFontSmoothing = true;
267
268 void Font::setShouldUseSmoothing(bool shouldUseSmoothing)
269 {
270     ASSERT(isMainThread());
271     shouldUseFontSmoothing = shouldUseSmoothing;
272 }
273
274 bool Font::shouldUseSmoothing()
275 {
276     return shouldUseFontSmoothing;
277 }
278
279 void Font::setCodePath(CodePath p)
280 {
281     s_codePath = p;
282 }
283
284 CodePath Font::codePath()
285 {
286     return s_codePath;
287 }
288
289 void Font::setDefaultTypesettingFeatures(TypesettingFeatures typesettingFeatures)
290 {
291     s_defaultTypesettingFeatures = typesettingFeatures;
292 }
293
294 TypesettingFeatures Font::defaultTypesettingFeatures()
295 {
296     return s_defaultTypesettingFeatures;
297 }
298
299 CodePath Font::codePath(const TextRun& run) const
300 {
301     if (s_codePath != AutoPath)
302         return s_codePath;
303
304 #if ENABLE(SVG_FONTS)
305     if (run.renderingContext())
306         return SimplePath;
307 #endif
308
309     if (m_fontDescription.featureSettings() && m_fontDescription.featureSettings()->size() > 0)
310         return ComplexPath;
311
312     if (run.length() > 1 && !WidthIterator::supportsTypesettingFeatures(*this))
313         return ComplexPath;
314
315     if (!run.characterScanForCodePath())
316         return SimplePath;
317
318     if (run.is8Bit())
319         return SimplePath;
320
321     // Start from 0 since drawing and highlighting also measure the characters before run->from.
322     return characterRangeCodePath(run.characters16(), run.length());
323 }
324
325 // Takes a flattened list of closed intervals
326 template <class T, size_t size>
327 bool valueInIntervalList(const T (&intervalList)[size], const T& value)
328 {
329     const T* bound = std::upper_bound(&intervalList[0], &intervalList[size], value);
330     if ((bound - intervalList) % 2 == 1)
331         return true;
332     return bound > intervalList && *(bound - 1) == value;
333 }
334
335 CodePath Font::characterRangeCodePath(const UChar* characters, unsigned len)
336 {
337     static const UChar complexCodePathRanges[] = {
338         // U+02E5 through U+02E9 (Modifier Letters : Tone letters)
339         0x2E5, 0x2E9,
340         // U+0300 through U+036F Combining diacritical marks
341         0x300, 0x36F,
342         // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, ...
343         0x0591, 0x05BD,
344         // ... Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
345         0x05BF, 0x05CF,
346         // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic,
347         // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada,
348         // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
349         0x0600, 0x109F,
350         // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left
351         // here if you precompose; Modern Korean will be precomposed as a result of step A)
352         0x1100, 0x11FF,
353         // U+135D through U+135F Ethiopic combining marks
354         0x135D, 0x135F,
355         // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian
356         0x1700, 0x18AF,
357         // U+1900 through U+194F Limbu (Unicode 4.0)
358         0x1900, 0x194F,
359         // U+1980 through U+19DF New Tai Lue
360         0x1980, 0x19DF,
361         // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic
362         0x1A00, 0x1CFF,
363         // U+1DC0 through U+1DFF Comining diacritical mark supplement
364         0x1DC0, 0x1DFF,
365         // U+20D0 through U+20FF Combining marks for symbols
366         0x20D0, 0x20FF,
367         // U+2CEF through U+2CF1 Combining marks for Coptic
368         0x2CEF, 0x2CF1,
369         // U+302A through U+302F Ideographic and Hangul Tone marks
370         0x302A, 0x302F,
371         // U+A67C through U+A67D Combining marks for old Cyrillic
372         0xA67C, 0xA67D,
373         // U+A6F0 through U+A6F1 Combining mark for Bamum
374         0xA6F0, 0xA6F1,
375         // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended,
376         // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek
377         0xA800, 0xABFF,
378         // U+D7B0 through U+D7FF Hangul Jamo Ext. B
379         0xD7B0, 0xD7FF,
380         // U+FE00 through U+FE0F Unicode variation selectors
381         0xFE00, 0xFE0F,
382         // U+FE20 through U+FE2F Combining half marks
383         0xFE20, 0xFE2F
384     };
385
386     CodePath result = SimplePath;
387     for (unsigned i = 0; i < len; i++) {
388         const UChar c = characters[i];
389
390         // Shortcut for common case
391         if (c < 0x2E5)
392             continue;
393
394         // U+1E00 through U+2000 characters with diacritics and stacked diacritics
395         if (c >= 0x1E00 && c <= 0x2000) {
396             result = SimpleWithGlyphOverflowPath;
397             continue;
398         }
399
400         // Surrogate pairs
401         if (c > 0xD7FF && c <= 0xDBFF) {
402             if (i == len - 1)
403                 continue;
404
405             UChar next = characters[++i];
406             if (!U16_IS_TRAIL(next))
407                 continue;
408
409             UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next);
410
411             if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols
412                 continue;
413             if (supplementaryCharacter <= 0x1F1FF)
414                 return ComplexPath;
415
416             if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors.
417                 continue;
418             if (supplementaryCharacter <= 0xE01EF)
419                 return ComplexPath;
420
421             // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts
422             // in plane 1 or higher.
423
424             continue;
425         }
426
427         // Search for other Complex cases
428         if (valueInIntervalList(complexCodePathRanges, c))
429             return ComplexPath;
430     }
431
432     return result;
433 }
434
435 bool Font::isCJKIdeograph(UChar32 c)
436 {
437     static const UChar32 cjkIdeographRanges[] = {
438         // CJK Radicals Supplement and Kangxi Radicals.
439         0x2E80, 0x2FDF,
440         // CJK Strokes.
441         0x31C0, 0x31EF,
442         // CJK Unified Ideographs Extension A.
443         0x3400, 0x4DBF,
444         // The basic CJK Unified Ideographs block.
445         0x4E00, 0x9FFF,
446         // CJK Compatibility Ideographs.
447         0xF900, 0xFAFF,
448         // CJK Unified Ideographs Extension B.
449         0x20000, 0x2A6DF,
450         // CJK Unified Ideographs Extension C.
451         // CJK Unified Ideographs Extension D.
452         0x2A700, 0x2B81F,
453         // CJK Compatibility Ideographs Supplement.
454         0x2F800, 0x2FA1F
455     };
456     static size_t cjkIdeographRangesCount = WTF_ARRAY_LENGTH(cjkIdeographRanges);
457
458     // Early out
459     if (c < cjkIdeographRanges[0] || c > cjkIdeographRanges[cjkIdeographRangesCount - 1])
460         return false;
461
462     return valueInIntervalList(cjkIdeographRanges, c);
463 }
464
465 bool Font::isCJKIdeographOrSymbol(UChar32 c)
466 {
467     // Likely common case
468     if (c < 0x2C7)
469         return false;
470
471     // Hash lookup for isolated symbols (those not part of a contiguous range)
472     static HashSet<UChar32>* cjkIsolatedSymbols = 0;
473     if (!cjkIsolatedSymbols) {
474         cjkIsolatedSymbols = new HashSet<UChar32>();
475         for (size_t i = 0; i < WTF_ARRAY_LENGTH(cjkIsolatedSymbolsArray); ++i)
476             cjkIsolatedSymbols->add(cjkIsolatedSymbolsArray[i]);
477     }
478     if (cjkIsolatedSymbols->contains(c))
479         return true;
480
481     if (isCJKIdeograph(c))
482         return true;
483
484     static const UChar32 cjkSymbolRanges[] = {
485         0x2156, 0x215A,
486         0x2160, 0x216B,
487         0x2170, 0x217B,
488         0x23BE, 0x23CC,
489         0x2460, 0x2492,
490         0x249C, 0x24FF,
491         0x25CE, 0x25D3,
492         0x25E2, 0x25E6,
493         0x2600, 0x2603,
494         0x2660, 0x266F,
495         0x2672, 0x267D,
496         0x2776, 0x277F,
497         // Ideographic Description Characters, with CJK Symbols and Punctuation, excluding 0x3030.
498         // Then Hiragana 0x3040 .. 0x309F, Katakana 0x30A0 .. 0x30FF, Bopomofo 0x3100 .. 0x312F
499         0x2FF0, 0x302F,
500         0x3031, 0x312F,
501         // More Bopomofo and Bopomofo Extended 0x31A0 .. 0x31BF
502         0x3190, 0x31BF,
503         // Enclosed CJK Letters and Months (0x3200 .. 0x32FF).
504         // CJK Compatibility (0x3300 .. 0x33FF).
505         0x3200, 0x33FF,
506         0xF860, 0xF862,
507         // CJK Compatibility Forms.
508         0xFE30, 0xFE4F,
509         // Halfwidth and Fullwidth Forms
510         // Usually only used in CJK
511         0xFF00, 0xFF0C,
512         0xFF0E, 0xFF1A,
513         0xFF1F, 0xFFEF,
514         // Emoji.
515         0x1F110, 0x1F129,
516         0x1F130, 0x1F149,
517         0x1F150, 0x1F169,
518         0x1F170, 0x1F189,
519         0x1F200, 0x1F6FF
520     };
521
522     return valueInIntervalList(cjkSymbolRanges, c);
523 }
524
525 unsigned Font::expansionOpportunityCount(const LChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
526 {
527     unsigned count = 0;
528     if (direction == LTR) {
529         for (size_t i = 0; i < length; ++i) {
530             if (treatAsSpace(characters[i])) {
531                 count++;
532                 isAfterExpansion = true;
533             } else
534                 isAfterExpansion = false;
535         }
536     } else {
537         for (size_t i = length; i > 0; --i) {
538             if (treatAsSpace(characters[i - 1])) {
539                 count++;
540                 isAfterExpansion = true;
541             } else
542                 isAfterExpansion = false;
543         }
544     }
545     return count;
546 }
547
548 unsigned Font::expansionOpportunityCount(const UChar* characters, size_t length, TextDirection direction, bool& isAfterExpansion)
549 {
550     static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
551     unsigned count = 0;
552     if (direction == LTR) {
553         for (size_t i = 0; i < length; ++i) {
554             UChar32 character = characters[i];
555             if (treatAsSpace(character)) {
556                 count++;
557                 isAfterExpansion = true;
558                 continue;
559             }
560             if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
561                 character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
562                 i++;
563             }
564             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
565                 if (!isAfterExpansion)
566                     count++;
567                 count++;
568                 isAfterExpansion = true;
569                 continue;
570             }
571             isAfterExpansion = false;
572         }
573     } else {
574         for (size_t i = length; i > 0; --i) {
575             UChar32 character = characters[i - 1];
576             if (treatAsSpace(character)) {
577                 count++;
578                 isAfterExpansion = true;
579                 continue;
580             }
581             if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
582                 character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
583                 i--;
584             }
585             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
586                 if (!isAfterExpansion)
587                     count++;
588                 count++;
589                 isAfterExpansion = true;
590                 continue;
591             }
592             isAfterExpansion = false;
593         }
594     }
595     return count;
596 }
597
598 bool Font::canReceiveTextEmphasis(UChar32 c)
599 {
600     CharCategory category = Unicode::category(c);
601     if (category & (Separator_Space | Separator_Line | Separator_Paragraph | Other_NotAssigned | Other_Control | Other_Format))
602         return false;
603
604     // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
605     if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
606         || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
607         return false;
608
609     return true;
610 }
611
612 void Font::willUseFontData() const
613 {
614     const FontFamily& family = fontDescription().family();
615     if (m_fontFallbackList && m_fontFallbackList->fontSelector() && !family.familyIsEmpty())
616         m_fontFallbackList->fontSelector()->willUseFontData(fontDescription(), family.family());
617 }
618
619 }