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