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 38 namespace WebCore { 39 40 FontFallbackList::FontFallbackList() 41 : m_pageZero(0) 42 , m_cachedPrimarySimpleFontData(0) 43 , m_fontSelector(nullptr) 44 , m_fontSelectorVersion(0) 45 , m_familyIndex(0) 46 , m_generation(FontCache::fontCache()->generation()) 47 , m_pitch(UnknownPitch) 48 , m_hasLoadingFallback(false) 49 { 50 } 51 52 void FontFallbackList::invalidate(PassRefPtrWillBeRawPtr<FontSelector> fontSelector) 53 { 54 releaseFontData(); 55 m_fontList.clear(); 56 m_pageZero = 0; 57 m_pages.clear(); 58 m_cachedPrimarySimpleFontData = 0; 59 m_familyIndex = 0; 60 m_pitch = UnknownPitch; 61 m_hasLoadingFallback = false; 62 m_fontSelector = fontSelector; 63 m_fontSelectorVersion = m_fontSelector ? m_fontSelector->version() : 0; 64 m_generation = FontCache::fontCache()->generation(); 65 m_widthCache.clear(); 66 } 67 68 void FontFallbackList::releaseFontData() 69 { 70 unsigned numFonts = m_fontList.size(); 71 for (unsigned i = 0; i < numFonts; ++i) { 72 if (!m_fontList[i]->isCustomFont()) { 73 ASSERT(!m_fontList[i]->isSegmented()); 74 FontCache::fontCache()->releaseFontData(static_cast<const SimpleFontData*>(m_fontList[i].get())); 75 } 76 } 77 } 78 79 void FontFallbackList::determinePitch(const FontDescription& fontDescription) const 80 { 81 const FontData* fontData = primaryFontData(fontDescription); 82 if (!fontData->isSegmented()) 83 m_pitch = static_cast<const SimpleFontData*>(fontData)->pitch(); 84 else { 85 const SegmentedFontData* segmentedFontData = static_cast<const SegmentedFontData*>(fontData); 86 unsigned numRanges = segmentedFontData->numRanges(); 87 if (numRanges == 1 && segmentedFontData->rangeAt(0).isEntireRange()) 88 m_pitch = segmentedFontData->rangeAt(0).fontData()->pitch(); 89 else 90 m_pitch = VariablePitch; 91 } 92 } 93 94 bool FontFallbackList::loadingCustomFonts() const 95 { 96 if (!m_hasLoadingFallback) 97 return false; 98 99 unsigned numFonts = m_fontList.size(); 100 for (unsigned i = 0; i < numFonts; ++i) { 101 if (m_fontList[i]->isLoading()) 102 return true; 103 } 104 return false; 105 } 106 107 bool FontFallbackList::shouldSkipDrawing() const 108 { 109 if (!m_hasLoadingFallback) 110 return false; 111 112 unsigned numFonts = m_fontList.size(); 113 for (unsigned i = 0; i < numFonts; ++i) { 114 if (m_fontList[i]->shouldSkipDrawing()) 115 return true; 116 } 117 return false; 118 } 119 120 const FontData* FontFallbackList::primaryFontData(const FontDescription& fontDescription) const 121 { 122 bool shouldLoadCustomFont = true; 123 124 for (unsigned fontIndex = 0; ; ++fontIndex) { 125 const FontData* fontData = fontDataAt(fontDescription, fontIndex); 126 if (!fontData) { 127 // All fonts are custom fonts and are loading. Return the first FontData. 128 fontData = fontDataAt(fontDescription, 0); 129 if (fontData) 130 return fontData->fontDataForCharacter(' '); 131 132 SimpleFontData* lastResortFallback = FontCache::fontCache()->getLastResortFallbackFont(fontDescription).get(); 133 ASSERT(lastResortFallback); 134 return lastResortFallback; 135 } 136 137 if (fontData->isSegmented() && !toSegmentedFontData(fontData)->containsCharacter(' ')) 138 continue; 139 140 const SimpleFontData* simpleFontData = fontData->fontDataForCharacter(' '); 141 ASSERT(simpleFontData); 142 143 // When a custom font is loading, we should use the correct fallback font to layout the text. 144 // Here skip the temporary font for the loading custom font which may not act as the correct fallback font. 145 if (!simpleFontData->isLoadingFallback()) 146 return fontData; 147 148 // Begin to load the first custom font if needed. 149 if (shouldLoadCustomFont) { 150 shouldLoadCustomFont = false; 151 simpleFontData->customFontData()->beginLoadIfNeeded(); 152 } 153 } 154 } 155 156 PassRefPtr<FontData> FontFallbackList::getFontData(const FontDescription& fontDescription, int& familyIndex) const 157 { 158 RefPtr<FontData> result; 159 160 int startIndex = familyIndex; 161 const FontFamily* startFamily = &fontDescription.family(); 162 for (int i = 0; startFamily && i < startIndex; i++) 163 startFamily = startFamily->next(); 164 const FontFamily* currFamily = startFamily; 165 while (currFamily && !result) { 166 familyIndex++; 167 if (currFamily->family().length()) { 168 if (m_fontSelector) 169 result = m_fontSelector->getFontData(fontDescription, currFamily->family()); 170 171 if (!result) 172 result = FontCache::fontCache()->getFontData(fontDescription, currFamily->family()); 173 } 174 currFamily = currFamily->next(); 175 } 176 177 if (!currFamily) 178 familyIndex = cAllFamiliesScanned; 179 180 if (result || startIndex) 181 return result.release(); 182 183 // If it's the primary font that we couldn't find, we try the following. In all other cases, we will 184 // just use per-character system fallback. 185 186 if (m_fontSelector) { 187 // Try the user's preferred standard font. 188 if (RefPtr<FontData> data = m_fontSelector->getFontData(fontDescription, FontFamilyNames::webkit_standard)) 189 return data.release(); 190 } 191 192 // Still no result. Hand back our last resort fallback font. 193 return FontCache::fontCache()->getLastResortFallbackFont(fontDescription); 194 } 195 196 197 const FontData* FontFallbackList::fontDataAt(const FontDescription& fontDescription, unsigned realizedFontIndex) const 198 { 199 if (realizedFontIndex < m_fontList.size()) 200 return m_fontList[realizedFontIndex].get(); // This fallback font is already in our list. 201 202 // Make sure we're not passing in some crazy value here. 203 ASSERT(realizedFontIndex == m_fontList.size()); 204 205 if (m_familyIndex == cAllFamiliesScanned) 206 return 0; 207 208 // Ask the font cache for the font data. 209 // We are obtaining this font for the first time. We keep track of the families we've looked at before 210 // in |m_familyIndex|, so that we never scan the same spot in the list twice. getFontData will adjust our 211 // |m_familyIndex| as it scans for the right font to make. 212 ASSERT(FontCache::fontCache()->generation() == m_generation); 213 RefPtr<FontData> result = getFontData(fontDescription, m_familyIndex); 214 if (result) { 215 m_fontList.append(result); 216 if (result->isLoadingFallback()) 217 m_hasLoadingFallback = true; 218 } 219 return result.get(); 220 } 221 222 } 223