4380b5c08532e821acaa34ef2cd78b51166a5bb9
[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, int from, int 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, int from, int 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     to = (to == -1 ? run.length() : to);
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 || static_cast<unsigned>(to) != run.length()))
317         codePathToUse = Complex;
318
319     GlyphBuffer glyphBuffer;
320     float startX = point.x() + glyphBufferForTextRun(codePathToUse, run, from, to, 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, int from, int to) const
331 {
332     if (isLoadingCustomFonts())
333         return;
334
335     if (to < 0)
336         to = run.length();
337
338     CodePath codePathToUse = codePath(run);
339     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
340     if (codePathToUse != Complex && (enableKerning() || requiresShaping()) && (from || static_cast<unsigned>(to) != run.length()))
341         codePathToUse = Complex;
342
343     if (codePathToUse != Complex)
344         drawEmphasisMarksForSimpleText(context, run, mark, point, from, to);
345     else
346         drawEmphasisMarksForComplexText(context, run, mark, point, from, to);
347 }
348
349 float FontCascade::width(const TextRun& run, HashSet<const Font*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
350 {
351     CodePath codePathToUse = codePath(run);
352     if (codePathToUse != Complex) {
353         // The complex path is more restrictive about returning fallback fonts than the simple path, so we need an explicit test to make their behaviors match.
354         if (!canReturnFallbackFontsForComplexText())
355             fallbackFonts = nullptr;
356         // The simple path can optimize the case where glyph overflow is not observable.
357         if (codePathToUse != SimpleWithGlyphOverflow && (glyphOverflow && !glyphOverflow->computeBounds))
358             glyphOverflow = nullptr;
359     }
360
361     bool hasWordSpacingOrLetterSpacing = wordSpacing() || letterSpacing();
362     float* cacheEntry = m_fonts->widthCache().add(run, std::numeric_limits<float>::quiet_NaN(), enableKerning() || requiresShaping(), hasWordSpacingOrLetterSpacing, glyphOverflow);
363     if (cacheEntry && !std::isnan(*cacheEntry))
364         return *cacheEntry;
365
366     HashSet<const Font*> localFallbackFonts;
367     if (!fallbackFonts)
368         fallbackFonts = &localFallbackFonts;
369
370     float result;
371     if (codePathToUse == Complex)
372         result = floatWidthForComplexText(run, fallbackFonts, glyphOverflow);
373     else
374         result = floatWidthForSimpleText(run, fallbackFonts, glyphOverflow);
375
376     if (cacheEntry && fallbackFonts->isEmpty())
377         *cacheEntry = result;
378     return result;
379 }
380
381 GlyphData FontCascade::glyphDataForCharacter(UChar32 c, bool mirror, FontVariant variant) const
382 {
383     if (variant == AutoVariant) {
384         if (m_fontDescription.variantCaps() == FontVariantCaps::Small) {
385             UChar32 upperC = u_toupper(c);
386             if (upperC != c) {
387                 c = upperC;
388                 variant = SmallCapsVariant;
389             } else
390                 variant = NormalVariant;
391         } else
392             variant = NormalVariant;
393     }
394
395     if (mirror)
396         c = u_charMirror(c);
397
398     return m_fonts->glyphDataForCharacter(c, m_fontDescription, variant);
399 }
400
401 #if !PLATFORM(COCOA)
402
403 std::unique_ptr<TextLayout, TextLayoutDeleter> FontCascade::createLayout(RenderText&, float, bool) const
404 {
405     return nullptr;
406 }
407
408 void TextLayoutDeleter::operator()(TextLayout*) const
409 {
410 }
411
412 float FontCascade::width(TextLayout&, unsigned, unsigned, HashSet<const Font*>*)
413 {
414     ASSERT_NOT_REACHED();
415     return 0;
416 }
417
418 #endif
419
420 static const char* fontFamiliesWithInvalidCharWidth[] = {
421     "American Typewriter",
422     "Arial Hebrew",
423     "Chalkboard",
424     "Cochin",
425     "Corsiva Hebrew",
426     "Courier",
427     "Euphemia UCAS",
428     "Geneva",
429     "Gill Sans",
430     "Hei",
431     "Helvetica",
432     "Hoefler Text",
433     "InaiMathi",
434     "Kai",
435     "Lucida Grande",
436     "Marker Felt",
437     "Monaco",
438     "Mshtakan",
439     "New Peninim MT",
440     "Osaka",
441     "Raanana",
442     "STHeiti",
443     "Symbol",
444     "Times",
445     "Apple Braille",
446     "Apple LiGothic",
447     "Apple LiSung",
448     "Apple Symbols",
449     "AppleGothic",
450     "AppleMyungjo",
451     "#GungSeo",
452     "#HeadLineA",
453     "#PCMyungjo",
454     "#PilGi",
455 };
456
457 // For font families where any of the fonts don't have a valid entry in the OS/2 table
458 // for avgCharWidth, fallback to the legacy webkit behavior of getting the avgCharWidth
459 // from the width of a '0'. This only seems to apply to a fixed number of Mac fonts,
460 // but, in order to get similar rendering across platforms, we do this check for
461 // all platforms.
462 bool FontCascade::hasValidAverageCharWidth() const
463 {
464     AtomicString family = firstFamily();
465     if (family.isEmpty())
466         return false;
467
468 #if PLATFORM(MAC) || PLATFORM(IOS)
469     // Internal fonts on OS X and iOS also have an invalid entry in the table for avgCharWidth.
470     if (primaryFontIsSystemFont())
471         return false;
472 #endif
473
474     static HashSet<AtomicString>* fontFamiliesWithInvalidCharWidthMap = 0;
475
476     if (!fontFamiliesWithInvalidCharWidthMap) {
477         fontFamiliesWithInvalidCharWidthMap = new HashSet<AtomicString>;
478
479         for (size_t i = 0; i < WTF_ARRAY_LENGTH(fontFamiliesWithInvalidCharWidth); ++i)
480             fontFamiliesWithInvalidCharWidthMap->add(AtomicString(fontFamiliesWithInvalidCharWidth[i]));
481     }
482
483     return !fontFamiliesWithInvalidCharWidthMap->contains(family);
484 }
485
486 bool FontCascade::fastAverageCharWidthIfAvailable(float& width) const
487 {
488     bool success = hasValidAverageCharWidth();
489     if (success)
490         width = roundf(primaryFont().avgCharWidth()); // FIXME: primaryFont() might not correspond to firstFamily().
491     return success;
492 }
493
494 void FontCascade::adjustSelectionRectForText(const TextRun& run, LayoutRect& selectionRect, int from, int to) const
495 {
496     to = (to == -1 ? run.length() : to);
497
498     CodePath codePathToUse = codePath(run);
499     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
500     if (codePathToUse != Complex && (enableKerning() || requiresShaping()) && (from || static_cast<unsigned>(to) != run.length()))
501         codePathToUse = Complex;
502
503     if (codePathToUse != Complex)
504         return adjustSelectionRectForSimpleText(run, selectionRect, from, to);
505
506     return adjustSelectionRectForComplexText(run, selectionRect, from, to);
507 }
508
509 int FontCascade::offsetForPosition(const TextRun& run, float x, bool includePartialGlyphs) const
510 {
511     // FIXME: Use the fast code path once it handles partial runs with kerning and ligatures. See http://webkit.org/b/100050
512     if (codePath(run) != Complex && (!(enableKerning() || requiresShaping())))
513         return offsetForPositionForSimpleText(run, x, includePartialGlyphs);
514
515     return offsetForPositionForComplexText(run, x, includePartialGlyphs);
516 }
517
518 template <typename CharacterType>
519 static inline String normalizeSpacesInternal(const CharacterType* characters, unsigned length)
520 {
521     StringBuilder normalized;
522     normalized.reserveCapacity(length);
523
524     for (unsigned i = 0; i < length; ++i)
525         normalized.append(FontCascade::normalizeSpaces(characters[i]));
526
527     return normalized.toString();
528 }
529
530 String FontCascade::normalizeSpaces(const LChar* characters, unsigned length)
531 {
532     return normalizeSpacesInternal(characters, length);
533 }
534
535 String FontCascade::normalizeSpaces(const UChar* characters, unsigned length)
536 {
537     return normalizeSpacesInternal(characters, length);
538 }
539
540 static bool shouldUseFontSmoothing = true;
541
542 void FontCascade::setShouldUseSmoothing(bool shouldUseSmoothing)
543 {
544     ASSERT(isMainThread());
545     shouldUseFontSmoothing = shouldUseSmoothing;
546 }
547
548 bool FontCascade::shouldUseSmoothing()
549 {
550     return shouldUseFontSmoothing;
551 }
552
553 void FontCascade::setCodePath(CodePath p)
554 {
555     s_codePath = p;
556 }
557
558 FontCascade::CodePath FontCascade::codePath()
559 {
560     return s_codePath;
561 }
562
563 FontCascade::CodePath FontCascade::codePath(const TextRun& run) const
564 {
565     if (s_codePath != Auto)
566         return s_codePath;
567
568 #if PLATFORM(COCOA)
569     // 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.
570     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=150791: @font-face features should also cause this to be complex.
571     if (m_fontDescription.featureSettings().size() > 0 || !m_fontDescription.variantSettings().isAllNormal())
572         return Complex;
573
574 #else
575
576     if (run.length() > 1 && (enableKerning() || requiresShaping()))
577         return Complex;
578 #endif
579
580     if (!run.characterScanForCodePath())
581         return Simple;
582
583     if (run.is8Bit())
584         return Simple;
585
586     // Start from 0 since drawing and highlighting also measure the characters before run->from.
587     return characterRangeCodePath(run.characters16(), run.length());
588 }
589
590 FontCascade::CodePath FontCascade::characterRangeCodePath(const UChar* characters, unsigned len)
591 {
592     // FIXME: Should use a UnicodeSet in ports where ICU is used. Note that we 
593     // can't simply use UnicodeCharacter Property/class because some characters
594     // are not 'combining', but still need to go to the complex path.
595     // Alternatively, we may as well consider binary search over a sorted
596     // list of ranges.
597     CodePath result = Simple;
598     bool previousCharacterIsEmojiGroupCandidate = false;
599     for (unsigned i = 0; i < len; i++) {
600         const UChar c = characters[i];
601         if (c == zeroWidthJoiner && previousCharacterIsEmojiGroupCandidate)
602             return Complex;
603         
604         previousCharacterIsEmojiGroupCandidate = false;
605         if (c < 0x2E5) // U+02E5 through U+02E9 (Modifier Letters : Tone letters)  
606             continue;
607         if (c <= 0x2E9) 
608             return Complex;
609
610         if (c < 0x300) // U+0300 through U+036F Combining diacritical marks
611             continue;
612         if (c <= 0x36F)
613             return Complex;
614
615         if (c < 0x0591 || c == 0x05BE) // U+0591 through U+05CF excluding U+05BE Hebrew combining marks, Hebrew punctuation Paseq, Sof Pasuq and Nun Hafukha
616             continue;
617         if (c <= 0x05CF)
618             return Complex;
619
620         // U+0600 through U+109F Arabic, Syriac, Thaana, NKo, Samaritan, Mandaic,
621         // Devanagari, Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, 
622         // Malayalam, Sinhala, Thai, Lao, Tibetan, Myanmar
623         if (c < 0x0600) 
624             continue;
625         if (c <= 0x109F)
626             return Complex;
627
628         // U+1100 through U+11FF Hangul Jamo (only Ancient Korean should be left here if you precompose;
629         // Modern Korean will be precomposed as a result of step A)
630         if (c < 0x1100)
631             continue;
632         if (c <= 0x11FF)
633             return Complex;
634
635         if (c < 0x135D) // U+135D through U+135F Ethiopic combining marks
636             continue;
637         if (c <= 0x135F)
638             return Complex;
639
640         if (c < 0x1700) // U+1780 through U+18AF Tagalog, Hanunoo, Buhid, Taghanwa,Khmer, Mongolian
641             continue;
642         if (c <= 0x18AF)
643             return Complex;
644
645         if (c < 0x1900) // U+1900 through U+194F Limbu (Unicode 4.0)
646             continue;
647         if (c <= 0x194F)
648             return Complex;
649
650         if (c < 0x1980) // U+1980 through U+19DF New Tai Lue
651             continue;
652         if (c <= 0x19DF)
653             return Complex;
654
655         if (c < 0x1A00) // U+1A00 through U+1CFF Buginese, Tai Tham, Balinese, Batak, Lepcha, Vedic
656             continue;
657         if (c <= 0x1CFF)
658             return Complex;
659
660         if (c < 0x1DC0) // U+1DC0 through U+1DFF Comining diacritical mark supplement
661             continue;
662         if (c <= 0x1DFF)
663             return Complex;
664
665         // U+1E00 through U+2000 characters with diacritics and stacked diacritics
666         if (c <= 0x2000) {
667             result = SimpleWithGlyphOverflow;
668             continue;
669         }
670
671         if (c < 0x20D0) // U+20D0 through U+20FF Combining marks for symbols
672             continue;
673         if (c <= 0x20FF)
674             return Complex;
675
676         if (c < 0x26F9)
677             continue;
678         if (c < 0x26FA)
679             return Complex;
680
681         if (c < 0x2CEF) // U+2CEF through U+2CF1 Combining marks for Coptic
682             continue;
683         if (c <= 0x2CF1)
684             return Complex;
685
686         if (c < 0x302A) // U+302A through U+302F Ideographic and Hangul Tone marks
687             continue;
688         if (c <= 0x302F)
689             return Complex;
690
691         if (c < 0xA67C) // U+A67C through U+A67D Combining marks for old Cyrillic
692             continue;
693         if (c <= 0xA67D)
694             return Complex;
695
696         if (c < 0xA6F0) // U+A6F0 through U+A6F1 Combining mark for Bamum
697             continue;
698         if (c <= 0xA6F1)
699             return Complex;
700
701         // U+A800 through U+ABFF Nagri, Phags-pa, Saurashtra, Devanagari Extended,
702         // Hangul Jamo Ext. A, Javanese, Myanmar Extended A, Tai Viet, Meetei Mayek,
703         if (c < 0xA800) 
704             continue;
705         if (c <= 0xABFF)
706             return Complex;
707
708         if (c < 0xD7B0) // U+D7B0 through U+D7FF Hangul Jamo Ext. B
709             continue;
710         if (c <= 0xD7FF)
711             return Complex;
712
713         if (c <= 0xDBFF) {
714             // High surrogate
715
716             if (i == len - 1)
717                 continue;
718
719             UChar next = characters[++i];
720             if (!U16_IS_TRAIL(next))
721                 continue;
722
723             UChar32 supplementaryCharacter = U16_GET_SUPPLEMENTARY(c, next);
724
725             if (supplementaryCharacter < 0x1F1E6) // U+1F1E6 through U+1F1FF Regional Indicator Symbols
726                 continue;
727             if (supplementaryCharacter <= 0x1F1FF)
728                 return Complex;
729
730             if (isEmojiGroupCandidate(supplementaryCharacter)) {
731                 previousCharacterIsEmojiGroupCandidate = true;
732                 continue;
733             }
734             if (isEmojiFitzpatrickModifier(supplementaryCharacter))
735                 return Complex;
736             if (supplementaryCharacter < 0xE0100) // U+E0100 through U+E01EF Unicode variation selectors.
737                 continue;
738             if (supplementaryCharacter <= 0xE01EF)
739                 return Complex;
740
741             // FIXME: Check for Brahmi (U+11000 block), Kaithi (U+11080 block) and other complex scripts
742             // in plane 1 or higher.
743
744             continue;
745         }
746
747         if (c < 0xFE00) // U+FE00 through U+FE0F Unicode variation selectors
748             continue;
749         if (c <= 0xFE0F)
750             return Complex;
751
752         if (c < 0xFE20) // U+FE20 through U+FE2F Combining half marks
753             continue;
754         if (c <= 0xFE2F)
755             return Complex;
756     }
757     return result;
758 }
759
760 bool FontCascade::isCJKIdeograph(UChar32 c)
761 {
762     // The basic CJK Unified Ideographs block.
763     if (c >= 0x4E00 && c <= 0x9FFF)
764         return true;
765     
766     // CJK Unified Ideographs Extension A.
767     if (c >= 0x3400 && c <= 0x4DBF)
768         return true;
769     
770     // CJK Radicals Supplement.
771     if (c >= 0x2E80 && c <= 0x2EFF)
772         return true;
773     
774     // Kangxi Radicals.
775     if (c >= 0x2F00 && c <= 0x2FDF)
776         return true;
777     
778     // CJK Strokes.
779     if (c >= 0x31C0 && c <= 0x31EF)
780         return true;
781     
782     // CJK Compatibility Ideographs.
783     if (c >= 0xF900 && c <= 0xFAFF)
784         return true;
785
786     // CJK Unified Ideographs Extension B.
787     if (c >= 0x20000 && c <= 0x2A6DF)
788         return true;
789
790     // CJK Unified Ideographs Extension C.
791     if (c >= 0x2A700 && c <= 0x2B73F)
792         return true;
793     
794     // CJK Unified Ideographs Extension D.
795     if (c >= 0x2B740 && c <= 0x2B81F)
796         return true;
797     
798     // CJK Compatibility Ideographs Supplement.
799     if (c >= 0x2F800 && c <= 0x2FA1F)
800         return true;
801
802     return false;
803 }
804
805 bool FontCascade::isCJKIdeographOrSymbol(UChar32 c)
806 {
807     // 0x2C7 Caron, Mandarin Chinese 3rd Tone
808     // 0x2CA Modifier Letter Acute Accent, Mandarin Chinese 2nd Tone
809     // 0x2CB Modifier Letter Grave Access, Mandarin Chinese 4th Tone 
810     // 0x2D9 Dot Above, Mandarin Chinese 5th Tone 
811     if ((c == 0x2C7) || (c == 0x2CA) || (c == 0x2CB) || (c == 0x2D9))
812         return true;
813
814     if ((c == 0x2020) || (c == 0x2021) || (c == 0x2030) || (c == 0x203B) || (c == 0x203C)
815         || (c == 0x2042) || (c == 0x2047) || (c == 0x2048) || (c == 0x2049) || (c == 0x2051)
816         || (c == 0x20DD) || (c == 0x20DE) || (c == 0x2100) || (c == 0x2103) || (c == 0x2105)
817         || (c == 0x2109) || (c == 0x210A) || (c == 0x2113) || (c == 0x2116) || (c == 0x2121)
818         || (c == 0x212B) || (c == 0x213B) || (c == 0x2150) || (c == 0x2151) || (c == 0x2152))
819         return true;
820
821     if (c >= 0x2156 && c <= 0x215A)
822         return true;
823
824     if (c >= 0x2160 && c <= 0x216B)
825         return true;
826
827     if (c >= 0x2170 && c <= 0x217B)
828         return true;
829
830     if ((c == 0x217F) || (c == 0x2189) || (c == 0x2307) || (c == 0x2312) || (c == 0x23BE) || (c == 0x23BF))
831         return true;
832
833     if (c >= 0x23C0 && c <= 0x23CC)
834         return true;
835
836     if ((c == 0x23CE) || (c == 0x2423))
837         return true;
838
839     if (c >= 0x2460 && c <= 0x2492)
840         return true;
841
842     if (c >= 0x249C && c <= 0x24FF)
843         return true;
844
845     if ((c == 0x25A0) || (c == 0x25A1) || (c == 0x25A2) || (c == 0x25AA) || (c == 0x25AB))
846         return true;
847
848     if ((c == 0x25B1) || (c == 0x25B2) || (c == 0x25B3) || (c == 0x25B6) || (c == 0x25B7) || (c == 0x25BC) || (c == 0x25BD))
849         return true;
850     
851     if ((c == 0x25C0) || (c == 0x25C1) || (c == 0x25C6) || (c == 0x25C7) || (c == 0x25C9) || (c == 0x25CB) || (c == 0x25CC))
852         return true;
853
854     if (c >= 0x25CE && c <= 0x25D3)
855         return true;
856
857     if (c >= 0x25E2 && c <= 0x25E6)
858         return true;
859
860     if (c == 0x25EF)
861         return true;
862
863     if (c >= 0x2600 && c <= 0x2603)
864         return true;
865
866     if ((c == 0x2605) || (c == 0x2606) || (c == 0x260E) || (c == 0x2616) || (c == 0x2617) || (c == 0x2640) || (c == 0x2642))
867         return true;
868
869     if (c >= 0x2660 && c <= 0x266F)
870         return true;
871
872     if (c >= 0x2672 && c <= 0x267D)
873         return true;
874
875     if ((c == 0x26A0) || (c == 0x26BD) || (c == 0x26BE) || (c == 0x2713) || (c == 0x271A) || (c == 0x273F) || (c == 0x2740) || (c == 0x2756))
876         return true;
877
878     if (c >= 0x2776 && c <= 0x277F)
879         return true;
880
881     if (c == 0x2B1A)
882         return true;
883
884     // Ideographic Description Characters.
885     if (c >= 0x2FF0 && c <= 0x2FFF)
886         return true;
887
888     // CJK Symbols and Punctuation, excluding 0x3030.
889     if (c >= 0x3000 && c < 0x3030)
890         return true;
891
892     if (c > 0x3030 && c <= 0x303F)
893         return true;
894
895     // Hiragana
896     if (c >= 0x3040 && c <= 0x309F)
897         return true;
898
899     // Katakana 
900     if (c >= 0x30A0 && c <= 0x30FF)
901         return true;
902
903     // Bopomofo
904     if (c >= 0x3100 && c <= 0x312F)
905         return true;
906
907     if (c >= 0x3190 && c <= 0x319F)
908         return true;
909
910     // Bopomofo Extended
911     if (c >= 0x31A0 && c <= 0x31BF)
912         return true;
913
914     // Enclosed CJK Letters and Months.
915     if (c >= 0x3200 && c <= 0x32FF)
916         return true;
917     
918     // CJK Compatibility.
919     if (c >= 0x3300 && c <= 0x33FF)
920         return true;
921
922     if (c >= 0xF860 && c <= 0xF862)
923         return true;
924
925     // CJK Compatibility Forms.
926     if (c >= 0xFE30 && c <= 0xFE4F)
927         return true;
928
929     if ((c == 0xFE10) || (c == 0xFE11) || (c == 0xFE12) || (c == 0xFE19))
930         return true;
931
932     if ((c == 0xFF0D) || (c == 0xFF1B) || (c == 0xFF1C) || (c == 0xFF1E))
933         return false;
934
935     // Halfwidth and Fullwidth Forms
936     // Usually only used in CJK
937     if (c >= 0xFF00 && c <= 0xFFEF)
938         return true;
939
940     // Emoji.
941     if (c == 0x1F100)
942         return true;
943
944     if (c >= 0x1F110 && c <= 0x1F129)
945         return true;
946
947     if (c >= 0x1F130 && c <= 0x1F149)
948         return true;
949
950     if (c >= 0x1F150 && c <= 0x1F169)
951         return true;
952
953     if (c >= 0x1F170 && c <= 0x1F189)
954         return true;
955
956     if (c >= 0x1F200 && c <= 0x1F6C5)
957         return true;
958
959     return isCJKIdeograph(c);
960 }
961
962 std::pair<unsigned, bool> FontCascade::expansionOpportunityCountInternal(const LChar* characters, size_t length, TextDirection direction, ExpansionBehavior expansionBehavior)
963 {
964     unsigned count = 0;
965     bool isAfterExpansion = (expansionBehavior & LeadingExpansionMask) == ForbidLeadingExpansion;
966     if ((expansionBehavior & LeadingExpansionMask) == ForceLeadingExpansion) {
967         ++count;
968         isAfterExpansion = true;
969     }
970     if (direction == LTR) {
971         for (size_t i = 0; i < length; ++i) {
972             if (treatAsSpace(characters[i])) {
973                 count++;
974                 isAfterExpansion = true;
975             } else
976                 isAfterExpansion = false;
977         }
978     } else {
979         for (size_t i = length; i > 0; --i) {
980             if (treatAsSpace(characters[i - 1])) {
981                 count++;
982                 isAfterExpansion = true;
983             } else
984                 isAfterExpansion = false;
985         }
986     }
987     if (!isAfterExpansion && (expansionBehavior & TrailingExpansionMask) == ForceTrailingExpansion) {
988         ++count;
989         isAfterExpansion = true;
990     } else if (isAfterExpansion && (expansionBehavior & TrailingExpansionMask) == ForbidTrailingExpansion) {
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, size_t 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 (size_t 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 (size_t 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         --count;
1054         isAfterExpansion = false;
1055     }
1056     return std::make_pair(count, isAfterExpansion);
1057 }
1058
1059 std::pair<unsigned, bool> FontCascade::expansionOpportunityCount(const StringView& stringView, TextDirection direction, ExpansionBehavior expansionBehavior)
1060 {
1061     // For each character, iterating from left to right:
1062     //   If it is recognized as a space, insert an opportunity after it
1063     //   If it is an ideograph, insert one opportunity before it and one opportunity after it
1064     // Do this such a way so that there are not two opportunities next to each other.
1065     if (stringView.is8Bit())
1066         return expansionOpportunityCountInternal(stringView.characters8(), stringView.length(), direction, expansionBehavior);
1067     return expansionOpportunityCountInternal(stringView.characters16(), stringView.length(), direction, expansionBehavior);
1068 }
1069
1070 bool FontCascade::leadingExpansionOpportunity(const StringView& stringView, TextDirection direction)
1071 {
1072     if (!stringView.length())
1073         return false;
1074
1075     UChar32 initialCharacter;
1076     if (direction == LTR) {
1077         initialCharacter = stringView[0];
1078         if (U16_IS_LEAD(initialCharacter) && stringView.length() > 1 && U16_IS_TRAIL(stringView[1]))
1079             initialCharacter = U16_GET_SUPPLEMENTARY(initialCharacter, stringView[1]);
1080     } else {
1081         initialCharacter = stringView[stringView.length() - 1];
1082         if (U16_IS_TRAIL(initialCharacter) && stringView.length() > 1 && U16_IS_LEAD(stringView[stringView.length() - 2]))
1083             initialCharacter = U16_GET_SUPPLEMENTARY(stringView[stringView.length() - 2], initialCharacter);
1084     }
1085
1086     return canExpandAroundIdeographsInComplexText() && isCJKIdeographOrSymbol(initialCharacter);
1087 }
1088
1089 bool FontCascade::trailingExpansionOpportunity(const StringView& stringView, TextDirection direction)
1090 {
1091     if (!stringView.length())
1092         return false;
1093
1094     UChar32 finalCharacter;
1095     if (direction == LTR) {
1096         finalCharacter = stringView[stringView.length() - 1];
1097         if (U16_IS_TRAIL(finalCharacter) && stringView.length() > 1 && U16_IS_LEAD(stringView[stringView.length() - 2]))
1098             finalCharacter = U16_GET_SUPPLEMENTARY(stringView[stringView.length() - 2], finalCharacter);
1099     } else {
1100         finalCharacter = stringView[0];
1101         if (U16_IS_LEAD(finalCharacter) && stringView.length() > 1 && U16_IS_TRAIL(stringView[1]))
1102             finalCharacter = U16_GET_SUPPLEMENTARY(finalCharacter, stringView[1]);
1103     }
1104
1105     return treatAsSpace(finalCharacter) || (canExpandAroundIdeographsInComplexText() && isCJKIdeographOrSymbol(finalCharacter));
1106 }
1107
1108 bool FontCascade::canReceiveTextEmphasis(UChar32 c)
1109 {
1110     if (U_GET_GC_MASK(c) & (U_GC_Z_MASK | U_GC_CN_MASK | U_GC_CC_MASK | U_GC_CF_MASK))
1111         return false;
1112
1113     // Additional word-separator characters listed in CSS Text Level 3 Editor's Draft 3 November 2010.
1114     if (c == ethiopicWordspace || c == aegeanWordSeparatorLine || c == aegeanWordSeparatorDot
1115         || c == ugariticWordDivider || c == tibetanMarkIntersyllabicTsheg || c == tibetanMarkDelimiterTshegBstar)
1116         return false;
1117
1118     return true;
1119 }
1120
1121 bool FontCascade::isLoadingCustomFonts() const
1122 {
1123     return m_fonts && m_fonts->isLoadingCustomFonts();
1124 }
1125     
1126 GlyphToPathTranslator::GlyphUnderlineType computeUnderlineType(const TextRun& textRun, const GlyphBuffer& glyphBuffer, int index)
1127 {
1128     // In general, we want to skip descenders. However, skipping descenders on CJK characters leads to undesirable renderings,
1129     // so we want to draw through CJK characters (on a character-by-character basis).
1130     UChar32 baseCharacter;
1131     unsigned offsetInString = glyphBuffer.offsetInString(index);
1132
1133     if (offsetInString == GlyphBuffer::noOffset || offsetInString >= textRun.length()) {
1134         // We have no idea which character spawned this glyph. Bail.
1135         ASSERT_WITH_SECURITY_IMPLICATION(offsetInString < textRun.length());
1136         return GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph;
1137     }
1138     
1139     if (textRun.is8Bit())
1140         baseCharacter = textRun.characters8()[offsetInString];
1141     else
1142         U16_NEXT(textRun.characters16(), offsetInString, textRun.length(), baseCharacter);
1143     
1144     // u_getIntPropertyValue with UCHAR_IDEOGRAPHIC doesn't return true for Japanese or Korean codepoints.
1145     // Instead, we can use the "Unicode allocation block" for the character.
1146     UBlockCode blockCode = ublock_getCode(baseCharacter);
1147     switch (blockCode) {
1148     case UBLOCK_CJK_RADICALS_SUPPLEMENT:
1149     case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION:
1150     case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS:
1151     case UBLOCK_CJK_COMPATIBILITY:
1152     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A:
1153     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS:
1154     case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS:
1155     case UBLOCK_CJK_COMPATIBILITY_FORMS:
1156     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B:
1157     case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT:
1158     case UBLOCK_CJK_STROKES:
1159     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C:
1160     case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D:
1161     case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS:
1162     case UBLOCK_LINEAR_B_IDEOGRAMS:
1163     case UBLOCK_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT:
1164     case UBLOCK_HIRAGANA:
1165     case UBLOCK_KATAKANA:
1166     case UBLOCK_BOPOMOFO:
1167     case UBLOCK_BOPOMOFO_EXTENDED:
1168     case UBLOCK_HANGUL_JAMO:
1169     case UBLOCK_HANGUL_COMPATIBILITY_JAMO:
1170     case UBLOCK_HANGUL_SYLLABLES:
1171     case UBLOCK_HANGUL_JAMO_EXTENDED_A:
1172     case UBLOCK_HANGUL_JAMO_EXTENDED_B:
1173         return GlyphToPathTranslator::GlyphUnderlineType::DrawOverGlyph;
1174     default:
1175         return GlyphToPathTranslator::GlyphUnderlineType::SkipDescenders;
1176     }
1177 }
1178
1179 // FIXME: This function may not work if the emphasis mark uses a complex script, but none of the
1180 // standard emphasis marks do so.
1181 Optional<GlyphData> FontCascade::getEmphasisMarkGlyphData(const AtomicString& mark) const
1182 {
1183     if (mark.isEmpty())
1184         return Nullopt;
1185
1186     UChar32 character;
1187     if (!mark.is8Bit()) {
1188         SurrogatePairAwareTextIterator iterator(mark.characters16(), 0, mark.length(), mark.length());
1189         unsigned clusterLength;
1190         if (!iterator.consume(character, clusterLength))
1191             return Nullopt;
1192     } else
1193         character = mark[0];
1194
1195     Optional<GlyphData> glyphData(glyphDataForCharacter(character, false, EmphasisMarkVariant));
1196     return glyphData.value().isValid() ? glyphData : Nullopt;
1197 }
1198
1199 int FontCascade::emphasisMarkAscent(const AtomicString& mark) const
1200 {
1201     Optional<GlyphData> markGlyphData = getEmphasisMarkGlyphData(mark);
1202     if (!markGlyphData)
1203         return 0;
1204
1205     const Font* markFontData = markGlyphData.value().font;
1206     ASSERT(markFontData);
1207     if (!markFontData)
1208         return 0;
1209
1210     return markFontData->fontMetrics().ascent();
1211 }
1212
1213 int FontCascade::emphasisMarkDescent(const AtomicString& mark) const
1214 {
1215     Optional<GlyphData> markGlyphData = getEmphasisMarkGlyphData(mark);
1216     if (!markGlyphData)
1217         return 0;
1218
1219     const Font* markFontData = markGlyphData.value().font;
1220     ASSERT(markFontData);
1221     if (!markFontData)
1222         return 0;
1223
1224     return markFontData->fontMetrics().descent();
1225 }
1226
1227 int FontCascade::emphasisMarkHeight(const AtomicString& mark) const
1228 {
1229     Optional<GlyphData> markGlyphData = getEmphasisMarkGlyphData(mark);
1230     if (!markGlyphData)
1231         return 0;
1232
1233     const Font* markFontData = markGlyphData.value().font;
1234     ASSERT(markFontData);
1235     if (!markFontData)
1236         return 0;
1237
1238     return markFontData->fontMetrics().height();
1239 }
1240
1241 float FontCascade::getGlyphsAndAdvancesForSimpleText(const TextRun& run, int from, int to, GlyphBuffer& glyphBuffer, ForTextEmphasisOrNot forTextEmphasis) const
1242 {
1243     float initialAdvance;
1244
1245     WidthIterator it(this, run, 0, false, forTextEmphasis);
1246     // FIXME: Using separate glyph buffers for the prefix and the suffix is incorrect when kerning or
1247     // ligatures are enabled.
1248     GlyphBuffer localGlyphBuffer;
1249     it.advance(from, &localGlyphBuffer);
1250     float beforeWidth = it.m_runWidthSoFar;
1251     it.advance(to, &glyphBuffer);
1252
1253     if (glyphBuffer.isEmpty())
1254         return 0;
1255
1256     float afterWidth = it.m_runWidthSoFar;
1257
1258     if (run.rtl()) {
1259         float finalRoundingWidth = it.m_finalRoundingWidth;
1260         it.advance(run.length(), &localGlyphBuffer);
1261         initialAdvance = finalRoundingWidth + it.m_runWidthSoFar - afterWidth;
1262     } else
1263         initialAdvance = beforeWidth;
1264
1265     if (run.rtl())
1266         glyphBuffer.reverse(0, glyphBuffer.size());
1267
1268     return initialAdvance;
1269 }
1270
1271 void FontCascade::drawEmphasisMarksForSimpleText(GraphicsContext& context, const TextRun& run, const AtomicString& mark, const FloatPoint& point, int from, int to) const
1272 {
1273     GlyphBuffer glyphBuffer;
1274     float initialAdvance = getGlyphsAndAdvancesForSimpleText(run, from, to, glyphBuffer, ForTextEmphasis);
1275
1276     if (glyphBuffer.isEmpty())
1277         return;
1278
1279     drawEmphasisMarks(context, glyphBuffer, mark, FloatPoint(point.x() + initialAdvance, point.y()));
1280 }
1281
1282 void FontCascade::drawGlyphBuffer(GraphicsContext& context, const GlyphBuffer& glyphBuffer, FloatPoint& point) const
1283 {
1284     // Draw each contiguous run of glyphs that use the same font data.
1285     const Font* fontData = glyphBuffer.fontAt(0);
1286     FloatSize offset = glyphBuffer.offsetAt(0);
1287     FloatPoint startPoint(point.x(), point.y() - glyphBuffer.initialAdvance().height());
1288     float nextX = startPoint.x() + glyphBuffer.advanceAt(0).width();
1289     float nextY = startPoint.y() + glyphBuffer.advanceAt(0).height();
1290     int lastFrom = 0;
1291     int nextGlyph = 1;
1292     while (nextGlyph < glyphBuffer.size()) {
1293         const Font* nextFontData = glyphBuffer.fontAt(nextGlyph);
1294         FloatSize nextOffset = glyphBuffer.offsetAt(nextGlyph);
1295
1296         if (nextFontData != fontData || nextOffset != offset) {
1297             context.drawGlyphs(*this, *fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
1298
1299             lastFrom = nextGlyph;
1300             fontData = nextFontData;
1301             offset = nextOffset;
1302             startPoint.setX(nextX);
1303             startPoint.setY(nextY);
1304         }
1305         nextX += glyphBuffer.advanceAt(nextGlyph).width();
1306         nextY += glyphBuffer.advanceAt(nextGlyph).height();
1307         nextGlyph++;
1308     }
1309
1310     context.drawGlyphs(*this, *fontData, glyphBuffer, lastFrom, nextGlyph - lastFrom, startPoint);
1311     point.setX(nextX);
1312 }
1313
1314 inline static float offsetToMiddleOfGlyph(const Font* fontData, Glyph glyph)
1315 {
1316     if (fontData->platformData().orientation() == Horizontal) {
1317         FloatRect bounds = fontData->boundsForGlyph(glyph);
1318         return bounds.x() + bounds.width() / 2;
1319     }
1320     // FIXME: Use glyph bounds once they make sense for vertical fonts.
1321     return fontData->widthForGlyph(glyph) / 2;
1322 }
1323
1324 inline static float offsetToMiddleOfGlyphAtIndex(const GlyphBuffer& glyphBuffer, size_t i)
1325 {
1326     return offsetToMiddleOfGlyph(glyphBuffer.fontAt(i), glyphBuffer.glyphAt(i));
1327 }
1328
1329 void FontCascade::drawEmphasisMarks(GraphicsContext& context, const GlyphBuffer& glyphBuffer, const AtomicString& mark, const FloatPoint& point) const
1330 {
1331     Optional<GlyphData> markGlyphData = getEmphasisMarkGlyphData(mark);
1332     if (!markGlyphData)
1333         return;
1334
1335     const Font* markFontData = markGlyphData.value().font;
1336     ASSERT(markFontData);
1337     if (!markFontData)
1338         return;
1339
1340     Glyph markGlyph = markGlyphData.value().glyph;
1341     Glyph spaceGlyph = markFontData->spaceGlyph();
1342
1343     float middleOfLastGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, 0);
1344     FloatPoint startPoint(point.x() + middleOfLastGlyph - offsetToMiddleOfGlyph(markFontData, markGlyph), point.y());
1345
1346     GlyphBuffer markBuffer;
1347     for (int i = 0; i + 1 < glyphBuffer.size(); ++i) {
1348         float middleOfNextGlyph = offsetToMiddleOfGlyphAtIndex(glyphBuffer, i + 1);
1349         float advance = glyphBuffer.advanceAt(i).width() - middleOfLastGlyph + middleOfNextGlyph;
1350         markBuffer.add(glyphBuffer.glyphAt(i) ? markGlyph : spaceGlyph, markFontData, advance);
1351         middleOfLastGlyph = middleOfNextGlyph;
1352     }
1353     markBuffer.add(glyphBuffer.glyphAt(glyphBuffer.size() - 1) ? markGlyph : spaceGlyph, markFontData, 0);
1354
1355     drawGlyphBuffer(context, markBuffer, startPoint);
1356 }
1357
1358 float FontCascade::floatWidthForSimpleText(const TextRun& run, HashSet<const Font*>* fallbackFonts, GlyphOverflow* glyphOverflow) const
1359 {
1360     WidthIterator it(this, run, fallbackFonts, glyphOverflow);
1361     GlyphBuffer glyphBuffer;
1362     it.advance(run.length(), (enableKerning() || requiresShaping()) ? &glyphBuffer : nullptr);
1363
1364     if (glyphOverflow) {
1365         glyphOverflow->top = std::max<int>(glyphOverflow->top, ceilf(-it.minGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().ascent()));
1366         glyphOverflow->bottom = std::max<int>(glyphOverflow->bottom, ceilf(it.maxGlyphBoundingBoxY()) - (glyphOverflow->computeBounds ? 0 : fontMetrics().descent()));
1367         glyphOverflow->left = ceilf(it.firstGlyphOverflow());
1368         glyphOverflow->right = ceilf(it.lastGlyphOverflow());
1369     }
1370
1371     return it.m_runWidthSoFar;
1372 }
1373
1374 void FontCascade::adjustSelectionRectForSimpleText(const TextRun& run, LayoutRect& selectionRect, int from, int to) const
1375 {
1376     GlyphBuffer glyphBuffer;
1377     WidthIterator it(this, run);
1378     it.advance(from, &glyphBuffer);
1379     float beforeWidth = it.m_runWidthSoFar;
1380     it.advance(to, &glyphBuffer);
1381     float afterWidth = it.m_runWidthSoFar;
1382     float totalWidth = -1;
1383
1384     if (run.rtl()) {
1385         it.advance(run.length(), &glyphBuffer);
1386         totalWidth = it.m_runWidthSoFar;
1387         selectionRect.move(totalWidth - afterWidth, 0);
1388     } else
1389         selectionRect.move(beforeWidth, 0);
1390     selectionRect.setWidth(LayoutUnit::fromFloatCeil(afterWidth - beforeWidth));
1391 }
1392
1393 int FontCascade::offsetForPositionForSimpleText(const TextRun& run, float x, bool includePartialGlyphs) const
1394 {
1395     float delta = x;
1396
1397     WidthIterator it(this, run);
1398     GlyphBuffer localGlyphBuffer;
1399     unsigned offset;
1400     if (run.rtl()) {
1401         delta -= floatWidthForSimpleText(run);
1402         while (1) {
1403             offset = it.m_currentCharacter;
1404             float w;
1405             if (!it.advanceOneCharacter(w, localGlyphBuffer))
1406                 break;
1407             delta += w;
1408             if (includePartialGlyphs) {
1409                 if (delta - w / 2 >= 0)
1410                     break;
1411             } else {
1412                 if (delta >= 0)
1413                     break;
1414             }
1415         }
1416     } else {
1417         while (1) {
1418             offset = it.m_currentCharacter;
1419             float w;
1420             if (!it.advanceOneCharacter(w, localGlyphBuffer))
1421                 break;
1422             delta -= w;
1423             if (includePartialGlyphs) {
1424                 if (delta + w / 2 <= 0)
1425                     break;
1426             } else {
1427                 if (delta <= 0)
1428                     break;
1429             }
1430         }
1431     }
1432
1433     return offset;
1434 }
1435
1436
1437 }