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 "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(0) 44 , m_fontSelectorVersion(0) 45 , m_familyIndex(0) 46 , m_generation(FontCache::fontCache()->generation()) 47 , m_pitch(UnknownPitch) 48 , m_loadingCustomFonts(false) 49 { 50 } 51 52 void FontFallbackList::invalidate(PassRefPtr<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_loadingCustomFonts = 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_loadingCustomFonts) 97 return true; 98 99 unsigned numFonts = m_fontList.size(); 100 for (unsigned i = 0; i < numFonts; ++i) { 101 if (m_fontList[i]->isCustomFont() && m_fontList[i]->isLoading()) { 102 m_loadingCustomFonts = true; 103 return true; 104 } 105 } 106 return false; 107 } 108 109 const FontData* FontFallbackList::primaryFontData(const FontDescription& fontDescription) const 110 { 111 for (unsigned fontIndex = 0; ; ++fontIndex) { 112 const FontData* fontData = fontDataAt(fontDescription, fontIndex); 113 if (!fontData) { 114 // All fonts are custom fonts and are loading. Return the first FontData. 115 // FIXME: Correct fallback to the default font. 116 return fontDataAt(fontDescription, 0); 117 } 118 119 // When a custom font is loading, we should use the correct fallback font to layout the text. 120 // Here skip the temporary font for the loading custom font which may not act as the correct fallback font. 121 if (!fontData->isLoadingFallback()) 122 return fontData; 123 124 // Begin to load the first custom font if needed. 125 if (!fontIndex) { 126 const SimpleFontData* simpleFontData = fontData->fontDataForCharacter(' '); 127 if (simpleFontData && simpleFontData->customFontData()) 128 simpleFontData->customFontData()->beginLoadIfNeeded(); 129 } 130 } 131 } 132 133 PassRefPtr<FontData> FontFallbackList::getFontData(const FontDescription& fontDescription, int& familyIndex) const 134 { 135 RefPtr<FontData> result; 136 137 int startIndex = familyIndex; 138 const FontFamily* startFamily = &fontDescription.family(); 139 for (int i = 0; startFamily && i < startIndex; i++) 140 startFamily = startFamily->next(); 141 const FontFamily* currFamily = startFamily; 142 while (currFamily && !result) { 143 familyIndex++; 144 if (currFamily->family().length()) { 145 if (m_fontSelector) 146 result = m_fontSelector->getFontData(fontDescription, currFamily->family()); 147 148 if (!result) 149 result = FontCache::fontCache()->getFontData(fontDescription, currFamily->family()); 150 } 151 currFamily = currFamily->next(); 152 } 153 154 if (!currFamily) 155 familyIndex = cAllFamiliesScanned; 156 157 if (result || startIndex) 158 return result.release(); 159 160 // If it's the primary font that we couldn't find, we try the following. In all other cases, we will 161 // just use per-character system fallback. 162 163 if (m_fontSelector) { 164 // Try the user's preferred standard font. 165 if (RefPtr<FontData> data = m_fontSelector->getFontData(fontDescription, FontFamilyNames::webkit_standard)) 166 return data.release(); 167 } 168 169 // Still no result. Hand back our last resort fallback font. 170 return FontCache::fontCache()->getLastResortFallbackFont(fontDescription); 171 } 172 173 174 const FontData* FontFallbackList::fontDataAt(const FontDescription& fontDescription, unsigned realizedFontIndex) const 175 { 176 if (realizedFontIndex < m_fontList.size()) 177 return m_fontList[realizedFontIndex].get(); // This fallback font is already in our list. 178 179 // Make sure we're not passing in some crazy value here. 180 ASSERT(realizedFontIndex == m_fontList.size()); 181 182 if (m_familyIndex == cAllFamiliesScanned) 183 return 0; 184 185 // Ask the font cache for the font data. 186 // We are obtaining this font for the first time. We keep track of the families we've looked at before 187 // in |m_familyIndex|, so that we never scan the same spot in the list twice. getFontData will adjust our 188 // |m_familyIndex| as it scans for the right font to make. 189 ASSERT(FontCache::fontCache()->generation() == m_generation); 190 RefPtr<FontData> result = getFontData(fontDescription, m_familyIndex); 191 if (result) { 192 m_fontList.append(result); 193 if (result->isLoading()) 194 m_loadingCustomFonts = true; 195 } 196 return result.get(); 197 } 198 199 void FontFallbackList::setPlatformFont(const FontPlatformData& platformData) 200 { 201 m_familyIndex = cAllFamiliesScanned; 202 RefPtr<FontData> fontData = FontCache::fontCache()->fontDataFromFontPlatformData(&platformData); 203 m_fontList.append(fontData); 204 } 205 206 } 207