REGRESSION(r239915): [FreeType] White space skipped when rendering plain text with...
[WebKit-https.git] / Source / WebCore / platform / graphics / Font.cpp
1 /*
2  * Copyright (C) 2005, 2008, 2010, 2015 Apple Inc. All rights reserved.
3  * Copyright (C) 2006 Alexey Proskuryakov
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer. 
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution. 
14  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission. 
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "Font.h"
32
33 #if PLATFORM(COCOA)
34 #include <pal/spi/cocoa/CoreTextSPI.h>
35 #endif
36 #include "FontCache.h"
37 #include "FontCascade.h"
38 #include "OpenTypeMathData.h"
39 #include <wtf/MathExtras.h>
40 #include <wtf/NeverDestroyed.h>
41 #include <wtf/text/AtomicStringHash.h>
42
43 #if ENABLE(OPENTYPE_VERTICAL)
44 #include "OpenTypeVerticalData.h"
45 #endif
46
47 #if USE(DIRECT2D)
48 #include <dwrite.h>
49 #endif
50
51 namespace WebCore {
52
53 unsigned GlyphPage::s_count = 0;
54
55 const float smallCapsFontSizeMultiplier = 0.7f;
56 const float emphasisMarkFontSizeMultiplier = 0.5f;
57
58 Font::Font(const FontPlatformData& platformData, Origin origin, Interstitial interstitial, Visibility visibility, OrientationFallback orientationFallback)
59     : m_platformData(platformData)
60     , m_origin(origin)
61     , m_visibility(visibility)
62     , m_treatAsFixedPitch(false)
63     , m_isInterstitial(interstitial == Interstitial::Yes)
64     , m_isTextOrientationFallback(orientationFallback == OrientationFallback::Yes)
65     , m_isBrokenIdeographFallback(false)
66     , m_hasVerticalGlyphs(false)
67     , m_isUsedInSystemFallbackCache(false)
68 #if PLATFORM(IOS_FAMILY)
69     , m_shouldNotBeUsedForArabic(false)
70 #endif
71 {
72     platformInit();
73     platformGlyphInit();
74     platformCharWidthInit();
75 #if ENABLE(OPENTYPE_VERTICAL)
76     if (platformData.orientation() == FontOrientation::Vertical && orientationFallback == OrientationFallback::No) {
77         m_verticalData = FontCache::singleton().verticalData(platformData);
78         m_hasVerticalGlyphs = m_verticalData.get() && m_verticalData->hasVerticalMetrics();
79     }
80 #endif
81 }
82
83 // Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font.
84 void Font::initCharWidths()
85 {
86     auto* glyphPageZero = glyphPage(GlyphPage::pageNumberForCodePoint('0'));
87
88     // Treat the width of a '0' as the avgCharWidth.
89     if (m_avgCharWidth <= 0.f && glyphPageZero) {
90         Glyph digitZeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph;
91         if (digitZeroGlyph)
92             m_avgCharWidth = widthForGlyph(digitZeroGlyph);
93     }
94
95     // If we can't retrieve the width of a '0', fall back to the x height.
96     if (m_avgCharWidth <= 0.f)
97         m_avgCharWidth = m_fontMetrics.xHeight();
98
99     if (m_maxCharWidth <= 0.f)
100         m_maxCharWidth = std::max(m_avgCharWidth, m_fontMetrics.floatAscent());
101 }
102
103 void Font::platformGlyphInit()
104 {
105 #if USE(FREETYPE)
106     auto* glyphPageZeroWidthSpace = glyphPage(GlyphPage::pageNumberForCodePoint(zeroWidthSpace));
107     UChar32 zeroWidthSpaceCharacter = zeroWidthSpace;
108 #else
109     // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0,
110     // are mapped to the ZERO WIDTH SPACE glyph for non FreeType based ports.
111     auto* glyphPageZeroWidthSpace = glyphPage(0);
112     UChar32 zeroWidthSpaceCharacter = 0;
113 #endif
114     auto* glyphPageCharacterZero = glyphPage(GlyphPage::pageNumberForCodePoint('0'));
115     auto* glyphPageSpace = glyphPage(GlyphPage::pageNumberForCodePoint(space));
116
117     if (glyphPageZeroWidthSpace)
118         m_zeroWidthSpaceGlyph = glyphPageZeroWidthSpace->glyphDataForCharacter(zeroWidthSpaceCharacter).glyph;
119
120     // Nasty hack to determine if we should round or ceil space widths.
121     // If the font is monospace or fake monospace we ceil to ensure that 
122     // every character and the space are the same width. Otherwise we round.
123     if (glyphPageSpace)
124         m_spaceGlyph = glyphPageSpace->glyphDataForCharacter(space).glyph;
125     float width = widthForGlyph(m_spaceGlyph);
126     m_spaceWidth = width;
127     if (glyphPageCharacterZero)
128         m_zeroGlyph = glyphPageCharacterZero->glyphDataForCharacter('0').glyph;
129     m_fontMetrics.setZeroWidth(widthForGlyph(m_zeroGlyph));
130     determinePitch();
131     m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width);
132
133     // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is shared with SPACE.
134     // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph.
135     // See <http://bugs.webkit.org/show_bug.cgi?id=13178> and Font::isZeroWidthSpaceGlyph()
136     if (m_zeroWidthSpaceGlyph == m_spaceGlyph)
137         m_zeroWidthSpaceGlyph = 0;
138 }
139
140 Font::~Font()
141 {
142     removeFromSystemFallbackCache();
143 }
144
145 static bool fillGlyphPage(GlyphPage& pageToFill, UChar* buffer, unsigned bufferLength, const Font& font)
146 {
147     bool hasGlyphs = pageToFill.fill(buffer, bufferLength);
148 #if ENABLE(OPENTYPE_VERTICAL)
149     if (hasGlyphs && font.verticalData())
150         font.verticalData()->substituteWithVerticalGlyphs(&font, &pageToFill);
151 #else
152     UNUSED_PARAM(font);
153 #endif
154     return hasGlyphs;
155 }
156
157 static Optional<size_t> codePointSupportIndex(UChar32 codePoint)
158 {
159     // FIXME: Consider reordering these so the most common ones are at the front.
160     // Doing this could cause the BitVector to fit inside inline storage and therefore
161     // be both a performance and a memory progression.
162     if (codePoint < 0x20)
163         return codePoint;
164     if (codePoint >= 0x7F && codePoint < 0xA0)
165         return codePoint - 0x7F + 0x20;
166     Optional<size_t> result;
167     switch (codePoint) {
168     case softHyphen:
169         result = 0x41;
170         break;
171     case newlineCharacter:
172         result = 0x42;
173         break;
174     case tabCharacter:
175         result = 0x43;
176         break;
177     case noBreakSpace:
178         result = 0x44;
179         break;
180     case narrowNoBreakSpace:
181         result = 0x45;
182         break;
183     case leftToRightMark:
184         result = 0x46;
185         break;
186     case rightToLeftMark:
187         result = 0x47;
188         break;
189     case leftToRightEmbed:
190         result = 0x48;
191         break;
192     case rightToLeftEmbed:
193         result = 0x49;
194         break;
195     case leftToRightOverride:
196         result = 0x4A;
197         break;
198     case rightToLeftOverride:
199         result = 0x4B;
200         break;
201     case leftToRightIsolate:
202         result = 0x4C;
203         break;
204     case rightToLeftIsolate:
205         result = 0x4D;
206         break;
207     case zeroWidthNonJoiner:
208         result = 0x4E;
209         break;
210     case zeroWidthJoiner:
211         result = 0x4F;
212         break;
213     case popDirectionalFormatting:
214         result = 0x50;
215         break;
216     case popDirectionalIsolate:
217         result = 0x51;
218         break;
219     case firstStrongIsolate:
220         result = 0x52;
221         break;
222     case objectReplacementCharacter:
223         result = 0x53;
224         break;
225     case zeroWidthNoBreakSpace:
226         result = 0x54;
227         break;
228     default:
229         result = WTF::nullopt;
230     }
231
232 #ifndef NDEBUG
233     UChar32 codePointOrder[] = {
234         0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
235         0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
236         0x7F,
237         0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
238         0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
239         softHyphen,
240         newlineCharacter,
241         tabCharacter,
242         noBreakSpace,
243         narrowNoBreakSpace,
244         leftToRightMark,
245         rightToLeftMark,
246         leftToRightEmbed,
247         rightToLeftEmbed,
248         leftToRightOverride,
249         rightToLeftOverride,
250         leftToRightIsolate,
251         rightToLeftIsolate,
252         zeroWidthNonJoiner,
253         zeroWidthJoiner,
254         popDirectionalFormatting,
255         popDirectionalIsolate,
256         firstStrongIsolate,
257         objectReplacementCharacter,
258         zeroWidthNoBreakSpace
259     };
260     bool found = false;
261     for (size_t i = 0; i < WTF_ARRAY_LENGTH(codePointOrder); ++i) {
262         if (codePointOrder[i] == codePoint) {
263             ASSERT(i == result);
264             found = true;
265         }
266     }
267     ASSERT(found == static_cast<bool>(result));
268 #endif
269     return result;
270 }
271
272 #if !USE(FREETYPE)
273 static void overrideControlCharacters(Vector<UChar>& buffer, unsigned start, unsigned end)
274 {
275     auto overwriteCodePoints = [&](unsigned minimum, unsigned maximum, UChar newCodePoint) {
276         unsigned begin = std::max(start, minimum);
277         unsigned complete = std::min(end, maximum);
278         for (unsigned i = begin; i < complete; ++i) {
279             ASSERT(codePointSupportIndex(i));
280             buffer[i - start] = newCodePoint;
281         }
282     };
283
284     auto overwriteCodePoint = [&](UChar codePoint, UChar newCodePoint) {
285         ASSERT(codePointSupportIndex(codePoint));
286         if (codePoint >= start && codePoint < end)
287             buffer[codePoint - start] = newCodePoint;
288     };
289
290     // Code points 0x0 - 0x20 and 0x7F - 0xA0 are control character and shouldn't render. Map them to ZERO WIDTH SPACE.
291     overwriteCodePoints(0x0, 0x20, zeroWidthSpace);
292     overwriteCodePoints(0x7F, 0xA0, zeroWidthSpace);
293     overwriteCodePoint(softHyphen, zeroWidthSpace);
294     overwriteCodePoint('\n', space);
295     overwriteCodePoint('\t', space);
296     overwriteCodePoint(noBreakSpace, space);
297     overwriteCodePoint(narrowNoBreakSpace, zeroWidthSpace);
298     overwriteCodePoint(leftToRightMark, zeroWidthSpace);
299     overwriteCodePoint(rightToLeftMark, zeroWidthSpace);
300     overwriteCodePoint(leftToRightEmbed, zeroWidthSpace);
301     overwriteCodePoint(rightToLeftEmbed, zeroWidthSpace);
302     overwriteCodePoint(leftToRightOverride, zeroWidthSpace);
303     overwriteCodePoint(rightToLeftOverride, zeroWidthSpace);
304     overwriteCodePoint(leftToRightIsolate, zeroWidthSpace);
305     overwriteCodePoint(rightToLeftIsolate, zeroWidthSpace);
306     overwriteCodePoint(zeroWidthNonJoiner, zeroWidthSpace);
307     overwriteCodePoint(zeroWidthJoiner, zeroWidthSpace);
308     overwriteCodePoint(popDirectionalFormatting, zeroWidthSpace);
309     overwriteCodePoint(popDirectionalIsolate, zeroWidthSpace);
310     overwriteCodePoint(firstStrongIsolate, zeroWidthSpace);
311     overwriteCodePoint(objectReplacementCharacter, zeroWidthSpace);
312     overwriteCodePoint(zeroWidthNoBreakSpace, zeroWidthSpace);
313 }
314 #endif
315
316 static RefPtr<GlyphPage> createAndFillGlyphPage(unsigned pageNumber, const Font& font)
317 {
318 #if PLATFORM(IOS_FAMILY)
319     // FIXME: Times New Roman contains Arabic glyphs, but Core Text doesn't know how to shape them. See <rdar://problem/9823975>.
320     // Once we have the fix for <rdar://problem/9823975> then remove this code together with Font::shouldNotBeUsedForArabic()
321     // in <rdar://problem/12096835>.
322     if (GlyphPage::pageNumberIsUsedForArabic(pageNumber) && font.shouldNotBeUsedForArabic())
323         return nullptr;
324 #endif
325
326     unsigned glyphPageSize = GlyphPage::sizeForPageNumber(pageNumber);
327
328     unsigned start = GlyphPage::startingCodePointInPageNumber(pageNumber);
329     Vector<UChar> buffer(glyphPageSize * 2 + 2);
330     unsigned bufferLength;
331     // Fill in a buffer with the entire "page" of characters that we want to look up glyphs for.
332     if (U_IS_BMP(start)) {
333         bufferLength = glyphPageSize;
334         for (unsigned i = 0; i < bufferLength; i++)
335             buffer[i] = start + i;
336
337 #if !USE(FREETYPE)
338         overrideControlCharacters(buffer, start, start + glyphPageSize);
339 #endif
340     } else {
341         bufferLength = glyphPageSize * 2;
342         for (unsigned i = 0; i < glyphPageSize; i++) {
343             int c = i + start;
344             buffer[i * 2] = U16_LEAD(c);
345             buffer[i * 2 + 1] = U16_TRAIL(c);
346         }
347     }
348
349     // Now that we have a buffer full of characters, we want to get back an array
350     // of glyph indices. This part involves calling into the platform-specific
351     // routine of our glyph map for actually filling in the page with the glyphs.
352     // Success is not guaranteed. For example, Times fails to fill page 260, giving glyph data
353     // for only 128 out of 256 characters.
354     Ref<GlyphPage> glyphPage = GlyphPage::create(font);
355
356     bool haveGlyphs = fillGlyphPage(glyphPage, buffer.data(), bufferLength, font);
357     if (!haveGlyphs)
358         return nullptr;
359
360     return glyphPage;
361 }
362
363 const GlyphPage* Font::glyphPage(unsigned pageNumber) const
364 {
365     if (!pageNumber) {
366         if (!m_glyphPageZero)
367             m_glyphPageZero = createAndFillGlyphPage(0, *this);
368         return m_glyphPageZero.get();
369     }
370     auto addResult = m_glyphPages.add(pageNumber, nullptr);
371     if (addResult.isNewEntry)
372         addResult.iterator->value = createAndFillGlyphPage(pageNumber, *this);
373
374     return addResult.iterator->value.get();
375 }
376
377 Glyph Font::glyphForCharacter(UChar32 character) const
378 {
379     auto* page = glyphPage(GlyphPage::pageNumberForCodePoint(character));
380     if (!page)
381         return 0;
382     return page->glyphForCharacter(character);
383 }
384
385 GlyphData Font::glyphDataForCharacter(UChar32 character) const
386 {
387     auto* page = glyphPage(GlyphPage::pageNumberForCodePoint(character));
388     if (!page)
389         return GlyphData();
390     return page->glyphDataForCharacter(character);
391 }
392
393 auto Font::ensureDerivedFontData() const -> DerivedFonts&
394 {
395     if (!m_derivedFontData)
396         m_derivedFontData = std::make_unique<DerivedFonts>();
397     return *m_derivedFontData;
398 }
399
400 const Font& Font::verticalRightOrientationFont() const
401 {
402     DerivedFonts& derivedFontData = ensureDerivedFontData();
403     if (!derivedFontData.verticalRightOrientationFont) {
404         auto verticalRightPlatformData = FontPlatformData::cloneWithOrientation(m_platformData, FontOrientation::Horizontal);
405         derivedFontData.verticalRightOrientationFont = create(verticalRightPlatformData, origin(), Interstitial::No, Visibility::Visible, OrientationFallback::Yes);
406     }
407     ASSERT(derivedFontData.verticalRightOrientationFont != this);
408     return *derivedFontData.verticalRightOrientationFont;
409 }
410
411 const Font& Font::uprightOrientationFont() const
412 {
413     DerivedFonts& derivedFontData = ensureDerivedFontData();
414     if (!derivedFontData.uprightOrientationFont)
415         derivedFontData.uprightOrientationFont = create(m_platformData, origin(), Interstitial::No, Visibility::Visible, OrientationFallback::Yes);
416     ASSERT(derivedFontData.uprightOrientationFont != this);
417     return *derivedFontData.uprightOrientationFont;
418 }
419
420 const Font& Font::invisibleFont() const
421 {
422     DerivedFonts& derivedFontData = ensureDerivedFontData();
423     if (!derivedFontData.invisibleFont)
424         derivedFontData.invisibleFont = create(m_platformData, origin(), Interstitial::Yes, Visibility::Invisible);
425     ASSERT(derivedFontData.invisibleFont != this);
426     return *derivedFontData.invisibleFont;
427 }
428
429 const Font* Font::smallCapsFont(const FontDescription& fontDescription) const
430 {
431     DerivedFonts& derivedFontData = ensureDerivedFontData();
432     if (!derivedFontData.smallCapsFont)
433         derivedFontData.smallCapsFont = createScaledFont(fontDescription, smallCapsFontSizeMultiplier);
434     ASSERT(derivedFontData.smallCapsFont != this);
435     return derivedFontData.smallCapsFont.get();
436 }
437
438 const Font& Font::noSynthesizableFeaturesFont() const
439 {
440 #if PLATFORM(COCOA)
441     DerivedFonts& derivedFontData = ensureDerivedFontData();
442     if (!derivedFontData.noSynthesizableFeaturesFont)
443         derivedFontData.noSynthesizableFeaturesFont = createFontWithoutSynthesizableFeatures();
444     ASSERT(derivedFontData.noSynthesizableFeaturesFont != this);
445     return *derivedFontData.noSynthesizableFeaturesFont;
446 #else
447     return *this;
448 #endif
449 }
450
451 const Font* Font::emphasisMarkFont(const FontDescription& fontDescription) const
452 {
453     DerivedFonts& derivedFontData = ensureDerivedFontData();
454     if (!derivedFontData.emphasisMarkFont)
455         derivedFontData.emphasisMarkFont = createScaledFont(fontDescription, emphasisMarkFontSizeMultiplier);
456     ASSERT(derivedFontData.emphasisMarkFont != this);
457     return derivedFontData.emphasisMarkFont.get();
458 }
459
460 const Font& Font::brokenIdeographFont() const
461 {
462     DerivedFonts& derivedFontData = ensureDerivedFontData();
463     if (!derivedFontData.brokenIdeographFont) {
464         derivedFontData.brokenIdeographFont = create(m_platformData, origin(), Interstitial::No);
465         derivedFontData.brokenIdeographFont->m_isBrokenIdeographFallback = true;
466     }
467     ASSERT(derivedFontData.brokenIdeographFont != this);
468     return *derivedFontData.brokenIdeographFont;
469 }
470
471 #if !LOG_DISABLED
472 String Font::description() const
473 {
474     if (origin() == Origin::Remote)
475         return "[custom font]";
476
477     return platformData().description();
478 }
479 #endif
480
481 const OpenTypeMathData* Font::mathData() const
482 {
483     if (isInterstitial())
484         return nullptr;
485     if (!m_mathData) {
486         m_mathData = OpenTypeMathData::create(m_platformData);
487         if (!m_mathData->hasMathData())
488             m_mathData = nullptr;
489     }
490     return m_mathData.get();
491 }
492
493 RefPtr<Font> Font::createScaledFont(const FontDescription& fontDescription, float scaleFactor) const
494 {
495     return platformCreateScaledFont(fontDescription, scaleFactor);
496 }
497
498 bool Font::applyTransforms(GlyphBufferGlyph* glyphs, GlyphBufferAdvance* advances, size_t glyphCount, bool enableKerning, bool requiresShaping) const
499 {
500 #if PLATFORM(COCOA)
501     CTFontTransformOptions options = (enableKerning ? kCTFontTransformApplyPositioning : 0) | (requiresShaping ? kCTFontTransformApplyShaping : 0);
502     return CTFontTransformGlyphs(m_platformData.ctFont(), glyphs, reinterpret_cast<CGSize*>(advances), glyphCount, options);
503 #else
504     UNUSED_PARAM(glyphs);
505     UNUSED_PARAM(advances);
506     UNUSED_PARAM(glyphCount);
507     UNUSED_PARAM(enableKerning);
508     UNUSED_PARAM(requiresShaping);
509     return false;
510 #endif
511 }
512
513 class CharacterFallbackMapKey {
514 public:
515     CharacterFallbackMapKey()
516     {
517     }
518
519     CharacterFallbackMapKey(const AtomicString& locale, UChar32 character, IsForPlatformFont isForPlatformFont)
520         : locale(locale)
521         , character(character)
522         , isForPlatformFont(isForPlatformFont == IsForPlatformFont::Yes)
523     {
524     }
525
526     CharacterFallbackMapKey(WTF::HashTableDeletedValueType)
527         : character(-1)
528     {
529     }
530
531     bool isHashTableDeletedValue() const { return character == -1; }
532
533     bool operator==(const CharacterFallbackMapKey& other) const
534     {
535         return locale == other.locale && character == other.character && isForPlatformFont == other.isForPlatformFont;
536     }
537
538     static const bool emptyValueIsZero = true;
539
540 private:
541     friend struct CharacterFallbackMapKeyHash;
542
543     AtomicString locale;
544     UChar32 character { 0 };
545     bool isForPlatformFont { false };
546 };
547
548 struct CharacterFallbackMapKeyHash {
549     static unsigned hash(const CharacterFallbackMapKey& key)
550     {
551         IntegerHasher hasher;
552         hasher.add(key.character);
553         hasher.add(key.isForPlatformFont);
554         hasher.add(key.locale.existingHash());
555         return hasher.hash();
556     }
557
558     static bool equal(const CharacterFallbackMapKey& a, const CharacterFallbackMapKey& b)
559     {
560         return a == b;
561     }
562
563     static const bool safeToCompareToEmptyOrDeleted = true;
564 };
565
566 // Fonts are not ref'd to avoid cycles.
567 // FIXME: Shouldn't these be WeakPtrs?
568 typedef HashMap<CharacterFallbackMapKey, Font*, CharacterFallbackMapKeyHash, WTF::SimpleClassHashTraits<CharacterFallbackMapKey>> CharacterFallbackMap;
569 typedef HashMap<const Font*, CharacterFallbackMap> SystemFallbackCache;
570
571 static SystemFallbackCache& systemFallbackCache()
572 {
573     static NeverDestroyed<SystemFallbackCache> map;
574     return map.get();
575 }
576
577 RefPtr<Font> Font::systemFallbackFontForCharacter(UChar32 character, const FontDescription& description, IsForPlatformFont isForPlatformFont) const
578 {
579     auto fontAddResult = systemFallbackCache().add(this, CharacterFallbackMap());
580
581     if (!character) {
582         UChar codeUnit = 0;
583         return FontCache::singleton().systemFallbackForCharacters(description, this, isForPlatformFont, FontCache::PreferColoredFont::No, &codeUnit, 1);
584     }
585
586     auto key = CharacterFallbackMapKey(description.locale(), character, isForPlatformFont);
587     auto characterAddResult = fontAddResult.iterator->value.add(WTFMove(key), nullptr);
588
589     Font*& fallbackFont = characterAddResult.iterator->value;
590
591     if (!fallbackFont) {
592         UChar codeUnits[2];
593         unsigned codeUnitsLength;
594         if (U_IS_BMP(character)) {
595             codeUnits[0] = FontCascade::normalizeSpaces(character);
596             codeUnitsLength = 1;
597         } else {
598             codeUnits[0] = U16_LEAD(character);
599             codeUnits[1] = U16_TRAIL(character);
600             codeUnitsLength = 2;
601         }
602
603         fallbackFont = FontCache::singleton().systemFallbackForCharacters(description, this, isForPlatformFont, FontCache::PreferColoredFont::No, codeUnits, codeUnitsLength).get();
604         if (fallbackFont)
605             fallbackFont->m_isUsedInSystemFallbackCache = true;
606     }
607
608     return fallbackFont;
609 }
610
611 void Font::removeFromSystemFallbackCache()
612 {
613     systemFallbackCache().remove(this);
614
615     if (!m_isUsedInSystemFallbackCache)
616         return;
617
618     for (auto& characterMap : systemFallbackCache().values()) {
619         Vector<CharacterFallbackMapKey, 512> toRemove;
620         for (auto& entry : characterMap) {
621             if (entry.value == this)
622                 toRemove.append(entry.key);
623         }
624         for (auto& key : toRemove)
625             characterMap.remove(key);
626     }
627 }
628
629 #if !PLATFORM(COCOA) && !USE(FREETYPE)
630 bool Font::variantCapsSupportsCharacterForSynthesis(FontVariantCaps fontVariantCaps, UChar32) const
631 {
632     switch (fontVariantCaps) {
633     case FontVariantCaps::Small:
634     case FontVariantCaps::Petite:
635     case FontVariantCaps::AllSmall:
636     case FontVariantCaps::AllPetite:
637         return false;
638     default:
639         // Synthesis only supports the variant-caps values listed above.
640         return true;
641     }
642 }
643
644 bool Font::platformSupportsCodePoint(UChar32 character) const
645 {
646     return glyphForCharacter(character);
647 }
648 #endif
649
650 bool Font::supportsCodePoint(UChar32 character) const
651 {
652     // This is very similar to static_cast<bool>(glyphForCharacter(character))
653     // except that glyphForCharacter() maps certain code points to ZWS (because they
654     // shouldn't be visible). This function doesn't do that mapping, and instead is
655     // as honest as possible about what code points the font supports. This is so
656     // that we can accurately determine which characters are supported by this font
657     // so we know which boundaries to break strings when we send them to the complex
658     // text codepath. The complex text codepath is totally separate from this ZWS
659     // replacement logic (because CoreText handles those characters instead of WebKit).
660     if (auto index = codePointSupportIndex(character)) {
661         m_codePointSupport.ensureSize(2 * (*index + 1));
662         bool hasBeenSet = m_codePointSupport.quickSet(2 * *index);
663         if (!hasBeenSet && platformSupportsCodePoint(character))
664             m_codePointSupport.quickSet(2 * *index + 1);
665         return m_codePointSupport.quickGet(2 * *index + 1);
666     }
667     return glyphForCharacter(character);
668 }
669
670 bool Font::canRenderCombiningCharacterSequence(const UChar* characters, size_t length) const
671 {
672     ASSERT(isMainThread());
673
674     for (UChar32 codePoint : StringView(characters, length).codePoints()) {
675         if (!supportsCodePoint(codePoint))
676             return false;
677     }
678     return true;
679 }
680
681 // Don't store the result of this! The hash map is free to rehash at any point, leaving this reference dangling.
682 const Path& Font::pathForGlyph(Glyph glyph) const
683 {
684     if (const auto& path = m_glyphPathMap.existingMetricsForGlyph(glyph))
685         return *path;
686     auto path = platformPathForGlyph(glyph);
687     m_glyphPathMap.setMetricsForGlyph(glyph, path);
688     return *m_glyphPathMap.existingMetricsForGlyph(glyph);
689 }
690
691 } // namespace WebCore