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 COMPUTER, 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 COMPUTER, 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 "CachedFont.h"
29
30#if PLATFORM(CG) || PLATFORM(QT) || PLATFORM(GTK) || (PLATFORM(CHROMIUM) && (OS(WINDOWS) || OS(LINUX))) || PLATFORM(HAIKU) || OS(WINCE) || OS(ANDROID)
31#define STORE_FONT_CUSTOM_PLATFORM_DATA
32#endif
33
34#include "Cache.h"
35#include "CachedResourceClient.h"
36#include "CachedResourceClientWalker.h"
37#include "DOMImplementation.h"
38#include "FontPlatformData.h"
39#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA
40#include "FontCustomPlatformData.h"
41#endif
42#include "TextResourceDecoder.h"
43#include "loader.h"
44#include <wtf/Vector.h>
45
46#if ENABLE(SVG_FONTS)
47#include "HTMLNames.h"
48#include "NodeList.h"
49#include "SVGElement.h"
50#include "SVGFontElement.h"
51#include "SVGGElement.h"
52#endif
53
54namespace WebCore {
55
56CachedFont::CachedFont(const String &url)
57    : CachedResource(url, FontResource)
58    , m_fontData(0)
59    , m_loadInitiated(false)
60#if ENABLE(SVG_FONTS)
61    , m_isSVGFont(false)
62#endif
63{
64}
65
66CachedFont::~CachedFont()
67{
68#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA
69    delete m_fontData;
70#endif
71}
72
73void CachedFont::load(DocLoader*)
74{
75    // Don't load the file yet.  Wait for an access before triggering the load.
76    m_loading = true;
77}
78
79void CachedFont::didAddClient(CachedResourceClient* c)
80{
81    if (!m_loading)
82        c->fontLoaded(this);
83}
84
85void CachedFont::data(PassRefPtr<SharedBuffer> data, bool allDataReceived)
86{
87    if (!allDataReceived)
88        return;
89
90    m_data = data;
91    setEncodedSize(m_data.get() ? m_data->size() : 0);
92    m_loading = false;
93    checkNotify();
94}
95
96void CachedFont::beginLoadIfNeeded(DocLoader* dl)
97{
98    if (!m_loadInitiated) {
99        m_loadInitiated = true;
100        cache()->loader()->load(dl, this, false);
101    }
102}
103
104bool CachedFont::ensureCustomFontData()
105{
106#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA
107#if ENABLE(SVG_FONTS)
108    ASSERT(!m_isSVGFont);
109#endif
110    if (!m_fontData && !m_errorOccurred && !m_loading && m_data) {
111        m_fontData = createFontCustomPlatformData(m_data.get());
112        if (!m_fontData)
113            m_errorOccurred = true;
114    }
115#endif
116    return m_fontData;
117}
118
119FontPlatformData CachedFont::platformDataFromCustomData(float size, bool bold, bool italic, FontRenderingMode renderingMode)
120{
121#if ENABLE(SVG_FONTS)
122    if (m_externalSVGDocument)
123        return FontPlatformData(size, bold, italic);
124#endif
125#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA
126    ASSERT(m_fontData);
127    return m_fontData->fontPlatformData(static_cast<int>(size), bold, italic, renderingMode);
128#else
129    return FontPlatformData();
130#endif
131}
132
133#if ENABLE(SVG_FONTS)
134bool CachedFont::ensureSVGFontData()
135{
136    ASSERT(m_isSVGFont);
137    if (!m_externalSVGDocument && !m_errorOccurred && !m_loading && m_data) {
138        m_externalSVGDocument = SVGDocument::create(0);
139        m_externalSVGDocument->open();
140
141        RefPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("application/xml");
142        m_externalSVGDocument->write(decoder->decode(m_data->data(), m_data->size()));
143        m_externalSVGDocument->write(decoder->flush());
144        if (decoder->sawError()) {
145            m_externalSVGDocument.clear();
146            return 0;
147        }
148
149        m_externalSVGDocument->finishParsing();
150        m_externalSVGDocument->close();
151    }
152
153    return m_externalSVGDocument;
154}
155
156SVGFontElement* CachedFont::getSVGFontById(const String& fontName) const
157{
158    ASSERT(m_isSVGFont);
159    RefPtr<NodeList> list = m_externalSVGDocument->getElementsByTagName(SVGNames::fontTag.localName());
160    if (!list)
161        return 0;
162
163    unsigned fonts = list->length();
164    for (unsigned i = 0; i < fonts; ++i) {
165        Node* node = list->item(i);
166        ASSERT(node);
167
168        if (static_cast<Element*>(node)->getAttribute(static_cast<Element*>(node)->idAttributeName()) != fontName)
169            continue;
170
171        ASSERT(node->hasTagName(SVGNames::fontTag));
172        return static_cast<SVGFontElement*>(node);
173    }
174
175    return 0;
176}
177#endif
178
179void CachedFont::allClientsRemoved()
180{
181#ifdef STORE_FONT_CUSTOM_PLATFORM_DATA
182    if (m_fontData) {
183        delete m_fontData;
184        m_fontData = 0;
185    }
186#endif
187}
188
189void CachedFont::checkNotify()
190{
191    if (m_loading)
192        return;
193
194    CachedResourceClientWalker w(m_clients);
195    while (CachedResourceClient *c = w.next())
196         c->fontLoaded(this);
197}
198
199
200void CachedFont::error()
201{
202    m_loading = false;
203    m_errorOccurred = true;
204    checkNotify();
205}
206
207}
208