Move locale information into FontDescription
[WebKit-https.git] / Source / WebCore / platform / graphics / FontCascade.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 "FontCascade.h"
26
27 #include "CharacterProperties.h"
28 #include "FloatRect.h"
29 #include "FontCache.h"
30 #include "GlyphBuffer.h"
31 #include "LayoutRect.h"
32 #include "SurrogatePairAwareTextIterator.h"
33 #include "TextRun.h"
34 #include "WidthIterator.h"
35 #include <wtf/MainThread.h>
36 #include <wtf/MathExtras.h>
37 #include <wtf/NeverDestroyed.h>
38 #include <wtf/text/AtomicStringHash.h>
39 #include <wtf/text/StringBuilder.h>
40
41 using namespace WTF;
42 using namespace Unicode;
43
44 namespace WebCore {
45
46 static Ref<FontCascadeFonts> retrieveOrAddCachedFonts(const FontCascadeDescription&, RefPtr<FontSelector>&&);
47
48 const uint8_t FontCascade::s_roundingHackCharacterTable[256] = {
49     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,
50     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 /*?*/,
51     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,
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     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,
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     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 };
58
59 static bool isDrawnWithSVGFont(const TextRun& run)
60 {
61     return run.renderingContext();
62 }
63
64 static bool useBackslashAsYenSignForFamily(const AtomicString& family)
65 {
66     if (family.isEmpty())
67         return false;
68     static HashSet<AtomicString>* set;
69     if (!set) {
70         set = new HashSet<AtomicString>;
71         set->add("MS PGothic");
72         UChar unicodeNameMSPGothic[] = {0xFF2D, 0xFF33, 0x0020, 0xFF30, 0x30B4, 0x30B7, 0x30C3, 0x30AF};
73         set->add(AtomicString(unicodeNameMSPGothic, WTF_ARRAY_LENGTH(unicodeNameMSPGothic)));
74
75         set->add("MS PMincho");
76         UChar unicodeNameMSPMincho[] = {0xFF2D, 0xFF33, 0x0020, 0xFF30, 0x660E, 0x671D};
77         set->add(AtomicString(unicodeNameMSPMincho, WTF_ARRAY_LENGTH(unicodeNameMSPMincho)));
78
79         set->add("MS Gothic");
80         UChar unicodeNameMSGothic[] = {0xFF2D, 0xFF33, 0x0020, 0x30B4, 0x30B7, 0x30C3, 0x30AF};
81         set->add(AtomicString(unicodeNameMSGothic, WTF_ARRAY_LENGTH(unicodeNameMSGothic)));
82
83         set->add("MS Mincho");
84         UChar unicodeNameMSMincho[] = {0xFF2D, 0xFF33, 0x0020, 0x660E, 0x671D};
85         set->add(AtomicString(unicodeNameMSMincho, WTF_ARRAY_LENGTH(unicodeNameMSMincho)));
86
87         set->add("Meiryo");
88         UChar unicodeNameMeiryo[] = {0x30E1, 0x30A4, 0x30EA, 0x30AA};
89         set->add(AtomicString(unicodeNameMeiryo, WTF_ARRAY_LENGTH(unicodeNameMeiryo)));
90     }
91     return set->contains(family);
92 }
93
94 FontCascade::CodePath FontCascade::s_codePath = Auto;
95
96 // ============================================================================================
97 // FontCascade Implementation (Cross-Platform Portion)
98 // ============================================================================================
99
100 FontCascade::FontCascade()
101     : m_weakPtrFactory(this)
102     , m_letterSpacing(0)
103     , m_wordSpacing(0)
104     , m_useBackslashAsYenSymbol(false)
105     , m_enableKerning(false)
106     , m_requiresShaping(false)
107 {
108 }
109
110 FontCascade::FontCascade(const FontCascadeDescription& fd, float letterSpacing, float wordSpacing)
111     : m_fontDescription(fd)
112     , m_weakPtrFactory(this)
113     , m_letterSpacing(letterSpacing)
114     , m_wordSpacing(wordSpacing)
115     , m_useBackslashAsYenSymbol(useBackslashAsYenSignForFamily(fd.firstFamily()))
116     , m_enableKerning(computeEnableKerning())
117     , m_requiresShaping(computeRequiresShaping())
118 {
119 }
120
121 // FIXME: We should make this constructor platform-independent.
122 FontCascade::FontCascade(const FontPlatformData& fontData, FontSmoothingMode fontSmoothingMode)
123     : m_fonts(FontCascadeFonts::createForPlatformFont(fontData))
124     , m_weakPtrFactory(this)
125     , m_letterSpacing(0)
126     , m_wordSpacing(0)
127     , m_useBackslashAsYenSymbol(false)
128     , m_enableKerning(computeEnableKerning())
129     , m_requiresShaping(computeRequiresShaping())
130 {
131     m_fontDescription.setFontSmoothing(fontSmoothingMode);
132 #if PLATFORM(IOS)
133     m_fontDescription.setSpecifiedSize(CTFontGetSize(fontData.font()));
134     m_fontDescription.setComputedSize(CTFontGetSize(fontData.font()));
135     m_fontDescription.setIsItalic(CTFontGetSymbolicTraits(fontData.font()) & kCTFontTraitItalic);
136     m_fontDescription.setWeight((CTFontGetSymbolicTraits(fontData.font()) & kCTFontTraitBold) ? FontWeightBold : FontWeightNormal);
137 #endif
138 }
139
140 FontCascade::FontCascade(const FontCascade& other)
141     : m_fontDescription(other.m_fontDescription)
142     , m_fonts(other.m_fonts)
143     , m_weakPtrFactory(this)
144     , m_letterSpacing(other.m_letterSpacing)
145     , m_wordSpacing(other.m_wordSpacing)
146     , m_useBackslashAsYenSymbol(other.m_useBackslashAsYenSymbol)
147     , m_enableKerning(computeEnableKerning())
148     , m_requiresShaping(computeRequiresShaping())
149 {
150 }
151
152 FontCascade& FontCascade::operator=(const FontCascade& other)
153 {
154     m_fontDescription = other.m_fontDescription;
155     m_fonts = other.m_fonts;
156     m_letterSpacing = other.m_letterSpacing;
157     m_wordSpacing = other.m_wordSpacing;
158     m_useBackslashAsYenSymbol = other.m_useBackslashAsYenSymbol;
159     m_enableKerning = other.m_enableKerning;
160     m_requiresShaping = other.m_requiresShaping;
161     return *this;
162 }
163
164 bool FontCascade::operator==(const FontCascade& other) const
165 {
166     if (isLoadingCustomFonts() || other.isLoadingCustomFonts())
167         return false;
168
169     if (m_fontDescription != other.m_fontDescription || m_letterSpacing != other.m_letterSpacing || m_wordSpacing != other.m_wordSpacing)
170         return false;
171     if (m_fonts == other.m_fonts)
172         return true;
173     if (!m_fonts || !other.m_fonts)
174         return false;
175     if (m_fonts->fontSelector() != other.m_fonts->fontSelector())
176         return false;
177     // Can these cases actually somehow occur? All fonts should get wiped out by full style recalc.
178     if (m_fonts->fontSelectorVersion() != other.m_fonts->fontSelectorVersion())
179         return false;
180     if (m_fonts->generation() != other.m_fonts->generation())
181         return false;
182     return true;
183 }
184
185 struct FontCascadeCacheKey {
186     FontDescriptionKey fontDescriptionKey; // Shared with the lower level FontCache (caching Font objects)
187     Vector<AtomicString, 3> families;
188     unsigned fontSelectorId;
189     unsigned fontSelectorVersion;
190 };
191
192 struct FontCascadeCacheEntry {
193     WTF_MAKE_FAST_ALLOCATED;
194 public:
195     FontCascadeCacheEntry(FontCascadeCacheKey&& key, Ref<FontCascadeFonts>&& fonts)
196         : key(WTF::move(key))
197         , fonts(WTF::move(fonts))
198     { }
199     FontCascadeCacheKey key;
200     Ref<FontCascadeFonts> fonts;
201 };
202
203 typedef HashMap<unsigned, std::unique_ptr<FontCascadeCacheEntry>, AlreadyHashed> FontCascadeCache;
204
205 static bool operator==(const FontCascadeCacheKey& a, const FontCascadeCacheKey& b)
206 {
207     if (a.fontDescriptionKey != b.fontDescriptionKey)
208         return false;
209     if (a.fontSelectorId != b.fontSelectorId || a.fontSelectorVersion != b.fontSelectorVersion)
210         return false;
211     if (a.families.size() != b.families.size())
212         return false;
213     for (unsigned i = 0; i < a.families.size(); ++i) {
214         if (!equalIgnoringCase(a.families[i].impl(), b.families[i].impl()))
215             return false;
216     }
217     return true;
218 }
219
220 static FontCascadeCache& fontCascadeCache()
221 {
222     static NeverDestroyed<FontCascadeCache> cache;
223     return cache.get();
224 }
225
226 void invalidateFontCascadeCache()
227 {
228     fontCascadeCache().clear();
229 }
230
231 void clearWidthCaches()
232 {
233     for (auto& value : fontCascadeCache().values())
234         value->fonts.get().widthCache().clear();
235 }
236
237 static FontCascadeCacheKey makeFontCascadeCacheKey(const FontCascadeDescription& description, FontSelector* fontSelector)
238 {
239     FontCascadeCacheKey key;
240     key.fontDescriptionKey = FontDescriptionKey(description);
241     for (unsigned i = 0; i < description.familyCount(); ++i)
242         key.families.append(description.familyAt(i));
243     key.fontSelectorId = fontSelector ? fontSelector->uniqueId() : 0;
244     key.fontSelectorVersion = fontSelector ? fontSelector->version() : 0;
245     return key;
246 }
247
248 // FIXME: Why can't we just teach HashMap about FontCascadeCacheKey instead of hashing a hash?
249 static unsigned computeFontCascadeCacheHash(const FontCascadeCacheKey& key)
250 {
251     Vector<unsigned, 7> hashCodes;
252     hashCodes.reserveInitialCapacity(4 + key.families.size());
253
254     hashCodes.uncheckedAppend(key.fontDescriptionKey.computeHash());
255     hashCodes.uncheckedAppend(key.fontSelectorId);
256     hashCodes.uncheckedAppend(key.fontSelectorVersion);
257     for (unsigned i = 0; i < key.families.size(); ++i)
258         hashCodes.uncheckedAppend(key.families[i].impl() ? CaseFoldingHash::hash(key.families[i]) : 0);
259
260     return StringHasher::hashMemory(hashCodes.data(), hashCodes.size() * sizeof(unsigned));
261 }
262
263 void pruneUnreferencedEntriesFromFontCascadeCache()
264 {
265     fontCascadeCache().removeIf([](FontCascadeCache::KeyValuePairType& entry) {
266         return entry.value->fonts.get().hasOneRef();
267     });
268 }
269
270 void pruneSystemFallbackFonts()
271 {
272     for (auto& entry : fontCascadeCache().values())
273         entry->fonts->pruneSystemFallbacks();
274 }
275
276 static Ref<FontCascadeFonts> retrieveOrAddCachedFonts(const FontCascadeDescription& fontDescription, RefPtr<FontSelector>&& fontSelector)
277 {
278     auto key = makeFontCascadeCacheKey(fontDescription, fontSelector.get());
279
280     unsigned hash = computeFontCascadeCacheHash(key);
281     auto addResult = fontCascadeCache().add(hash, std::unique_ptr<FontCascadeCacheEntry>());
282     if (!addResult.isNewEntry && addResult.iterator->value->key == key)
283         return addResult.iterator->value->fonts.get();
284
285     auto& newEntry = addResult.iterator->value;
286     newEntry = std::make_unique<FontCascadeCacheEntry>(WTF::move(key), FontCascadeFonts::create(WTF::move(fontSelector)));
287     Ref<FontCascadeFonts> glyphs = newEntry->fonts.get();
288
289     static const unsigned unreferencedPruneInterval = 50;
290     static const int maximumEntries = 400;
291     static unsigned pruneCounter;
292     // Referenced FontCascadeFonts would exist anyway so pruning them saves little memory.
293     if (!(++pruneCounter % unreferencedPruneInterval))
294         pruneUnreferencedEntriesFromFontCascadeCache();
295     // Prevent pathological growth.
296     if (fontCascadeCache().size() > maximumEntries)
297         fontCascadeCache().remove(fontCascadeCache().begin());
298     return glyphs;
299 }
300
301 void FontCascade::update(RefPtr<FontSelector>&& fontSelector) const
302 {
303     m_fonts = retrieveOrAddCachedFonts(m_fontDescription, WTF::move(fontSelector));
304     m_useBackslashAsYenSymbol = useBackslashAsYenSignForFamily(firstFamily());
305     m_enableKerning = computeEnableKerning();
306     m_requiresShaping = computeRequiresShaping();
307 }
308
309 float FontCascade::drawText(GraphicsContext& context, const TextRun& run, const FloatPoint& point, int from, int to, CustomFontNotReadyAction customFontNotReadyAction) const
310 {
311     // Don't draw anything while we are using custom fonts that are in the process of loading,
312     // except if the 'force' argument is set to true (in which case it will use a fallback
313     // font).
314     if (isLoadingCustomFonts() && customFontNotReadyAction == DoNotPaintIfFontNotReady)
315         return 0;
316
317     to = (to == -1 ? run.length() : to);
318
319     CodePath codePathToUse = codePath(run);
320     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
321     if (codePathToUse != Complex && (enableKerning() || requiresShaping()) && (from || static_cast<unsigned>(to) != run.length()) && !isDrawnWithSVGFont(run))
322         codePathToUse = Complex;
323
324     if (codePathToUse != Complex)
325         return drawSimpleText(context, run, point, from, to);
326
327     return drawComplexText(context, run, point, from, to);
328 }
329
330 void FontCascade::drawEmphasisMarks(GraphicsContext& context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
331 {
332     if (isLoadingCustomFonts())
333         return;
334
335     if (to < 0)
336         to = run.length();
337
338     CodePath codePathToUse = codePath(run);
339     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
340     if (codePathToUse != Complex && (enableKerning() || requiresShaping()) && (from || static_cast<unsigned>(to) != run.length()) && !isDrawnWithSVGFont(run))
341         codePathToUse = Complex;
342
343     if (codePathToUse != Complex)
344         drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
345     else
346         drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
347 }
348
349 float FontCascade::width(const TextRun& run, HashSet<const Font*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
350 {
351     CodePath codePathToUse = codePath(run);
352     if (codePathToUse != Complex) {
353         // 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.
354         if (!canReturnFallbackFontsForComplexText())
355             fallbackFonts = 0;
356         // The simple path can optimize the case where glyph overflow is not observable.
357         if (codePathToUse != SimpleWithGlyphOverflow && (glyphOverflow && !glyphOverflow->computeBounds))
358             glyphOverflow = 0;
359     }
360
361     bool hasWordSpacingOrLetterSpacing = wordSpacing() || letterSpacing();
362     float* cacheEntry = m_fonts->widthCache().add(run, std::numeric_limits<float>::quiet_NaN(), enableKerning() || requiresShaping(), hasWordSpacingOrLetterSpacing, glyphOverflow);
363     if (cacheEntry && !std::isnan(*cacheEntry))
364         return *cacheEntry;
365
366     HashSet<const Font*> localFallbackFonts;
367     if (!fallbackFonts)
368         fallbackFonts = &localFallbackFonts;
369
370     float result;
371     if (codePathToUse == Complex)
372         result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
373     else
374         result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow);
375
376     if (cacheEntry && fallbackFonts->isEmpty())
377         *cacheEntry = result;
378     return result;
379 }
380
381 float FontCascade::width(const TextRun& run, int& charsConsumed, String& glyphName) const
382 {
383 #if ENABLE(SVG_FONTS)
384     if (isDrawnWithSVGFont(run))
385         return run.renderingContext()->floatWidthUsingSVGFont(*this, run, charsConsumed, glyphName);
386 #endif
387
388     charsConsumed = run.length();
389     glyphName = "";
390     return width(run);
391 }
392
393 GlyphData FontCascade::glyphDataForCharacter(UChar32 c, bool mirror, FontVariant variant) const
394 {
395     if (variant == AutoVariant) {
396         if (m_fontDescription.smallCaps() && !primaryFont().isSVGFont()) {
397             UChar32 upperC = u_toupper(c);
398             if (upperC != c) {
399                 c = upperC;
400                 variant = SmallCapsVariant;
401             } else
402                 variant = NormalVariant;
403         } else
404             variant = NormalVariant;
405     }
406
407     if (mirror)
408         c = u_charMirror(c);
409
410     return m_fonts->glyphDataForCharacter(c, m_fontDescription, variant);
411 }
412
413 #if !PLATFORM(COCOA)
414
415 std::unique_ptr<TextLayout, TextLayoutDeleter> FontCascade::createLayout(RenderText&, float, bool) const
416 {
417     return nullptr;
418 }
419
420 void TextLayoutDeleter::operator()(TextLayout*) const
421 {
422 }
423
424 float FontCascade::width(TextLayout&, unsigned, unsigned, HashSet<const Font*>*)
425 {
426     ASSERT_NOT_REACHED();
427     return 0;
428 }
429
430 #endif
431
432 static const char* fontFamiliesWithInvalidCharWidth[] = {
433     "American Typewriter",
434     "Arial Hebrew",
435     "Chalkboard",
436     "Cochin",
437     "Corsiva Hebrew",
438     "Courier",
439     "Euphemia UCAS",
440     "Geneva",
441     "Gill Sans",
442     "Hei",
443     "Helvetica",
444     "Hoefler Text",
445     "InaiMathi",
446     "Kai",
447     "Lucida Grande",
448     "Marker Felt",
449     "Monaco",
450     "Mshtakan",
451     "New Peninim MT",
452     "Osaka",
453     "Raanana",
454     "STHeiti",
455     "Symbol",
456     "Times",
457     "Apple Braille",
458     "Apple LiGothic",
459     "Apple LiSung",
460     "Apple Symbols",
461     "AppleGothic",
462     "AppleMyungjo",
463     "#GungSeo",
464     "#HeadLineA",
465     "#PCMyungjo",
466     "#PilGi",
467 };
468
469 // For font families where any of the fonts don't have a valid entry in the OS/2 table
470 // for avgCharWidth, fallback to the legacy webkit behavior of getting the avgCharWidth
471 // from the width of a '0'. This only seems to apply to a fixed number of Mac fonts,
472 // but, in order to get similar rendering across platforms, we do this check for
473 // all platforms.
474 bool FontCascade::hasValidAverageCharWidth() const
475 {
476     AtomicString family = firstFamily();
477     if (family.isEmpty())
478         return false;
479
480 #if PLATFORM(MAC) || PLATFORM(IOS)
481     // Internal fonts on OS X and iOS also have an invalid entry in the table for avgCharWidth.
482     if (primaryFontIsSystemFont())
483         return false;
484 #endif
485
486     static HashSet<AtomicString>* fontFamiliesWithInvalidCharWidthMap = 0;
487
488     if (!fontFamiliesWithInvalidCharWidthMap) {
489         fontFamiliesWithInvalidCharWidthMap = new HashSet<AtomicString>;
490
491         for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontFamiliesWithInvalidCharWidth); ++i)
492             fontFamiliesWithInvalidCharWidthMap->add(AtomicString(fontFamiliesWithInvalidCharWidth[i]));
493     }
494
495     return !fontFamiliesWithInvalidCharWidthMap->contains(family);
496 }
497
498 bool FontCascade::fastAverageCharWidthIfAvailable(float& width) const
499 {
500     bool success = hasValidAverageCharWidth();
501     if (success)
502         width = roundf(primaryFont().avgCharWidth()); // FIXME: primaryFont() might not correspond to firstFamily().
503     return success;
504 }
505
506 void FontCascade::adjustSelectionRectForText(const TextRun& run, LayoutRect& selectionRect, int from, int to) const
507 {
508     to = (to == -1 ? run.length() : to);
509
510     CodePath codePathToUse = codePath(run);
511     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
512     if (codePathToUse != Complex && (enableKerning() || requiresShaping()) && (from || static_cast<unsigned>(to) != run.length()) && !isDrawnWithSVGFont(run))
513         codePathToUse = Complex;
514
515     if (codePathToUse != Complex)
516         return adjustSelectionRectForSimpleText(run, selectionRect, from, to);
517
518     return adjustSelectionRectForComplexText(run, selectionRect, from, to);
519 }
520
521 int FontCascade::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
522 {
523     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
524     if (codePath(run) != Complex && (!(enableKerning() || requiresShaping()) || isDrawnWithSVGFont(run)))
525         return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
526
527     return offsetForPositionForComplexText(run, x, includePartialGlyphs);
528 }
529
530 template <typename CharacterType>
531 static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length)
532 {
533     StringBuilder normalized;
534     normalized.reserveCapacity(length);
535
536     for (unsigned i = 0; i < length; ++i)
537         normalized.append(FontCascade::normalizeSpaces(characters[i]));
538
539     return normalized.toString();
540 }
541
542 String FontCascade::normalizeSpaces(const LChar* characters, unsigned length)
543 {
544     return normalizeSpacesInternal(characters, length);
545 }
546
547 String FontCascade::normalizeSpaces(const UChar* characters, unsigned length)
548 {
549     return normalizeSpacesInternal(characters, length);
550 }
551
552 static bool shouldUseFontSmoothing = true;
553
554 void FontCascade::setShouldUseSmoothing(bool shouldUseSmoothing)
555 {
556     ASSERT(isMainThread());
557     shouldUseFontSmoothing = shouldUseSmoothing;
558 }
559
560 bool FontCascade::shouldUseSmoothing()
561 {
562     return shouldUseFontSmoothing;
563 }
564
565 static bool antialiasedFontDilationIsEnabled = false;
566
567 void FontCascade::setAntialiasedFontDilationEnabled(bool enabled)
568 {
569     antialiasedFontDilationIsEnabled = enabled;
570 }
571
572 bool FontCascade::antialiasedFontDilationEnabled()
573 {
574     return antialiasedFontDilationIsEnabled;
575 }
576
577 void FontCascade::setCodePath(CodePath p)
578 {
579     s_codePath = p;
580 }
581
582 FontCascade::CodePath FontCascade::codePath()
583 {
584     return s_codePath;
585 }
586
587 FontCascade::CodePath FontCascade::codePath(const TextRun& run) const
588 {
589     if (s_codePath != Auto)
590         return s_codePath;
591
592 #if ENABLE(SVG_FONTS)
593     if (isDrawnWithSVGFont(run))
594         return Simple;
595 #endif
596
597     // Because Font::applyTransforms() doesn't know which features to enable/disable in the simple code path, it can't properly handle feature or variant settings.
598     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=150791: @font-face features should also cause this to be complex.
599     if (m_fontDescription.featureSettings().size() > 0 || !m_fontDescription.variantSettings().isAllNormal())
600         return Complex;
601
602 #if !PLATFORM(COCOA)
603     if (run.length() > 1 && (enableKerning() || requiresShaping()))
604         return Complex;
605 #endif
606
607     if (!run.characterScanForCodePath())
608         return Simple;
609
610     if (run.is8Bit())
611         return Simple;
612
613     // Start from 0 since drawing and highlighting also measure the characters before run->from.
614     return characterRangeCodePath(run.characters16(), run.length());
615 }
616
617 FontCascade::CodePath FontCascade::characterRangeCodePath(const UChar* characters, unsigned len)
618 {
619     // FIXME: Should use a UnicodeSet in ports where ICU is used. Note that we 
620     // can't simply use UnicodeCharacter Property/class because some characters
621     // are not 'combining', but still need to go to the complex path.
622     // Alternatively, we may as well consider binary search over a sorted
623     // list of ranges.
624     CodePath result = Simple;
625     bool previousCharacterIsEmojiGroupCandidate = false;
626     for (unsigned i = 0; i < len; i++) {
627         const UChar c = characters[i];
628         if (c == zeroWidthJoiner && previousCharacterIsEmojiGroupCandidate)
629             return Complex;
630         
631         previousCharacterIsEmojiGroupCandidate = false;
632         if (c < 0x2E5) // U+02E5 through U+02E9 (Modifier Letters : Tone letters)  
633             continue;
634         if (c <= 0x2E9) 
635             return Complex;
636
637         if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
638             continue;
639         if (c <= 0x36F)
640             return Complex;
641
642         if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
643             continue;
644         if (c <= 0x05CF)
645             return Complex;
646
647         // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic,
648         // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, 
649         // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
650         if (c < 0x0600) 
651             continue;
652         if (c <= 0x109F)
653             return Complex;
654
655         // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose;
656         // Modern Korean will be precomposed as a result of step A)
657         if (c < 0x1100)
658             continue;
659         if (c <= 0x11FF)
660             return Complex;
661
662         if (c < 0x135D) // U+135D through U+135F Ethiopic combining marks
663             continue;
664         if (c <= 0x135F)
665             return Complex;
666
667         if (c < 0x1700) // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian
668             continue;
669         if (c <= 0x18AF)
670             return Complex;
671
672         if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
673             continue;
674         if (c <= 0x194F)
675             return Complex;
676
677         if (c < 0x1980) // U+1980 through U+19DF New Tai Lue
678             continue;
679         if (c <= 0x19DF)
680             return Complex;
681
682         if (c < 0x1A00) // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic
683             continue;
684         if (c <= 0x1CFF)
685             return Complex;
686
687         if (c < 0x1DC0) // U+1DC0 through U+1DFF Comining diacritical mark supplement
688             continue;
689         if (c <= 0x1DFF)
690             return Complex;
691
692         // U+1E00 through U+2000 characters with diacritics and stacked diacritics
693         if (c <= 0x2000) {
694             result = SimpleWithGlyphOverflow;
695             continue;
696         }
697
698         if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
699             continue;
700         if (c <= 0x20FF)
701             return Complex;
702
703         if (c < 0x2CEF) // U+2CEF through U+2CF1 Combining marks for Coptic
704             continue;
705         if (c <= 0x2CF1)
706             return Complex;
707
708         if (c < 0x302A) // U+302A through U+302F Ideographic and Hangul Tone marks
709             continue;
710         if (c <= 0x302F)
711             return Complex;
712
713         if (c < 0xA67C) // U+A67C through U+A67D Combining marks for old Cyrillic
714             continue;
715         if (c <= 0xA67D)
716             return Complex;
717
718         if (c < 0xA6F0) // U+A6F0 through U+A6F1 Combining mark for Bamum
719             continue;
720         if (c <= 0xA6F1)
721             return Complex;
722
723         // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended,
724         // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek,
725         if (c < 0xA800) 
726             continue;
727         if (c <= 0xABFF)
728             return Complex;
729
730         if (c < 0xD7B0) // U+D7B0 through U+D7FF Hangul Jamo Ext. B
731             continue;
732         if (c <= 0xD7FF)
733             return Complex;
734
735         if (c <= 0xDBFF) {
736             // High surrogate
737
738             if (i == len - 1)
739                 continue;
740
741             UChar next = characters[++i];
742             if (!U16_IS_TRAIL(next))
743                 continue;
744
745             UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next);
746
747             if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols
748                 continue;
749             if (supplementaryCharacter <= 0x1F1FF)
750                 return Complex;
751
752             if (supplementaryCharacter == 0x1F441 || supplementaryCharacter == 0x1F5E8 || (supplementaryCharacter >= 0x1F466 && supplementaryCharacter <= 0x1F469)) {
753                 previousCharacterIsEmojiGroupCandidate = true;
754                 continue;
755             }
756             if (isEmojiModifier(supplementaryCharacter))
757                 return Complex;
758             if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors.
759                 continue;
760             if (supplementaryCharacter <= 0xE01EF)
761                 return Complex;
762
763             // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts
764             // in plane 1 or higher.
765
766             continue;
767         }
768
769         if (c < 0xFE00) // U+FE00 through U+FE0F Unicode variation selectors
770             continue;
771         if (c <= 0xFE0F)
772             return Complex;
773
774         if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
775             continue;
776         if (c <= 0xFE2F)
777             return Complex;
778     }
779     return result;
780 }
781
782 bool FontCascade::isCJKIdeograph(UChar32 c)
783 {
784     // The basic CJK Unified Ideographs block.
785     if (c >= 0x4E00 && c <= 0x9FFF)
786         return true;
787     
788     // CJK Unified Ideographs Extension A.
789     if (c >= 0x3400 && c <= 0x4DBF)
790         return true;
791     
792     // CJK Radicals Supplement.
793     if (c >= 0x2E80 && c <= 0x2EFF)
794         return true;
795     
796     // Kangxi Radicals.
797     if (c >= 0x2F00 && c <= 0x2FDF)
798         return true;
799     
800     // CJK Strokes.
801     if (c >= 0x31C0 && c <= 0x31EF)
802         return true;
803     
804     // CJK Compatibility Ideographs.
805     if (c >= 0xF900 && c <= 0xFAFF)
806         return true;
807
808     // CJK Unified Ideographs Extension B.
809     if (c >= 0x20000 && c <= 0x2A6DF)
810         return true;
811
812     // CJK Unified Ideographs Extension C.
813     if (c >= 0x2A700 && c <= 0x2B73F)
814         return true;
815     
816     // CJK Unified Ideographs Extension D.
817     if (c >= 0x2B740 && c <= 0x2B81F)
818         return true;
819     
820     // CJK Compatibility Ideographs Supplement.
821     if (c >= 0x2F800 && c <= 0x2FA1F)
822         return true;
823
824     return false;
825 }
826
827 bool FontCascade::isCJKIdeographOrSymbol(UChar32 c)
828 {
829     // 0x2C7 Caron, Mandarin Chinese 3rd Tone
830     // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
831     // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone 
832     // 0x2D9 Dot Above, Mandarin Chinese 5th Tone 
833     if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9))
834         return true;
835
836     if ((c == 0x2020) || (c == 0x2021) || (c == 0x2030) || (c == 0x203B) || (c == 0x203C)
837         || (c == 0x2042) || (c == 0x2047) || (c == 0x2048) || (c == 0x2049) || (c == 0x2051)
838         || (c == 0x20DD) || (c == 0x20DE) || (c == 0x2100) || (c == 0x2103) || (c == 0x2105)
839         || (c == 0x2109) || (c == 0x210A) || (c == 0x2113) || (c == 0x2116) || (c == 0x2121)
840         || (c == 0x212B) || (c == 0x213B) || (c == 0x2150) || (c == 0x2151) || (c == 0x2152))
841         return true;
842
843     if (c >= 0x2156 && c <= 0x215A)
844         return true;
845
846     if (c >= 0x2160 && c <= 0x216B)
847         return true;
848
849     if (c >= 0x2170 && c <= 0x217B)
850         return true;
851
852     if ((c == 0x217F) || (c == 0x2189) || (c == 0x2307) || (c == 0x2312) || (c == 0x23BE) || (c == 0x23BF))
853         return true;
854
855     if (c >= 0x23C0 && c <= 0x23CC)
856         return true;
857
858     if ((c == 0x23CE) || (c == 0x2423))
859         return true;
860
861     if (c >= 0x2460 && c <= 0x2492)
862         return true;
863
864     if (c >= 0x249C && c <= 0x24FF)
865         return true;
866
867     if ((c == 0x25A0) || (c == 0x25A1) || (c == 0x25A2) || (c == 0x25AA) || (c == 0x25AB))
868         return true;
869
870     if ((c == 0x25B1) || (c == 0x25B2) || (c == 0x25B3) || (c == 0x25B6) || (c == 0x25B7) || (c == 0x25BC) || (c == 0x25BD))
871         return true;
872     
873     if ((c == 0x25C0) || (c == 0x25C1) || (c == 0x25C6) || (c == 0x25C7) || (c == 0x25C9) || (c == 0x25CB) || (c == 0x25CC))
874         return true;
875
876     if (c >= 0x25CE && c <= 0x25D3)
877         return true;
878
879     if (c >= 0x25E2 && c <= 0x25E6)
880         return true;
881
882     if (c == 0x25EF)
883         return true;
884
885     if (c >= 0x2600 && c <= 0x2603)
886         return true;
887
888     if ((c == 0x2605) || (c == 0x2606) || (c == 0x260E) || (c == 0x2616) || (c == 0x2617) || (c == 0x2640) || (c == 0x2642))
889         return true;
890
891     if (c >= 0x2660 && c <= 0x266F)
892         return true;
893
894     if (c >= 0x2672 && c <= 0x267D)
895         return true;
896
897     if ((c == 0x26A0) || (c == 0x26BD) || (c == 0x26BE) || (c == 0x2713) || (c == 0x271A) || (c == 0x273F) || (c == 0x2740) || (c == 0x2756))
898         return true;
899
900     if (c >= 0x2776 && c <= 0x277F)
901         return true;
902
903     if (c == 0x2B1A)
904         return true;
905
906     // Ideographic Description Characters.
907     if (c >= 0x2FF0 && c <= 0x2FFF)
908         return true;
909
910     // CJK Symbols and Punctuation, excluding 0x3030.
911     if (c >= 0x3000 && c < 0x3030)
912         return true;
913
914     if (c > 0x3030 && c <= 0x303F)
915         return true;
916
917     // Hiragana
918     if (c >= 0x3040 && c <= 0x309F)
919         return true;
920
921     // Katakana 
922     if (c >= 0x30A0 && c <= 0x30FF)
923         return true;
924
925     // Bopomofo
926     if (c >= 0x3100 && c <= 0x312F)
927         return true;
928
929     if (c >= 0x3190 && c <= 0x319F)
930         return true;
931
932     // Bopomofo Extended
933     if (c >= 0x31A0 && c <= 0x31BF)
934         return true;
935
936     // Enclosed CJK Letters and Months.
937     if (c >= 0x3200 && c <= 0x32FF)
938         return true;
939     
940     // CJK Compatibility.
941     if (c >= 0x3300 && c <= 0x33FF)
942         return true;
943
944     if (c >= 0xF860 && c <= 0xF862)
945         return true;
946
947     // CJK Compatibility Forms.
948     if (c >= 0xFE30 && c <= 0xFE4F)
949         return true;
950
951     if ((c == 0xFE10) || (c == 0xFE11) || (c == 0xFE12) || (c == 0xFE19))
952         return true;
953
954     if ((c == 0xFF0D) || (c == 0xFF1B) || (c == 0xFF1C) || (c == 0xFF1E))
955         return false;
956
957     // Halfwidth and Fullwidth Forms
958     // Usually only used in CJK
959     if (c >= 0xFF00 && c <= 0xFFEF)
960         return true;
961
962     // Emoji.
963     if (c == 0x1F100)
964         return true;
965
966     if (c >= 0x1F110 && c <= 0x1F129)
967         return true;
968
969     if (c >= 0x1F130 && c <= 0x1F149)
970         return true;
971
972     if (c >= 0x1F150 && c <= 0x1F169)
973         return true;
974
975     if (c >= 0x1F170 && c <= 0x1F189)
976         return true;
977
978     if (c >= 0x1F200 && c <= 0x1F6C5)
979         return true;
980
981     return isCJKIdeograph(c);
982 }
983
984 std::pair<unsigned, bool> FontCascade::expansionOpportunityCountInternal(const LChar* characters, size_t length, TextDirection direction, ExpansionBehavior expansionBehavior)
985 {
986     unsigned count = 0;
987     bool isAfterExpansion = (expansionBehavior & LeadingExpansionMask) == ForbidLeadingExpansion;
988     if ((expansionBehavior & LeadingExpansionMask) == ForceLeadingExpansion) {
989         ++count;
990         isAfterExpansion = true;
991     }
992     if (direction == LTR) {
993         for (size_t i = 0; i < length; ++i) {
994             if (treatAsSpace(characters[i])) {
995                 count++;
996                 isAfterExpansion = true;
997             } else
998                 isAfterExpansion = false;
999         }
1000     } else {
1001         for (size_t i = length; i > 0; --i) {
1002             if (treatAsSpace(characters[i - 1])) {
1003                 count++;
1004                 isAfterExpansion = true;
1005             } else
1006                 isAfterExpansion = false;
1007         }
1008     }
1009     if (!isAfterExpansion && (expansionBehavior & TrailingExpansionMask) == ForceTrailingExpansion) {
1010         ++count;
1011         isAfterExpansion = true;
1012     } else if (isAfterExpansion && (expansionBehavior & TrailingExpansionMask) == ForbidTrailingExpansion) {
1013         --count;
1014         isAfterExpansion = false;
1015     }
1016     return std::make_pair(count, isAfterExpansion);
1017 }
1018
1019 std::pair<unsigned, bool> FontCascade::expansionOpportunityCountInternal(const UChar* characters, size_t length, TextDirection direction, ExpansionBehavior expansionBehavior)
1020 {
1021     static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
1022     unsigned count = 0;
1023     bool isAfterExpansion = (expansionBehavior & LeadingExpansionMask) == ForbidLeadingExpansion;
1024     if ((expansionBehavior & LeadingExpansionMask) == ForceLeadingExpansion) {
1025         ++count;
1026         isAfterExpansion = true;
1027     }
1028     if (direction == LTR) {
1029         for (size_t i = 0; i < length; ++i) {
1030             UChar32 character = characters[i];
1031             if (treatAsSpace(character)) {
1032                 count++;
1033                 isAfterExpansion = true;
1034                 continue;
1035             }
1036             if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
1037                 character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
1038                 i++;
1039             }
1040             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
1041                 if (!isAfterExpansion)
1042                     count++;
1043                 count++;
1044                 isAfterExpansion = true;
1045                 continue;
1046             }
1047             isAfterExpansion = false;
1048         }
1049     } else {
1050         for (size_t i = length; i > 0; --i) {
1051             UChar32 character = characters[i - 1];
1052             if (treatAsSpace(character)) {
1053                 count++;
1054                 isAfterExpansion = true;
1055                 continue;
1056             }
1057             if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
1058                 character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
1059                 i--;
1060             }
1061             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
1062                 if (!isAfterExpansion)
1063                     count++;
1064                 count++;
1065                 isAfterExpansion = true;
1066                 continue;
1067             }
1068             isAfterExpansion = false;
1069         }
1070     }
1071     if (!isAfterExpansion && (expansionBehavior & TrailingExpansionMask) == ForceTrailingExpansion) {
1072         ++count;
1073         isAfterExpansion = true;
1074     } else if (isAfterExpansion && (expansionBehavior & TrailingExpansionMask) == ForbidTrailingExpansion) {
1075         --count;
1076         isAfterExpansion = false;
1077     }
1078     return std::make_pair(count, isAfterExpansion);
1079 }
1080
1081 std::pair<unsigned, bool> FontCascade::expansionOpportunityCount(const StringView& stringView, TextDirection direction, ExpansionBehavior expansionBehavior)
1082 {
1083     // For each character, iterating from left to right:
1084     //   If it is recognized as a space, insert an opportunity after it
1085     //   If it is an ideograph, insert one opportunity before it and one opportunity after it
1086     // Do this such a way so that there are not two opportunities next to each other.
1087     if (stringView.is8Bit())
1088         return expansionOpportunityCountInternal(stringView.characters8(), stringView.length(), direction, expansionBehavior);
1089     return expansionOpportunityCountInternal(stringView.characters16(), stringView.length(), direction, expansionBehavior);
1090 }
1091
1092 bool FontCascade::leadingExpansionOpportunity(const StringView& stringView, TextDirection direction)
1093 {
1094     if (!stringView.length())
1095         return false;
1096
1097     UChar32 initialCharacter;
1098     if (direction == LTR) {
1099         initialCharacter = stringView[0];
1100         if (U16_IS_LEAD(initialCharacter) && stringView.length() > 1 && U16_IS_TRAIL(stringView[1]))
1101             initialCharacter = U16_GET_SUPPLEMENTARY(initialCharacter, stringView[1]);
1102     } else {
1103         initialCharacter = stringView[stringView.length() - 1];
1104         if (U16_IS_TRAIL(initialCharacter) && stringView.length() > 1 && U16_IS_LEAD(stringView[stringView.length() - 2]))
1105             initialCharacter = U16_GET_SUPPLEMENTARY(stringView[stringView.length() - 2], initialCharacter);
1106     }
1107
1108     return canExpandAroundIdeographsInComplexText() && isCJKIdeographOrSymbol(initialCharacter);
1109 }
1110
1111 bool FontCascade::trailingExpansionOpportunity(const StringView& stringView, TextDirection direction)
1112 {
1113     if (!stringView.length())
1114         return false;
1115
1116     UChar32 finalCharacter;
1117     if (direction == LTR) {
1118         finalCharacter = stringView[stringView.length() - 1];
1119         if (U16_IS_TRAIL(finalCharacter) && stringView.length() > 1 && U16_IS_LEAD(stringView[stringView.length() - 2]))
1120             finalCharacter = U16_GET_SUPPLEMENTARY(stringView[stringView.length() - 2], finalCharacter);
1121     } else {
1122         finalCharacter = stringView[0];
1123         if (U16_IS_LEAD(finalCharacter) && stringView.length() > 1 && U16_IS_TRAIL(stringView[1]))
1124             finalCharacter = U16_GET_SUPPLEMENTARY(finalCharacter, stringView[1]);
1125     }
1126
1127     return treatAsSpace(finalCharacter) || (canExpandAroundIdeographsInComplexText() && isCJKIdeographOrSymbol(finalCharacter));
1128 }
1129
1130 bool FontCascade::canReceiveTextEmphasis(UChar32 c)
1131 {
1132     if (U_GET_GC_MASK(c) & (U_GC_Z_MASK | U_GC_CN_MASK | U_GC_CC_MASK | U_GC_CF_MASK))
1133         return false;
1134
1135     // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
1136     if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
1137         || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
1138         return false;
1139
1140     return true;
1141 }
1142
1143 bool FontCascade::isLoadingCustomFonts() const
1144 {
1145     return m_fonts && m_fonts->isLoadingCustomFonts();
1146 }
1147     
1148 GlyphToPathTranslator::GlyphUnderlineType computeUnderlineType(const TextRun& textRun, const GlyphBuffer& glyphBuffer, int index)
1149 {
1150     // In general, we want to skip descenders. However, skipping descenders on CJK characters leads to undesirable renderings,
1151     // so we want to draw through CJK characters (on a character-by-character basis).
1152     UChar32 baseCharacter;
1153     unsigned offsetInString = glyphBuffer.offsetInString(index);
1154
1155     if (offsetInString == GlyphBuffer::noOffset) {
1156         // We have no idea which character spawned this glyph. Bail.
1157         return GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph;
1158     }
1159     
1160     if (textRun.is8Bit())
1161         baseCharacter = textRun.characters8()[offsetInString];
1162     else
1163         U16_NEXT(textRun.characters16(), offsetInString, textRun.length(), baseCharacter);
1164     
1165     // u_getIntPropertyValue with UCHAR_IDEOGRAPHIC doesn't return true for Japanese or Korean codepoints.
1166     // Instead, we can use the "Unicode allocation block" for the character.
1167     UBlockCode blockCode = ublock_getCode(baseCharacter);
1168     switch (blockCode) {
1169     case UBLOCK_CJK_RADICALS_SUPPLEMENT:
1170     case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
1171     case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS:
1172     case UBLOCK_CJK_COMPATIBILITY:
1173     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A:
1174     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS:
1175     case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS:
1176     case UBLOCK_CJK_COMPATIBILITY_FORMS:
1177     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B:
1178     case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT:
1179     case UBLOCK_CJK_STROKES:
1180     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C:
1181     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D:
1182     case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS:
1183     case UBLOCK_LINEAR_B_IDEOGRAMS:
1184     case UBLOCK_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT:
1185     case UBLOCK_HIRAGANA:
1186     case UBLOCK_KATAKANA:
1187     case UBLOCK_BOPOMOFO:
1188     case UBLOCK_BOPOMOFO_EXTENDED:
1189     case UBLOCK_HANGUL_JAMO:
1190     case UBLOCK_HANGUL_COMPATIBILITY_JAMO:
1191     case UBLOCK_HANGUL_SYLLABLES:
1192     case UBLOCK_HANGUL_JAMO_EXTENDED_A:
1193     case UBLOCK_HANGUL_JAMO_EXTENDED_B:
1194         return GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph;
1195     default:
1196         return GlyphToPathTranslator::GlyphUnderlineType::SkipDescenders;
1197     }
1198 }
1199
1200 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
1201 // standard emphasis marks do so.
1202 Optional<GlyphData> FontCascade::getEmphasisMarkGlyphData(const AtomicString& mark) const
1203 {
1204     if (mark.isEmpty())
1205         return Nullopt;
1206
1207     UChar32 character;
1208     if (!mark.is8Bit()) {
1209         SurrogatePairAwareTextIterator iterator(mark.characters16(), 0, mark.length(), mark.length());
1210         unsigned clusterLength;
1211         if (!iterator.consume(character, clusterLength))
1212             return Nullopt;
1213     } else
1214         character = mark[0];
1215
1216     Optional<GlyphData> glyphData(glyphDataForCharacter(character, false, EmphasisMarkVariant));
1217     return glyphData.value().isValid() ? glyphData : Nullopt;
1218 }
1219
1220 int FontCascade::emphasisMarkAscent(const AtomicString& mark) const
1221 {
1222     Optional<GlyphData> markGlyphData = getEmphasisMarkGlyphData(mark);
1223     if (!markGlyphData)
1224         return 0;
1225
1226     const Font* markFontData = markGlyphData.value().font;
1227     ASSERT(markFontData);
1228     if (!markFontData)
1229         return 0;
1230
1231     return markFontData->fontMetrics().ascent();
1232 }
1233
1234 int FontCascade::emphasisMarkDescent(const AtomicString& mark) const
1235 {
1236     Optional<GlyphData> markGlyphData = getEmphasisMarkGlyphData(mark);
1237     if (!markGlyphData)
1238         return 0;
1239
1240     const Font* markFontData = markGlyphData.value().font;
1241     ASSERT(markFontData);
1242     if (!markFontData)
1243         return 0;
1244
1245     return markFontData->fontMetrics().descent();
1246 }
1247
1248 int FontCascade::emphasisMarkHeight(const AtomicString& mark) const
1249 {
1250     Optional<GlyphData> markGlyphData = getEmphasisMarkGlyphData(mark);
1251     if (!markGlyphData)
1252         return 0;
1253
1254     const Font* markFontData = markGlyphData.value().font;
1255     ASSERT(markFontData);
1256     if (!markFontData)
1257         return 0;
1258
1259     return markFontData->fontMetrics().height();
1260 }
1261
1262 float FontCascade::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
1263 {
1264     float initialAdvance;
1265
1266     WidthIterator it(this, run, 0, false, forTextEmphasis);
1267     // FIXME: Using separate glyph buffers for the prefix and the suffix is incorrect when kerning or
1268     // ligatures are enabled.
1269     GlyphBuffer localGlyphBuffer;
1270     it.advance(from, &localGlyphBuffer);
1271     float beforeWidth = it.m_runWidthSoFar;
1272     it.advance(to, &glyphBuffer);
1273
1274     if (glyphBuffer.isEmpty())
1275         return 0;
1276
1277     float afterWidth = it.m_runWidthSoFar;
1278
1279     if (run.rtl()) {
1280         float finalRoundingWidth = it.m_finalRoundingWidth;
1281         it.advance(run.length(), &localGlyphBuffer);
1282         initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
1283     } else
1284         initialAdvance = beforeWidth;
1285
1286     if (run.rtl())
1287         glyphBuffer.reverse(0, glyphBuffer.size());
1288
1289     return initialAdvance;
1290 }
1291
1292 float FontCascade::drawSimpleText(GraphicsContext& context, const TextRun& run, const FloatPoint& point, int from, int to) const
1293 {
1294     // This glyph buffer holds our glyphs+advances+font data for each glyph.
1295     GlyphBuffer glyphBuffer;
1296
1297     float startX = point.x() + getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer);
1298
1299     if (glyphBuffer.isEmpty())
1300         return 0;
1301
1302     FloatPoint startPoint(startX, point.y());
1303     drawGlyphBuffer(context, run, glyphBuffer, startPoint);
1304
1305     return startPoint.x() - startX;
1306 }
1307
1308 void FontCascade::drawEmphasisMarksForSimpleText(GraphicsContext& context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
1309 {
1310     GlyphBuffer glyphBuffer;
1311     float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis);
1312
1313     if (glyphBuffer.isEmpty())
1314         return;
1315
1316     drawEmphasisMarks(context, run, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
1317 }
1318
1319 void FontCascade::drawGlyphBuffer(GraphicsContext& context, const TextRun& run, const GlyphBuffer& glyphBuffer, FloatPoint& point) const
1320 {
1321 #if !ENABLE(SVG_FONTS)
1322     UNUSED_PARAM(run);
1323 #endif
1324
1325     // Draw each contiguous run of glyphs that use the same font data.
1326     const Font* fontData = glyphBuffer.fontAt(0);
1327     FloatSize offset = glyphBuffer.offsetAt(0);
1328     FloatPoint startPoint(point.x(), point.y() - glyphBuffer.initialAdvance().height());
1329     float nextX = startPoint.x() + glyphBuffer.advanceAt(0).width();
1330     float nextY = startPoint.y() + glyphBuffer.advanceAt(0).height();
1331     int lastFrom = 0;
1332     int nextGlyph = 1;
1333 #if ENABLE(SVG_FONTS)
1334     TextRun::RenderingContext* renderingContext = run.renderingContext();
1335 #endif
1336     while (nextGlyph < glyphBuffer.size()) {
1337         const Font* nextFontData = glyphBuffer.fontAt(nextGlyph);
1338         FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
1339
1340         if (nextFontData != fontData || nextOffset != offset) {
1341 #if ENABLE(SVG_FONTS)
1342             if (renderingContext && fontData->isSVGFont())
1343                 renderingContext->drawSVGGlyphs(context, *fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
1344             else
1345 #endif
1346                 drawGlyphs(context, *fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
1347
1348             lastFrom = nextGlyph;
1349             fontData = nextFontData;
1350             offset = nextOffset;
1351             startPoint.setX(nextX);
1352             startPoint.setY(nextY);
1353         }
1354         nextX += glyphBuffer.advanceAt(nextGlyph).width();
1355         nextY += glyphBuffer.advanceAt(nextGlyph).height();
1356         nextGlyph++;
1357     }
1358
1359 #if ENABLE(SVG_FONTS)
1360     if (renderingContext && fontData->isSVGFont())
1361         renderingContext->drawSVGGlyphs(context, *fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
1362     else
1363 #endif
1364     {
1365         drawGlyphs(context, *fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
1366         point.setX(nextX);
1367     }
1368 }
1369
1370 inline static float offsetToMiddleOfGlyph(const Font* fontData, Glyph glyph)
1371 {
1372     if (fontData->platformData().orientation() == Horizontal) {
1373         FloatRect bounds = fontData->boundsForGlyph(glyph);
1374         return bounds.x() + bounds.width() / 2;
1375     }
1376     // FIXME: Use glyph bounds once they make sense for vertical fonts.
1377     return fontData->widthForGlyph(glyph) / 2;
1378 }
1379
1380 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
1381 {
1382     return offsetToMiddleOfGlyph(glyphBuffer.fontAt(i), glyphBuffer.glyphAt(i));
1383 }
1384
1385 void FontCascade::drawEmphasisMarks(GraphicsContext& context, const TextRun& run, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
1386 {
1387     Optional<GlyphData> markGlyphData = getEmphasisMarkGlyphData(mark);
1388     if (!markGlyphData)
1389         return;
1390
1391     const Font* markFontData = markGlyphData.value().font;
1392     ASSERT(markFontData);
1393     if (!markFontData)
1394         return;
1395
1396     Glyph markGlyph = markGlyphData.value().glyph;
1397     Glyph spaceGlyph = markFontData->spaceGlyph();
1398
1399     float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
1400     FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
1401
1402     GlyphBuffer markBuffer;
1403     for (int i = 0; i + 1 < glyphBuffer.size(); ++i) {
1404         float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1);
1405         float advance = glyphBuffer.advanceAt(i).width() - middleOfLastGlyph + middleOfNextGlyph;
1406         markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
1407         middleOfLastGlyph = middleOfNextGlyph;
1408     }
1409     markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
1410
1411     drawGlyphBuffer(context, run, markBuffer, startPoint);
1412 }
1413
1414 float FontCascade::floatWidthForSimpleText(const TextRun& run, HashSet<const Font*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1415 {
1416     WidthIterator it(this, run, fallbackFonts, glyphOverflow);
1417     GlyphBuffer glyphBuffer;
1418     it.advance(run.length(), (enableKerning() || requiresShaping()) ? &glyphBuffer : nullptr);
1419
1420     if (glyphOverflow) {
1421         glyphOverflow->top = std::max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent()));
1422         glyphOverflow->bottom = std::max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent()));
1423         glyphOverflow->left = ceilf(it.firstGlyphOverflow());
1424         glyphOverflow->right = ceilf(it.lastGlyphOverflow());
1425     }
1426
1427     return it.m_runWidthSoFar;
1428 }
1429
1430 void FontCascade::adjustSelectionRectForSimpleText(const TextRun& run, LayoutRect& selectionRect, int from, int to) const
1431 {
1432     GlyphBuffer glyphBuffer;
1433     WidthIterator it(this, run);
1434     it.advance(from, &glyphBuffer);
1435     float beforeWidth = it.m_runWidthSoFar;
1436     it.advance(to, &glyphBuffer);
1437     float afterWidth = it.m_runWidthSoFar;
1438     float totalWidth = -1;
1439
1440     if (run.rtl()) {
1441         it.advance(run.length(), &glyphBuffer);
1442         totalWidth = it.m_runWidthSoFar;
1443         selectionRect.move(totalWidth - afterWidth, 0);
1444     } else
1445         selectionRect.move(beforeWidth, 0);
1446     selectionRect.setWidth(LayoutUnit::fromFloatCeil(afterWidth - beforeWidth));
1447 }
1448
1449 int FontCascade::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
1450 {
1451     float delta = x;
1452
1453     WidthIterator it(this, run);
1454     GlyphBuffer localGlyphBuffer;
1455     unsigned offset;
1456     if (run.rtl()) {
1457         delta -= floatWidthForSimpleText(run);
1458         while (1) {
1459             offset = it.m_currentCharacter;
1460             float w;
1461             if (!it.advanceOneCharacter(w, localGlyphBuffer))
1462                 break;
1463             delta += w;
1464             if (includePartialGlyphs) {
1465                 if (delta - w / 2 >= 0)
1466                     break;
1467             } else {
1468                 if (delta >= 0)
1469                     break;
1470             }
1471         }
1472     } else {
1473         while (1) {
1474             offset = it.m_currentCharacter;
1475             float w;
1476             if (!it.advanceOneCharacter(w, localGlyphBuffer))
1477                 break;
1478             delta -= w;
1479             if (includePartialGlyphs) {
1480                 if (delta + w / 2 <= 0)
1481                     break;
1482             } else {
1483                 if (delta <= 0)
1484                     break;
1485             }
1486         }
1487     }
1488
1489     return offset;
1490 }
1491
1492
1493 }