[WTF] Import std::optional reference implementation as WTF::Optional
[WebKit-https.git] / Source / WebCore / css / CSSSegmentedFontFace.cpp
1 /*
2  * Copyright (C) 2008, 2013 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "CSSSegmentedFontFace.h"
28
29 #include "CSSFontFace.h"
30 #include "CSSFontFaceSource.h"
31 #include "CSSFontSelector.h"
32 #include "Document.h"
33 #include "Font.h"
34 #include "FontCache.h"
35 #include "FontDescription.h"
36 #include "RuntimeEnabledFeatures.h"
37
38 namespace WebCore {
39
40 CSSSegmentedFontFace::CSSSegmentedFontFace()
41 {
42 }
43
44 CSSSegmentedFontFace::~CSSSegmentedFontFace()
45 {
46     for (auto& face : m_fontFaces)
47         face->removeClient(*this);
48 }
49
50 void CSSSegmentedFontFace::appendFontFace(Ref<CSSFontFace>&& fontFace)
51 {
52     m_cache.clear();
53     fontFace->addClient(*this);
54     m_fontFaces.append(WTFMove(fontFace));
55 }
56
57 void CSSSegmentedFontFace::fontLoaded(CSSFontFace&)
58 {
59     m_cache.clear();
60 }
61
62 class CSSFontAccessor final : public FontAccessor {
63 public:
64     static Ref<CSSFontAccessor> create(CSSFontFace& fontFace, const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic)
65     {
66         return adoptRef(*new CSSFontAccessor(fontFace, fontDescription, syntheticBold, syntheticItalic));
67     }
68
69     const Font* font() const final
70     {
71         if (!m_result)
72             m_result = m_fontFace->font(m_fontDescription, m_syntheticBold, m_syntheticItalic);
73         return m_result.value().get();
74     }
75
76 private:
77     CSSFontAccessor(CSSFontFace& fontFace, const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic)
78         : m_fontFace(fontFace)
79         , m_fontDescription(fontDescription)
80         , m_syntheticBold(syntheticBold)
81         , m_syntheticItalic(syntheticItalic)
82     {
83     }
84
85     bool isLoading() const final
86     {
87         return m_result && m_result.value() && m_result.value()->isLoading();
88     }
89
90     mutable std::optional<RefPtr<Font>> m_result; // Caches nullptr too
91     mutable Ref<CSSFontFace> m_fontFace;
92     FontDescription m_fontDescription;
93     bool m_syntheticBold;
94     bool m_syntheticItalic;
95 };
96
97 static void appendFontWithInvalidUnicodeRangeIfLoading(FontRanges& ranges, Ref<FontAccessor>&& fontAccessor, const Vector<CSSFontFace::UnicodeRange>& unicodeRanges)
98 {
99     if (fontAccessor->isLoading()) {
100         ranges.appendRange({ 0, 0, WTFMove(fontAccessor) });
101         return;
102     }
103
104     if (unicodeRanges.isEmpty()) {
105         ranges.appendRange({ 0, 0x7FFFFFFF, WTFMove(fontAccessor) });
106         return;
107     }
108
109     for (auto& range : unicodeRanges)
110         ranges.appendRange({ range.from, range.to, fontAccessor.copyRef() });
111 }
112
113 FontRanges CSSSegmentedFontFace::fontRanges(const FontDescription& fontDescription)
114 {
115     FontTraitsMask desiredTraitsMask = fontDescription.traitsMask();
116
117     auto addResult = m_cache.add(FontDescriptionKey(fontDescription), FontRanges());
118     auto& result = addResult.iterator->value;
119
120     if (addResult.isNewEntry) {
121         for (auto& face : m_fontFaces) {
122             if (face->allSourcesFailed())
123                 continue;
124
125             FontTraitsMask traitsMask = face->traitsMask();
126             bool syntheticBold = (fontDescription.fontSynthesis() & FontSynthesisWeight) && !(traitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)) && (desiredTraitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask));
127             bool syntheticItalic = (fontDescription.fontSynthesis() & FontSynthesisStyle) && !(traitsMask & FontStyleItalicMask) && (desiredTraitsMask & FontStyleItalicMask);
128
129             // This doesn't trigger an unnecessary download because every element styled with this family will need font metrics in order to run layout.
130             // Metrics used for layout come from FontRanges::fontForFirstRange(), which assumes that the first font is non-null.
131             // We're kicking off this necessary first download now.
132             auto fontAccessor = CSSFontAccessor::create(face, fontDescription, syntheticBold, syntheticItalic);
133             if (result.isNull() && !fontAccessor->font())
134                 continue;
135             appendFontWithInvalidUnicodeRangeIfLoading(result, WTFMove(fontAccessor), face->ranges());
136         }
137     }
138     return result;
139 }
140
141 }