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