[WebGL2] Teach WebGLRenderingContextBase about new texture internal formats
[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, unsigned 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 (unsigned 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 (unsigned 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         ASSERT(count);
991         --count;
992         isAfterExpansion = false;
993     }
994     return std::make_pair(count, isAfterExpansion);
995 }
996
997 std::pair<unsigned, bool> FontCascade::expansionOpportunityCountInternal(const UChar* characters, unsigned length, TextDirection direction, ExpansionBehavior expansionBehavior)
998 {
999     static bool expandAroundIdeographs = canExpandAroundIdeographsInComplexText();
1000     unsigned count = 0;
1001     bool isAfterExpansion = (expansionBehavior & LeadingExpansionMask) == ForbidLeadingExpansion;
1002     if ((expansionBehavior & LeadingExpansionMask) == ForceLeadingExpansion) {
1003         ++count;
1004         isAfterExpansion = true;
1005     }
1006     if (direction == LTR) {
1007         for (unsigned i = 0; i < length; ++i) {
1008             UChar32 character = characters[i];
1009             if (treatAsSpace(character)) {
1010                 count++;
1011                 isAfterExpansion = true;
1012                 continue;
1013             }
1014             if (U16_IS_LEAD(character) && i + 1 < length && U16_IS_TRAIL(characters[i + 1])) {
1015                 character = U16_GET_SUPPLEMENTARY(character, characters[i + 1]);
1016                 i++;
1017             }
1018             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
1019                 if (!isAfterExpansion)
1020                     count++;
1021                 count++;
1022                 isAfterExpansion = true;
1023                 continue;
1024             }
1025             isAfterExpansion = false;
1026         }
1027     } else {
1028         for (unsigned i = length; i > 0; --i) {
1029             UChar32 character = characters[i - 1];
1030             if (treatAsSpace(character)) {
1031                 count++;
1032                 isAfterExpansion = true;
1033                 continue;
1034             }
1035             if (U16_IS_TRAIL(character) && i > 1 && U16_IS_LEAD(characters[i - 2])) {
1036                 character = U16_GET_SUPPLEMENTARY(characters[i - 2], character);
1037                 i--;
1038             }
1039             if (expandAroundIdeographs && isCJKIdeographOrSymbol(character)) {
1040                 if (!isAfterExpansion)
1041                     count++;
1042                 count++;
1043                 isAfterExpansion = true;
1044                 continue;
1045             }
1046             isAfterExpansion = false;
1047         }
1048     }
1049     if (!isAfterExpansion && (expansionBehavior & TrailingExpansionMask) == ForceTrailingExpansion) {
1050         ++count;
1051         isAfterExpansion = true;
1052     } else if (isAfterExpansion && (expansionBehavior & TrailingExpansionMask) == ForbidTrailingExpansion) {
1053         ASSERT(count);
1054         --count;
1055         isAfterExpansion = false;
1056     }
1057     return std::make_pair(count, isAfterExpansion);
1058 }
1059
1060 std::pair<unsigned, bool> FontCascade::expansionOpportunityCount(const StringView& stringView, TextDirection direction, ExpansionBehavior expansionBehavior)
1061 {
1062     // For each character, iterating from left to right:
1063     //   If it is recognized as a space, insert an opportunity after it
1064     //   If it is an ideograph, insert one opportunity before it and one opportunity after it
1065     // Do this such a way so that there are not two opportunities next to each other.
1066     if (stringView.is8Bit())
1067         return expansionOpportunityCountInternal(stringView.characters8(), stringView.length(), direction, expansionBehavior);
1068     return expansionOpportunityCountInternal(stringView.characters16(), stringView.length(), direction, expansionBehavior);
1069 }
1070
1071 bool FontCascade::leadingExpansionOpportunity(const StringView& stringView, TextDirection direction)
1072 {
1073     if (!stringView.length())
1074         return false;
1075
1076     UChar32 initialCharacter;
1077     if (direction == LTR) {
1078         initialCharacter = stringView[0];
1079         if (U16_IS_LEAD(initialCharacter) && stringView.length() > 1 && U16_IS_TRAIL(stringView[1]))
1080             initialCharacter = U16_GET_SUPPLEMENTARY(initialCharacter, stringView[1]);
1081     } else {
1082         initialCharacter = stringView[stringView.length() - 1];
1083         if (U16_IS_TRAIL(initialCharacter) && stringView.length() > 1 && U16_IS_LEAD(stringView[stringView.length() - 2]))
1084             initialCharacter = U16_GET_SUPPLEMENTARY(stringView[stringView.length() - 2], initialCharacter);
1085     }
1086
1087     return canExpandAroundIdeographsInComplexText() && isCJKIdeographOrSymbol(initialCharacter);
1088 }
1089
1090 bool FontCascade::trailingExpansionOpportunity(const StringView& stringView, TextDirection direction)
1091 {
1092     if (!stringView.length())
1093         return false;
1094
1095     UChar32 finalCharacter;
1096     if (direction == LTR) {
1097         finalCharacter = stringView[stringView.length() - 1];
1098         if (U16_IS_TRAIL(finalCharacter) && stringView.length() > 1 && U16_IS_LEAD(stringView[stringView.length() - 2]))
1099             finalCharacter = U16_GET_SUPPLEMENTARY(stringView[stringView.length() - 2], finalCharacter);
1100     } else {
1101         finalCharacter = stringView[0];
1102         if (U16_IS_LEAD(finalCharacter) && stringView.length() > 1 && U16_IS_TRAIL(stringView[1]))
1103             finalCharacter = U16_GET_SUPPLEMENTARY(finalCharacter, stringView[1]);
1104     }
1105
1106     return treatAsSpace(finalCharacter) || (canExpandAroundIdeographsInComplexText() && isCJKIdeographOrSymbol(finalCharacter));
1107 }
1108
1109 bool FontCascade::canReceiveTextEmphasis(UChar32 c)
1110 {
1111     if (U_GET_GC_MASK(c) & (U_GC_Z_MASK | U_GC_CN_MASK | U_GC_CC_MASK | U_GC_CF_MASK))
1112         return false;
1113
1114     // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
1115     if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
1116         || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
1117         return false;
1118
1119     return true;
1120 }
1121
1122 bool FontCascade::isLoadingCustomFonts() const
1123 {
1124     return m_fonts && m_fonts->isLoadingCustomFonts();
1125 }
1126     
1127 GlyphToPathTranslator::GlyphUnderlineType computeUnderlineType(const TextRun& textRun, const GlyphBuffer& glyphBuffer, unsigned index)
1128 {
1129     // In general, we want to skip descenders. However, skipping descenders on CJK characters leads to undesirable renderings,
1130     // so we want to draw through CJK characters (on a character-by-character basis).
1131     UChar32 baseCharacter;
1132     unsigned offsetInString = glyphBuffer.offsetInString(index);
1133
1134     if (offsetInString == GlyphBuffer::noOffset || offsetInString >= textRun.length()) {
1135         // We have no idea which character spawned this glyph. Bail.
1136         ASSERT_WITH_SECURITY_IMPLICATION(offsetInString < textRun.length());
1137         return GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph;
1138     }
1139     
1140     if (textRun.is8Bit())
1141         baseCharacter = textRun.characters8()[offsetInString];
1142     else
1143         U16_NEXT(textRun.characters16(), offsetInString, textRun.length(), baseCharacter);
1144     
1145     // u_getIntPropertyValue with UCHAR_IDEOGRAPHIC doesn't return true for Japanese or Korean codepoints.
1146     // Instead, we can use the "Unicode allocation block" for the character.
1147     UBlockCode blockCode = ublock_getCode(baseCharacter);
1148     switch (blockCode) {
1149     case UBLOCK_CJK_RADICALS_SUPPLEMENT:
1150     case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
1151     case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS:
1152     case UBLOCK_CJK_COMPATIBILITY:
1153     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A:
1154     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS:
1155     case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS:
1156     case UBLOCK_CJK_COMPATIBILITY_FORMS:
1157     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B:
1158     case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT:
1159     case UBLOCK_CJK_STROKES:
1160     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C:
1161     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D:
1162     case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS:
1163     case UBLOCK_LINEAR_B_IDEOGRAMS:
1164     case UBLOCK_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT:
1165     case UBLOCK_HIRAGANA:
1166     case UBLOCK_KATAKANA:
1167     case UBLOCK_BOPOMOFO:
1168     case UBLOCK_BOPOMOFO_EXTENDED:
1169     case UBLOCK_HANGUL_JAMO:
1170     case UBLOCK_HANGUL_COMPATIBILITY_JAMO:
1171     case UBLOCK_HANGUL_SYLLABLES:
1172     case UBLOCK_HANGUL_JAMO_EXTENDED_A:
1173     case UBLOCK_HANGUL_JAMO_EXTENDED_B:
1174         return GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph;
1175     default:
1176         return GlyphToPathTranslator::GlyphUnderlineType::SkipDescenders;
1177     }
1178 }
1179
1180 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
1181 // standard emphasis marks do so.
1182 Optional<GlyphData> FontCascade::getEmphasisMarkGlyphData(const AtomicString& mark) const
1183 {
1184     if (mark.isEmpty())
1185         return Nullopt;
1186
1187     UChar32 character;
1188     if (!mark.is8Bit()) {
1189         SurrogatePairAwareTextIterator iterator(mark.characters16(), 0, mark.length(), mark.length());
1190         unsigned clusterLength;
1191         if (!iterator.consume(character, clusterLength))
1192             return Nullopt;
1193     } else
1194         character = mark[0];
1195
1196     Optional<GlyphData> glyphData(glyphDataForCharacter(character, false, EmphasisMarkVariant));
1197     return glyphData.value().isValid() ? glyphData : Nullopt;
1198 }
1199
1200 int FontCascade::emphasisMarkAscent(const AtomicString& mark) const
1201 {
1202     Optional<GlyphData> markGlyphData = getEmphasisMarkGlyphData(mark);
1203     if (!markGlyphData)
1204         return 0;
1205
1206     const Font* markFontData = markGlyphData.value().font;
1207     ASSERT(markFontData);
1208     if (!markFontData)
1209         return 0;
1210
1211     return markFontData->fontMetrics().ascent();
1212 }
1213
1214 int FontCascade::emphasisMarkDescent(const AtomicString& mark) const
1215 {
1216     Optional<GlyphData> markGlyphData = getEmphasisMarkGlyphData(mark);
1217     if (!markGlyphData)
1218         return 0;
1219
1220     const Font* markFontData = markGlyphData.value().font;
1221     ASSERT(markFontData);
1222     if (!markFontData)
1223         return 0;
1224
1225     return markFontData->fontMetrics().descent();
1226 }
1227
1228 int FontCascade::emphasisMarkHeight(const AtomicString& mark) const
1229 {
1230     Optional<GlyphData> markGlyphData = getEmphasisMarkGlyphData(mark);
1231     if (!markGlyphData)
1232         return 0;
1233
1234     const Font* markFontData = markGlyphData.value().font;
1235     ASSERT(markFontData);
1236     if (!markFontData)
1237         return 0;
1238
1239     return markFontData->fontMetrics().height();
1240 }
1241
1242 float FontCascade::getGlyphsAndAdvancesForSimpleText(const TextRun& run, unsigned from, unsigned to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
1243 {
1244     float initialAdvance;
1245
1246     WidthIterator it(this, run, 0, false, forTextEmphasis);
1247     // FIXME: Using separate glyph buffers for the prefix and the suffix is incorrect when kerning or
1248     // ligatures are enabled.
1249     GlyphBuffer localGlyphBuffer;
1250     it.advance(from, &localGlyphBuffer);
1251     float beforeWidth = it.m_runWidthSoFar;
1252     it.advance(to, &glyphBuffer);
1253
1254     if (glyphBuffer.isEmpty())
1255         return 0;
1256
1257     float afterWidth = it.m_runWidthSoFar;
1258
1259     if (run.rtl()) {
1260         float finalRoundingWidth = it.m_finalRoundingWidth;
1261         it.advance(run.length(), &localGlyphBuffer);
1262         initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
1263     } else
1264         initialAdvance = beforeWidth;
1265
1266     if (run.rtl())
1267         glyphBuffer.reverse(0, glyphBuffer.size());
1268
1269     return initialAdvance;
1270 }
1271
1272 void FontCascade::drawEmphasisMarksForSimpleText(GraphicsContext& context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, unsigned from, unsigned to) const
1273 {
1274     GlyphBuffer glyphBuffer;
1275     float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis);
1276
1277     if (glyphBuffer.isEmpty())
1278         return;
1279
1280     drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
1281 }
1282
1283 void FontCascade::drawGlyphBuffer(GraphicsContext& context, const GlyphBuffer& glyphBuffer, FloatPoint& point) const
1284 {
1285     // Draw each contiguous run of glyphs that use the same font data.
1286     const Font* fontData = glyphBuffer.fontAt(0);
1287     FloatSize offset = glyphBuffer.offsetAt(0);
1288     FloatPoint startPoint(point.x(), point.y() - glyphBuffer.initialAdvance().height());
1289     float nextX = startPoint.x() + glyphBuffer.advanceAt(0).width();
1290     float nextY = startPoint.y() + glyphBuffer.advanceAt(0).height();
1291     unsigned lastFrom = 0;
1292     unsigned nextGlyph = 1;
1293     while (nextGlyph < glyphBuffer.size()) {
1294         const Font* nextFontData = glyphBuffer.fontAt(nextGlyph);
1295         FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
1296
1297         if (nextFontData != fontData || nextOffset != offset) {
1298             context.drawGlyphs(*this, *fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
1299
1300             lastFrom = nextGlyph;
1301             fontData = nextFontData;
1302             offset = nextOffset;
1303             startPoint.setX(nextX);
1304             startPoint.setY(nextY);
1305         }
1306         nextX += glyphBuffer.advanceAt(nextGlyph).width();
1307         nextY += glyphBuffer.advanceAt(nextGlyph).height();
1308         nextGlyph++;
1309     }
1310
1311     context.drawGlyphs(*this, *fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
1312     point.setX(nextX);
1313 }
1314
1315 inline static float offsetToMiddleOfGlyph(const Font* fontData, Glyph glyph)
1316 {
1317     if (fontData->platformData().orientation() == Horizontal) {
1318         FloatRect bounds = fontData->boundsForGlyph(glyph);
1319         return bounds.x() + bounds.width() / 2;
1320     }
1321     // FIXME: Use glyph bounds once they make sense for vertical fonts.
1322     return fontData->widthForGlyph(glyph) / 2;
1323 }
1324
1325 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, unsigned i)
1326 {
1327     return offsetToMiddleOfGlyph(glyphBuffer.fontAt(i), glyphBuffer.glyphAt(i));
1328 }
1329
1330 void FontCascade::drawEmphasisMarks(GraphicsContext& context, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
1331 {
1332     Optional<GlyphData> markGlyphData = getEmphasisMarkGlyphData(mark);
1333     if (!markGlyphData)
1334         return;
1335
1336     const Font* markFontData = markGlyphData.value().font;
1337     ASSERT(markFontData);
1338     if (!markFontData)
1339         return;
1340
1341     Glyph markGlyph = markGlyphData.value().glyph;
1342     Glyph spaceGlyph = markFontData->spaceGlyph();
1343
1344     float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
1345     FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
1346
1347     GlyphBuffer markBuffer;
1348     for (unsigned i = 0; i + 1 < glyphBuffer.size(); ++i) {
1349         float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1);
1350         float advance = glyphBuffer.advanceAt(i).width() - middleOfLastGlyph + middleOfNextGlyph;
1351         markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
1352         middleOfLastGlyph = middleOfNextGlyph;
1353     }
1354     markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
1355
1356     drawGlyphBuffer(context, markBuffer, startPoint);
1357 }
1358
1359 float FontCascade::floatWidthForSimpleText(const TextRun& run, HashSet<const Font*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1360 {
1361     WidthIterator it(this, run, fallbackFonts, glyphOverflow);
1362     GlyphBuffer glyphBuffer;
1363     it.advance(run.length(), (enableKerning() || requiresShaping()) ? &glyphBuffer : nullptr);
1364
1365     if (glyphOverflow) {
1366         glyphOverflow->top = std::max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent()));
1367         glyphOverflow->bottom = std::max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent()));
1368         glyphOverflow->left = ceilf(it.firstGlyphOverflow());
1369         glyphOverflow->right = ceilf(it.lastGlyphOverflow());
1370     }
1371
1372     return it.m_runWidthSoFar;
1373 }
1374
1375 void FontCascade::adjustSelectionRectForSimpleText(const TextRun& run, LayoutRect& selectionRect, unsigned from, unsigned to) const
1376 {
1377     GlyphBuffer glyphBuffer;
1378     WidthIterator it(this, run);
1379     it.advance(from, &glyphBuffer);
1380     float beforeWidth = it.m_runWidthSoFar;
1381     it.advance(to, &glyphBuffer);
1382     float afterWidth = it.m_runWidthSoFar;
1383     float totalWidth = -1;
1384
1385     if (run.rtl()) {
1386         it.advance(run.length(), &glyphBuffer);
1387         totalWidth = it.m_runWidthSoFar;
1388         selectionRect.move(totalWidth - afterWidth, 0);
1389     } else
1390         selectionRect.move(beforeWidth, 0);
1391     selectionRect.setWidth(LayoutUnit::fromFloatCeil(afterWidth - beforeWidth));
1392 }
1393
1394 int FontCascade::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
1395 {
1396     float delta = x;
1397
1398     WidthIterator it(this, run);
1399     GlyphBuffer localGlyphBuffer;
1400     unsigned offset;
1401     if (run.rtl()) {
1402         delta -= floatWidthForSimpleText(run);
1403         while (1) {
1404             offset = it.m_currentCharacter;
1405             float w;
1406             if (!it.advanceOneCharacter(w, localGlyphBuffer))
1407                 break;
1408             delta += w;
1409             if (includePartialGlyphs) {
1410                 if (delta - w / 2 >= 0)
1411                     break;
1412             } else {
1413                 if (delta >= 0)
1414                     break;
1415             }
1416         }
1417     } else {
1418         while (1) {
1419             offset = it.m_currentCharacter;
1420             float w;
1421             if (!it.advanceOneCharacter(w, localGlyphBuffer))
1422                 break;
1423             delta -= w;
1424             if (includePartialGlyphs) {
1425                 if (delta + w / 2 <= 0)
1426                     break;
1427             } else {
1428                 if (delta <= 0)
1429                     break;
1430             }
1431         }
1432     }
1433
1434     return offset;
1435 }
1436
1437
1438 }