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 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 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 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 80 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 108 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 121 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 134 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 181 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 222 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