1/*
2 * Copyright (C) 2007, 2008, 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 COMPUTER, 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 COMPUTER, 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 "CSSFontFace.h"
28
29#include "CSSFontFaceSource.h"
30#include "CSSFontSelector.h"
31#include "CSSSegmentedFontFace.h"
32#include "Document.h"
33#include "FontDescription.h"
34#include "FontLoader.h"
35#include "RuntimeEnabledFeatures.h"
36#include "SimpleFontData.h"
37
38namespace WebCore {
39
40bool CSSFontFace::isLoaded() const
41{
42    size_t size = m_sources.size();
43    for (size_t i = 0; i < size; i++) {
44        if (!m_sources[i]->isLoaded())
45            return false;
46    }
47    return true;
48}
49
50bool CSSFontFace::isValid() const
51{
52    size_t size = m_sources.size();
53    for (size_t i = 0; i < size; i++) {
54        if (m_sources[i]->isValid())
55            return true;
56    }
57    return false;
58}
59
60void CSSFontFace::addedToSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace)
61{
62    m_segmentedFontFaces.add(segmentedFontFace);
63}
64
65void CSSFontFace::removedFromSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace)
66{
67    m_segmentedFontFaces.remove(segmentedFontFace);
68}
69
70void CSSFontFace::addSource(PassOwnPtr<CSSFontFaceSource> source)
71{
72    source->setFontFace(this);
73    m_sources.append(source);
74}
75
76void CSSFontFace::fontLoaded(CSSFontFaceSource* source)
77{
78    if (source != m_activeSource)
79        return;
80
81    // FIXME: Can we assert that m_segmentedFontFaces is not empty? That may
82    // require stopping in-progress font loading when the last
83    // CSSSegmentedFontFace is removed.
84    if (m_segmentedFontFaces.isEmpty())
85        return;
86
87    // Use one of the CSSSegmentedFontFaces' font selector. They all have
88    // the same font selector, so it's wasteful to store it in the CSSFontFace.
89    CSSFontSelector* fontSelector = (*m_segmentedFontFaces.begin())->fontSelector();
90    fontSelector->fontLoaded();
91
92#if ENABLE(FONT_LOAD_EVENTS)
93    if (RuntimeEnabledFeatures::fontLoadEventsEnabled() && m_loadState == Loading) {
94        if (source->ensureFontData())
95            notifyFontLoader(Loaded);
96        else if (!isValid())
97            notifyFontLoader(Error);
98    }
99#endif
100
101    HashSet<CSSSegmentedFontFace*>::iterator end = m_segmentedFontFaces.end();
102    for (HashSet<CSSSegmentedFontFace*>::iterator it = m_segmentedFontFaces.begin(); it != end; ++it)
103        (*it)->fontLoaded(this);
104
105#if ENABLE(FONT_LOAD_EVENTS)
106    if (RuntimeEnabledFeatures::fontLoadEventsEnabled())
107        notifyLoadingDone();
108#endif
109}
110
111PassRefPtr<SimpleFontData> CSSFontFace::getFontData(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic)
112{
113    m_activeSource = 0;
114    if (!isValid())
115        return 0;
116
117    ASSERT(!m_segmentedFontFaces.isEmpty());
118    CSSFontSelector* fontSelector = (*m_segmentedFontFaces.begin())->fontSelector();
119
120#if ENABLE(FONT_LOAD_EVENTS)
121    if (RuntimeEnabledFeatures::fontLoadEventsEnabled() && m_loadState == NotLoaded)
122        notifyFontLoader(Loading);
123#endif
124
125    size_t size = m_sources.size();
126    for (size_t i = 0; i < size; ++i) {
127        if (RefPtr<SimpleFontData> result = m_sources[i]->getFontData(fontDescription, syntheticBold, syntheticItalic, fontSelector)) {
128            m_activeSource = m_sources[i].get();
129#if ENABLE(FONT_LOAD_EVENTS)
130            if (RuntimeEnabledFeatures::fontLoadEventsEnabled() && m_loadState == Loading && m_sources[i]->isLoaded()) {
131                notifyFontLoader(Loaded);
132                notifyLoadingDone();
133            }
134#endif
135            return result.release();
136        }
137    }
138
139#if ENABLE(FONT_LOAD_EVENTS)
140    if (RuntimeEnabledFeatures::fontLoadEventsEnabled() && m_loadState == Loading) {
141        notifyFontLoader(Error);
142        notifyLoadingDone();
143    }
144#endif
145    return 0;
146}
147
148#if ENABLE(FONT_LOAD_EVENTS)
149void CSSFontFace::notifyFontLoader(LoadState newState)
150{
151    m_loadState = newState;
152
153    Document* document = (*m_segmentedFontFaces.begin())->fontSelector()->document();
154    if (!document)
155        return;
156
157    switch (newState) {
158    case Loading:
159        document->fontloader()->beginFontLoading(m_rule.get());
160        break;
161    case Loaded:
162        document->fontloader()->fontLoaded(m_rule.get());
163        break;
164    case Error:
165        document->fontloader()->loadError(m_rule.get(), m_activeSource);
166        break;
167    default:
168        break;
169    }
170}
171
172void CSSFontFace::notifyLoadingDone()
173{
174    Document* document = (*m_segmentedFontFaces.begin())->fontSelector()->document();
175    if (document)
176        document->fontloader()->loadingDone();
177}
178#endif
179
180#if ENABLE(SVG_FONTS)
181bool CSSFontFace::hasSVGFontFaceSource() const
182{
183    size_t size = m_sources.size();
184    for (size_t i = 0; i < size; i++) {
185        if (m_sources[i]->isSVGFontFaceSource())
186            return true;
187    }
188    return false;
189}
190#endif
191
192}
193