1 /*
2 * Copyright (C) 2006 Apple Computer, 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 *
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 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "config.h"
30 #include "platform/fonts/FontFallbackList.h"
31
32 #include "platform/FontFamilyNames.h"
33 #include "platform/fonts/FontCache.h"
34 #include "platform/fonts/FontDescription.h"
35 #include "platform/fonts/FontFamily.h"
36 #include "platform/fonts/SegmentedFontData.h"
37 #include "wtf/unicode/CharacterNames.h"
38
39 namespace blink {
40
FontFallbackList()41 FontFallbackList::FontFallbackList()
42 : m_pageZero(0)
43 , m_cachedPrimarySimpleFontData(0)
44 , m_fontSelector(nullptr)
45 , m_fontSelectorVersion(0)
46 , m_familyIndex(0)
47 , m_generation(FontCache::fontCache()->generation())
48 , m_pitch(UnknownPitch)
49 , m_hasLoadingFallback(false)
50 {
51 }
52
invalidate(PassRefPtrWillBeRawPtr<FontSelector> fontSelector)53 void FontFallbackList::invalidate(PassRefPtrWillBeRawPtr<FontSelector> fontSelector)
54 {
55 releaseFontData();
56 m_fontList.clear();
57 m_pageZero = 0;
58 m_pages.clear();
59 m_cachedPrimarySimpleFontData = 0;
60 m_familyIndex = 0;
61 m_pitch = UnknownPitch;
62 m_hasLoadingFallback = false;
63 m_fontSelector = fontSelector;
64 m_fontSelectorVersion = m_fontSelector ? m_fontSelector->version() : 0;
65 m_generation = FontCache::fontCache()->generation();
66 m_widthCache.clear();
67 }
68
releaseFontData()69 void FontFallbackList::releaseFontData()
70 {
71 unsigned numFonts = m_fontList.size();
72 for (unsigned i = 0; i < numFonts; ++i) {
73 if (!m_fontList[i]->isCustomFont()) {
74 ASSERT(!m_fontList[i]->isSegmented());
75 FontCache::fontCache()->releaseFontData(toSimpleFontData(m_fontList[i]));
76 }
77 }
78 }
79
determinePitch(const FontDescription & fontDescription) const80 void FontFallbackList::determinePitch(const FontDescription& fontDescription) const
81 {
82 for (unsigned fontIndex = 0; ; ++fontIndex) {
83 const FontData* fontData = fontDataAt(fontDescription, fontIndex);
84 if (!fontData) {
85 // All fonts are custom fonts and are loading. Fallback should be variable pitch.
86 m_pitch = VariablePitch;
87 break;
88 }
89
90 const SimpleFontData* simpleFontData;
91 if (fontData->isSegmented()) {
92 const SegmentedFontData* segmentedFontData = toSegmentedFontData(fontData);
93 if (segmentedFontData->numRanges() != 1 || !segmentedFontData->rangeAt(0).isEntireRange()) {
94 m_pitch = VariablePitch;
95 break;
96 }
97 simpleFontData = segmentedFontData->rangeAt(0).fontData().get();
98 } else {
99 simpleFontData = toSimpleFontData(fontData);
100 }
101 if (!fontData->isLoadingFallback()) {
102 m_pitch = simpleFontData->pitch();
103 break;
104 }
105 }
106 }
107
loadingCustomFonts() const108 bool FontFallbackList::loadingCustomFonts() const
109 {
110 if (!m_hasLoadingFallback)
111 return false;
112
113 unsigned numFonts = m_fontList.size();
114 for (unsigned i = 0; i < numFonts; ++i) {
115 if (m_fontList[i]->isLoading())
116 return true;
117 }
118 return false;
119 }
120
shouldSkipDrawing() const121 bool FontFallbackList::shouldSkipDrawing() const
122 {
123 if (!m_hasLoadingFallback)
124 return false;
125
126 unsigned numFonts = m_fontList.size();
127 for (unsigned i = 0; i < numFonts; ++i) {
128 if (m_fontList[i]->shouldSkipDrawing())
129 return true;
130 }
131 return false;
132 }
133
determinePrimarySimpleFontData(const FontDescription & fontDescription) const134 const SimpleFontData* FontFallbackList::determinePrimarySimpleFontData(const FontDescription& fontDescription) const
135 {
136 bool shouldLoadCustomFont = true;
137
138 for (unsigned fontIndex = 0; ; ++fontIndex) {
139 const FontData* fontData = fontDataAt(fontDescription, fontIndex);
140 if (!fontData) {
141 // All fonts are custom fonts and are loading. Return the first FontData.
142 fontData = fontDataAt(fontDescription, 0);
143 if (fontData)
144 return fontData->fontDataForCharacter(space);
145
146 SimpleFontData* lastResortFallback = FontCache::fontCache()->getLastResortFallbackFont(fontDescription).get();
147 ASSERT(lastResortFallback);
148 return lastResortFallback;
149 }
150
151 if (fontData->isSegmented() && !toSegmentedFontData(fontData)->containsCharacter(space))
152 continue;
153
154 const SimpleFontData* fontDataForSpace = fontData->fontDataForCharacter(space);
155 ASSERT(fontDataForSpace);
156
157 // When a custom font is loading, we should use the correct fallback font to layout the text.
158 // Here skip the temporary font for the loading custom font which may not act as the correct fallback font.
159 if (!fontDataForSpace->isLoadingFallback())
160 return fontDataForSpace;
161
162 if (fontData->isSegmented()) {
163 const SegmentedFontData* segmented = toSegmentedFontData(fontData);
164 for (unsigned i = 0; i < segmented->numRanges(); i++) {
165 const SimpleFontData* rangeFontData = segmented->rangeAt(i).fontData().get();
166 if (!rangeFontData->isLoadingFallback())
167 return rangeFontData;
168 }
169 if (fontData->isLoading())
170 shouldLoadCustomFont = false;
171 }
172
173 // Begin to load the first custom font if needed.
174 if (shouldLoadCustomFont) {
175 shouldLoadCustomFont = false;
176 fontDataForSpace->customFontData()->beginLoadIfNeeded();
177 }
178 }
179 }
180
getFontData(const FontDescription & fontDescription,int & familyIndex) const181 PassRefPtr<FontData> FontFallbackList::getFontData(const FontDescription& fontDescription, int& familyIndex) const
182 {
183 RefPtr<FontData> result;
184
185 int startIndex = familyIndex;
186 const FontFamily* startFamily = &fontDescription.family();
187 for (int i = 0; startFamily && i < startIndex; i++)
188 startFamily = startFamily->next();
189 const FontFamily* currFamily = startFamily;
190 while (currFamily && !result) {
191 familyIndex++;
192 if (currFamily->family().length()) {
193 if (m_fontSelector)
194 result = m_fontSelector->getFontData(fontDescription, currFamily->family());
195
196 if (!result)
197 result = FontCache::fontCache()->getFontData(fontDescription, currFamily->family());
198 }
199 currFamily = currFamily->next();
200 }
201
202 if (!currFamily)
203 familyIndex = cAllFamiliesScanned;
204
205 if (result || startIndex)
206 return result.release();
207
208 // If it's the primary font that we couldn't find, we try the following. In all other cases, we will
209 // just use per-character system fallback.
210
211 if (m_fontSelector) {
212 // Try the user's preferred standard font.
213 if (RefPtr<FontData> data = m_fontSelector->getFontData(fontDescription, FontFamilyNames::webkit_standard))
214 return data.release();
215 }
216
217 // Still no result. Hand back our last resort fallback font.
218 return FontCache::fontCache()->getLastResortFallbackFont(fontDescription);
219 }
220
221
fontDataAt(const FontDescription & fontDescription,unsigned realizedFontIndex) const222 const FontData* FontFallbackList::fontDataAt(const FontDescription& fontDescription, unsigned realizedFontIndex) const
223 {
224 if (realizedFontIndex < m_fontList.size())
225 return m_fontList[realizedFontIndex].get(); // This fallback font is already in our list.
226
227 // Make sure we're not passing in some crazy value here.
228 ASSERT(realizedFontIndex == m_fontList.size());
229
230 if (m_familyIndex == cAllFamiliesScanned)
231 return 0;
232
233 // Ask the font cache for the font data.
234 // We are obtaining this font for the first time. We keep track of the families we've looked at before
235 // in |m_familyIndex|, so that we never scan the same spot in the list twice. getFontData will adjust our
236 // |m_familyIndex| as it scans for the right font to make.
237 ASSERT(FontCache::fontCache()->generation() == m_generation);
238 RefPtr<FontData> result = getFontData(fontDescription, m_familyIndex);
239 if (result) {
240 m_fontList.append(result);
241 if (result->isLoadingFallback())
242 m_hasLoadingFallback = true;
243 }
244 return result.get();
245 }
246
247 } // namespace blink
248