1 | /*
|
---|
2 | * Copyright (C) 2007-2021 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 "CSSFontFaceSource.h"
|
---|
28 |
|
---|
29 | #include "CSSFontFace.h"
|
---|
30 | #include "CSSFontSelector.h"
|
---|
31 | #include "CachedFontLoadRequest.h"
|
---|
32 | #include "CachedSVGFont.h"
|
---|
33 | #include "Document.h"
|
---|
34 | #include "Font.h"
|
---|
35 | #include "FontCache.h"
|
---|
36 | #include "FontCascadeDescription.h"
|
---|
37 | #include "FontCreationContext.h"
|
---|
38 | #include "FontCustomPlatformData.h"
|
---|
39 | #include "FontDescription.h"
|
---|
40 | #include "ResourceLoadObserver.h"
|
---|
41 | #include "RuntimeEnabledFeatures.h"
|
---|
42 | #include "SVGElementTypeHelpers.h"
|
---|
43 | #include "SVGFontElement.h"
|
---|
44 | #include "SVGFontFaceElement.h"
|
---|
45 | #include "SVGToOTFFontConversion.h"
|
---|
46 | #include "SVGURIReference.h"
|
---|
47 | #include "SharedBuffer.h"
|
---|
48 |
|
---|
49 | namespace WebCore {
|
---|
50 |
|
---|
51 | inline void CSSFontFaceSource::setStatus(Status newStatus)
|
---|
52 | {
|
---|
53 | switch (newStatus) {
|
---|
54 | case Status::Pending:
|
---|
55 | ASSERT_NOT_REACHED();
|
---|
56 | break;
|
---|
57 | case Status::Loading:
|
---|
58 | ASSERT(status() == Status::Pending);
|
---|
59 | break;
|
---|
60 | case Status::Success:
|
---|
61 | ASSERT(status() == Status::Loading);
|
---|
62 | break;
|
---|
63 | case Status::Failure:
|
---|
64 | ASSERT(status() == Status::Loading);
|
---|
65 | break;
|
---|
66 | }
|
---|
67 |
|
---|
68 | m_status = newStatus;
|
---|
69 | }
|
---|
70 |
|
---|
71 | CSSFontFaceSource::CSSFontFaceSource(CSSFontFace& owner, const String& familyNameOrURI)
|
---|
72 | : m_familyNameOrURI(familyNameOrURI)
|
---|
73 | , m_face(owner)
|
---|
74 | {
|
---|
75 | }
|
---|
76 |
|
---|
77 | CSSFontFaceSource::CSSFontFaceSource(CSSFontFace& owner, const String& familyNameOrURI, CSSFontSelector& fontSelector, UniqueRef<FontLoadRequest>&& request)
|
---|
78 | : m_familyNameOrURI(familyNameOrURI)
|
---|
79 | , m_face(owner)
|
---|
80 | , m_fontSelector(fontSelector)
|
---|
81 | , m_fontRequest(request.moveToUniquePtr())
|
---|
82 | {
|
---|
83 | // This may synchronously call fontLoaded().
|
---|
84 | m_fontRequest->setClient(this);
|
---|
85 |
|
---|
86 | if (status() == Status::Pending && !m_fontRequest->isPending()) {
|
---|
87 | setStatus(Status::Loading);
|
---|
88 | if (!shouldIgnoreFontLoadCompletions()) {
|
---|
89 | if (m_fontRequest->errorOccurred())
|
---|
90 | setStatus(Status::Failure);
|
---|
91 | else
|
---|
92 | setStatus(Status::Success);
|
---|
93 | }
|
---|
94 | }
|
---|
95 | }
|
---|
96 |
|
---|
97 | CSSFontFaceSource::CSSFontFaceSource(CSSFontFace& owner, const String& familyNameOrURI, SVGFontFaceElement& fontFace)
|
---|
98 | : m_familyNameOrURI(familyNameOrURI)
|
---|
99 | , m_face(owner)
|
---|
100 | , m_svgFontFaceElement(fontFace)
|
---|
101 | , m_hasSVGFontFaceElement(true)
|
---|
102 | {
|
---|
103 | }
|
---|
104 |
|
---|
105 | CSSFontFaceSource::CSSFontFaceSource(CSSFontFace& owner, const String& familyNameOrURI, Ref<JSC::ArrayBufferView>&& arrayBufferView)
|
---|
106 | : m_familyNameOrURI(familyNameOrURI)
|
---|
107 | , m_face(owner)
|
---|
108 | , m_immediateSource(WTFMove(arrayBufferView))
|
---|
109 | {
|
---|
110 | }
|
---|
111 |
|
---|
112 | CSSFontFaceSource::~CSSFontFaceSource()
|
---|
113 | {
|
---|
114 | if (m_fontRequest)
|
---|
115 | m_fontRequest->setClient(nullptr);
|
---|
116 | }
|
---|
117 |
|
---|
118 | bool CSSFontFaceSource::shouldIgnoreFontLoadCompletions() const
|
---|
119 | {
|
---|
120 | return m_face.shouldIgnoreFontLoadCompletions();
|
---|
121 | }
|
---|
122 |
|
---|
123 | void CSSFontFaceSource::opportunisticallyStartFontDataURLLoading()
|
---|
124 | {
|
---|
125 | if (status() == Status::Pending && m_fontRequest && m_fontRequest->url().protocolIsData() && m_familyNameOrURI.length() < MB)
|
---|
126 | load();
|
---|
127 | }
|
---|
128 |
|
---|
129 | void CSSFontFaceSource::fontLoaded(FontLoadRequest& fontRequest)
|
---|
130 | {
|
---|
131 | ASSERT_UNUSED(fontRequest, &fontRequest == m_fontRequest.get());
|
---|
132 |
|
---|
133 | if (shouldIgnoreFontLoadCompletions())
|
---|
134 | return;
|
---|
135 |
|
---|
136 | Ref<CSSFontFace> protectedFace(m_face);
|
---|
137 |
|
---|
138 | // If the font is in the cache, this will be synchronously called from FontLoadRequest::addClient().
|
---|
139 | if (m_status == Status::Pending)
|
---|
140 | setStatus(Status::Loading);
|
---|
141 | else if (m_status == Status::Failure) {
|
---|
142 | // This function may be called twice if loading was cancelled.
|
---|
143 | ASSERT(m_fontRequest->errorOccurred());
|
---|
144 | return;
|
---|
145 | }
|
---|
146 |
|
---|
147 | if (m_fontRequest->errorOccurred() || !m_fontRequest->ensureCustomFontData(m_familyNameOrURI))
|
---|
148 | setStatus(Status::Failure);
|
---|
149 | else
|
---|
150 | setStatus(Status::Success);
|
---|
151 |
|
---|
152 | m_face.fontLoaded(*this);
|
---|
153 | }
|
---|
154 |
|
---|
155 | void CSSFontFaceSource::load(Document* document)
|
---|
156 | {
|
---|
157 | setStatus(Status::Loading);
|
---|
158 |
|
---|
159 | if (m_fontRequest) {
|
---|
160 | ASSERT(m_fontSelector);
|
---|
161 | if (auto* context = m_fontSelector->scriptExecutionContext())
|
---|
162 | context->beginLoadingFontSoon(*m_fontRequest);
|
---|
163 | } else {
|
---|
164 | bool success = false;
|
---|
165 | if (m_hasSVGFontFaceElement) {
|
---|
166 | if (m_svgFontFaceElement && is<SVGFontElement>(m_svgFontFaceElement->parentNode())) {
|
---|
167 | ASSERT(!m_inDocumentCustomPlatformData);
|
---|
168 | SVGFontElement& fontElement = downcast<SVGFontElement>(*m_svgFontFaceElement->parentNode());
|
---|
169 | if (auto otfFont = convertSVGToOTFFont(fontElement))
|
---|
170 | m_generatedOTFBuffer = SharedBuffer::create(WTFMove(otfFont.value()));
|
---|
171 | if (m_generatedOTFBuffer) {
|
---|
172 | m_inDocumentCustomPlatformData = createFontCustomPlatformData(*m_generatedOTFBuffer, String());
|
---|
173 | success = static_cast<bool>(m_inDocumentCustomPlatformData);
|
---|
174 | }
|
---|
175 | }
|
---|
176 | } else if (m_immediateSource) {
|
---|
177 | ASSERT(!m_immediateFontCustomPlatformData);
|
---|
178 | bool wrapping;
|
---|
179 | auto buffer = SharedBuffer::create(static_cast<const char*>(m_immediateSource->baseAddress()), m_immediateSource->byteLength());
|
---|
180 | m_immediateFontCustomPlatformData = CachedFont::createCustomFontData(buffer.get(), String(), wrapping);
|
---|
181 | success = static_cast<bool>(m_immediateFontCustomPlatformData);
|
---|
182 | } else {
|
---|
183 | // We are only interested in whether or not fontForFamily() returns null or not. Luckily, none of
|
---|
184 | // the values in the FontDescription other than the family name can cause the function to return
|
---|
185 | // null if it wasn't going to otherwise (and vice-versa).
|
---|
186 | FontCascadeDescription fontDescription;
|
---|
187 | fontDescription.setOneFamily(m_familyNameOrURI);
|
---|
188 | fontDescription.setComputedSize(1);
|
---|
189 | fontDescription.setShouldAllowUserInstalledFonts(m_face.allowUserInstalledFonts());
|
---|
190 | success = FontCache::forCurrentThread().fontForFamily(fontDescription, m_familyNameOrURI, { }, true);
|
---|
191 | if (document && RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
|
---|
192 | ResourceLoadObserver::shared().logFontLoad(*document, m_familyNameOrURI.string(), success);
|
---|
193 | }
|
---|
194 | setStatus(success ? Status::Success : Status::Failure);
|
---|
195 | }
|
---|
196 | }
|
---|
197 |
|
---|
198 | RefPtr<Font> CSSFontFaceSource::font(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic, const FontCreationContext& fontCreationContext)
|
---|
199 | {
|
---|
200 | ASSERT(status() == Status::Success);
|
---|
201 |
|
---|
202 | bool usesInDocumentSVGFont = m_hasSVGFontFaceElement;
|
---|
203 |
|
---|
204 | if (!m_fontRequest && !usesInDocumentSVGFont) {
|
---|
205 | if (m_immediateSource) {
|
---|
206 | if (!m_immediateFontCustomPlatformData)
|
---|
207 | return nullptr;
|
---|
208 | return Font::create(CachedFont::platformDataFromCustomData(*m_immediateFontCustomPlatformData, fontDescription, syntheticBold, syntheticItalic, fontCreationContext), Font::Origin::Remote);
|
---|
209 | }
|
---|
210 |
|
---|
211 | // We're local. Just return a Font from the normal cache.
|
---|
212 | // We don't want to check alternate font family names here, so pass true as the checkingAlternateName parameter.
|
---|
213 | return FontCache::forCurrentThread().fontForFamily(fontDescription, m_familyNameOrURI, fontCreationContext, true);
|
---|
214 | }
|
---|
215 |
|
---|
216 | if (m_fontRequest) {
|
---|
217 | auto success = m_fontRequest->ensureCustomFontData(m_familyNameOrURI);
|
---|
218 | ASSERT_UNUSED(success, success);
|
---|
219 |
|
---|
220 | ASSERT(status() == Status::Success);
|
---|
221 | auto result = m_fontRequest->createFont(fontDescription, m_familyNameOrURI, syntheticBold, syntheticItalic, fontCreationContext);
|
---|
222 | ASSERT(result);
|
---|
223 | return result;
|
---|
224 | }
|
---|
225 |
|
---|
226 | if (!usesInDocumentSVGFont)
|
---|
227 | return nullptr;
|
---|
228 |
|
---|
229 | if (!m_svgFontFaceElement || !is<SVGFontElement>(m_svgFontFaceElement->parentNode()))
|
---|
230 | return nullptr;
|
---|
231 | if (!m_inDocumentCustomPlatformData)
|
---|
232 | return nullptr;
|
---|
233 | return Font::create(m_inDocumentCustomPlatformData->fontPlatformData(fontDescription, syntheticBold, syntheticItalic, fontCreationContext), Font::Origin::Remote);
|
---|
234 | }
|
---|
235 |
|
---|
236 | bool CSSFontFaceSource::isSVGFontFaceSource() const
|
---|
237 | {
|
---|
238 | return m_hasSVGFontFaceElement || (is<CachedFontLoadRequest>(m_fontRequest) && is<CachedSVGFont>(downcast<CachedFontLoadRequest>(m_fontRequest.get())->cachedFont()));
|
---|
239 | }
|
---|
240 |
|
---|
241 | }
|
---|