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