1/*
2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 Torch Mobile, Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "CachedSVGFont.h"
29
30#if ENABLE(SVG_FONTS)
31
32#include "FontDescription.h"
33#include "FontPlatformData.h"
34#include "SVGDocument.h"
35#include "SVGFontElement.h"
36#include "SVGFontFaceElement.h"
37#include "ScriptDisallowedScope.h"
38#include "SharedBuffer.h"
39#include "TextResourceDecoder.h"
40#include "TypedElementDescendantIterator.h"
41#include "SVGToOTFFontConversion.h"
42
43#if USE(DIRECT2D)
44#include <dwrite.h>
45#endif
46
47namespace WebCore {
48
49CachedSVGFont::CachedSVGFont(CachedResourceRequest&& request, const PAL::SessionID& sessionID, const CookieJar* cookieJar)
50 : CachedFont(WTFMove(request), sessionID, cookieJar, Type::SVGFontResource)
51 , m_externalSVGFontElement(nullptr)
52{
53}
54
55RefPtr<Font> CachedSVGFont::createFont(const FontDescription& fontDescription, const AtomicString& remoteURI, bool syntheticBold, bool syntheticItalic, const FontFeatureSettings& fontFaceFeatures, const FontVariantSettings& fontFaceVariantSettings, FontSelectionSpecifiedCapabilities fontFaceCapabilities)
56{
57 ASSERT(firstFontFace(remoteURI));
58 return CachedFont::createFont(fontDescription, remoteURI, syntheticBold, syntheticItalic, fontFaceFeatures, fontFaceVariantSettings, fontFaceCapabilities);
59}
60
61FontPlatformData CachedSVGFont::platformDataFromCustomData(const FontDescription& fontDescription, bool bold, bool italic, const FontFeatureSettings& fontFaceFeatures, const FontVariantSettings& fontFaceVariantSettings, FontSelectionSpecifiedCapabilities fontFaceCapabilities)
62{
63 if (m_externalSVGDocument)
64 return FontPlatformData(fontDescription.computedPixelSize(), bold, italic);
65 return CachedFont::platformDataFromCustomData(fontDescription, bold, italic, fontFaceFeatures, fontFaceVariantSettings, fontFaceCapabilities);
66}
67
68bool CachedSVGFont::ensureCustomFontData(const AtomicString& remoteURI)
69{
70 if (!m_externalSVGDocument && !errorOccurred() && !isLoading() && m_data) {
71 bool sawError = false;
72 {
73 // We may get here during render tree updates when events are forbidden.
74 // Frameless document can't run scripts or call back to the client so this is safe.
75 m_externalSVGDocument = SVGDocument::create(nullptr, URL());
76 auto decoder = TextResourceDecoder::create("application/xml");
77
78 ScriptDisallowedScope::DisableAssertionsInScope disabledScope;
79
80 m_externalSVGDocument->setContent(decoder->decodeAndFlush(m_data->data(), m_data->size()));
81 sawError = decoder->sawError();
82 }
83
84 if (sawError)
85 m_externalSVGDocument = nullptr;
86 if (m_externalSVGDocument)
87 maybeInitializeExternalSVGFontElement(remoteURI);
88 if (!m_externalSVGFontElement || !firstFontFace(remoteURI))
89 return false;
90 if (auto convertedFont = convertSVGToOTFFont(*m_externalSVGFontElement))
91 m_convertedFont = SharedBuffer::create(WTFMove(convertedFont.value()));
92 else {
93 m_externalSVGDocument = nullptr;
94 m_externalSVGFontElement = nullptr;
95 return false;
96 }
97 }
98
99 return m_externalSVGDocument && CachedFont::ensureCustomFontData(m_convertedFont.get());
100}
101
102SVGFontElement* CachedSVGFont::getSVGFontById(const String& fontName) const
103{
104 ASSERT(m_externalSVGDocument);
105 auto elements = descendantsOfType<SVGFontElement>(*m_externalSVGDocument);
106
107 if (fontName.isEmpty())
108 return elements.first();
109
110 for (auto& element : elements) {
111 if (element.getIdAttribute() == fontName)
112 return &element;
113 }
114 return nullptr;
115}
116
117SVGFontElement* CachedSVGFont::maybeInitializeExternalSVGFontElement(const AtomicString& remoteURI)
118{
119 if (m_externalSVGFontElement)
120 return m_externalSVGFontElement;
121 String fragmentIdentifier;
122 size_t start = remoteURI.find('#');
123 if (start != notFound)
124 fragmentIdentifier = remoteURI.string().substring(start + 1);
125 m_externalSVGFontElement = getSVGFontById(fragmentIdentifier);
126 return m_externalSVGFontElement;
127}
128
129SVGFontFaceElement* CachedSVGFont::firstFontFace(const AtomicString& remoteURI)
130{
131 if (!maybeInitializeExternalSVGFontElement(remoteURI))
132 return nullptr;
133
134 if (auto* firstFontFace = childrenOfType<SVGFontFaceElement>(*m_externalSVGFontElement).first())
135 return firstFontFace;
136 return nullptr;
137}
138
139}
140
141#endif
142