Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / css / CSSFontFace.cpp
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 "core/css/CSSFontFace.h"
28
29 #include "core/css/CSSFontSelector.h"
30 #include "core/css/CSSSegmentedFontFace.h"
31 #include "core/css/FontFaceSet.h"
32 #include "core/dom/Document.h"
33 #include "core/frame/UseCounter.h"
34 #include "platform/fonts/SimpleFontData.h"
35
36 namespace WebCore {
37
38 void CSSFontFace::addSource(PassOwnPtr<CSSFontFaceSource> source)
39 {
40     source->setFontFace(this);
41     m_sources.append(source);
42 }
43
44 void CSSFontFace::setSegmentedFontFace(CSSSegmentedFontFace* segmentedFontFace)
45 {
46     ASSERT(!m_segmentedFontFace);
47     m_segmentedFontFace = segmentedFontFace;
48 }
49
50 void CSSFontFace::beginLoadIfNeeded(CSSFontFaceSource* source, CSSFontSelector* fontSelector)
51 {
52     if (source->resource() && source->resource()->stillNeedsLoad()) {
53         if (!fontSelector) {
54             if (!m_segmentedFontFace)
55                 return;
56             fontSelector = m_segmentedFontFace->fontSelector();
57         }
58         fontSelector->beginLoadingFontSoon(source->resource());
59     }
60
61     if (loadStatus() == FontFace::Unloaded)
62         setLoadStatus(FontFace::Loading);
63 }
64
65 void CSSFontFace::fontLoaded(CSSFontFaceSource* source)
66 {
67     if (m_segmentedFontFace)
68         m_segmentedFontFace->fontSelector()->fontLoaded();
69
70     if (!isValid() || source != m_sources.first())
71         return;
72
73     if (loadStatus() == FontFace::Loading) {
74         if (source->ensureFontData()) {
75             setLoadStatus(FontFace::Loaded);
76             Document* document = m_segmentedFontFace ? m_segmentedFontFace->fontSelector()->document() : 0;
77             if (document && source->isSVGFontFaceSource())
78                 UseCounter::count(*document, UseCounter::SVGFontInCSS);
79         } else {
80             m_sources.removeFirst();
81             if (!isValid())
82                 setLoadStatus(FontFace::Error);
83         }
84     }
85
86     if (m_segmentedFontFace)
87         m_segmentedFontFace->fontLoaded(this);
88 }
89
90 PassRefPtr<SimpleFontData> CSSFontFace::getFontData(const FontDescription& fontDescription)
91 {
92     if (!isValid())
93         return 0;
94
95     while (!m_sources.isEmpty()) {
96         OwnPtr<CSSFontFaceSource>& source = m_sources.first();
97         if (RefPtr<SimpleFontData> result = source->getFontData(fontDescription)) {
98             if (loadStatus() == FontFace::Unloaded && (source->isLoading() || source->isLoaded()))
99                 setLoadStatus(FontFace::Loading);
100             if (loadStatus() == FontFace::Loading && source->isLoaded())
101                 setLoadStatus(FontFace::Loaded);
102             return result.release();
103         }
104         m_sources.removeFirst();
105     }
106
107     if (loadStatus() == FontFace::Unloaded)
108         setLoadStatus(FontFace::Loading);
109     if (loadStatus() == FontFace::Loading)
110         setLoadStatus(FontFace::Error);
111     return 0;
112 }
113
114 void CSSFontFace::willUseFontData(const FontDescription& fontDescription)
115 {
116     // Kicks off font load here only if the @font-face has no unicode-range.
117     // @font-faces with unicode-range will be loaded when a GlyphPage for the
118     // font is created.
119     // FIXME: Pass around the text to render from RenderText, and kick download
120     // if m_ranges intersects with the text. Make sure this does not cause
121     // performance regression.
122     if (m_ranges.isEntireRange())
123         load(fontDescription);
124 }
125
126 void CSSFontFace::load(const FontDescription& fontDescription, CSSFontSelector* fontSelector)
127 {
128     if (loadStatus() != FontFace::Unloaded)
129         return;
130     setLoadStatus(FontFace::Loading);
131
132     while (!m_sources.isEmpty()) {
133         OwnPtr<CSSFontFaceSource>& source = m_sources.first();
134         if (source->isValid()) {
135             if (source->isLocal()) {
136                 if (source->isLocalFontAvailable(fontDescription)) {
137                     setLoadStatus(FontFace::Loaded);
138                     return;
139                 }
140             } else {
141                 if (!source->isLoaded()) {
142                     beginLoadIfNeeded(source.get(), fontSelector);
143                 } else {
144                     setLoadStatus(FontFace::Loaded);
145                 }
146                 return;
147             }
148         }
149         m_sources.removeFirst();
150     }
151     setLoadStatus(FontFace::Error);
152 }
153
154 void CSSFontFace::setLoadStatus(FontFace::LoadStatus newStatus)
155 {
156     ASSERT(m_fontFace);
157     m_fontFace->setLoadStatus(newStatus);
158
159     if (!m_segmentedFontFace)
160         return;
161     Document* document = m_segmentedFontFace->fontSelector()->document();
162     if (!document)
163         return;
164
165     switch (newStatus) {
166     case FontFace::Loading:
167         FontFaceSet::from(document)->beginFontLoading(m_fontFace);
168         break;
169     case FontFace::Loaded:
170         FontFaceSet::from(document)->fontLoaded(m_fontFace);
171         break;
172     case FontFace::Error:
173         FontFaceSet::from(document)->loadError(m_fontFace);
174         break;
175     default:
176         break;
177     }
178 }
179
180 bool CSSFontFace::UnicodeRangeSet::intersectsWith(const String& text) const
181 {
182     if (text.isEmpty())
183         return false;
184     if (isEntireRange())
185         return true;
186
187     // FIXME: This takes O(text.length() * m_ranges.size()) time. It would be
188     // better to make m_ranges sorted and use binary search.
189     unsigned index = 0;
190     while (index < text.length()) {
191         UChar32 c = text.characterStartingAt(index);
192         index += U16_LENGTH(c);
193         for (unsigned i = 0; i < m_ranges.size(); i++) {
194             if (m_ranges[i].contains(c))
195                 return true;
196         }
197     }
198     return false;
199 }
200
201 }