• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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