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