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