1 /* 2 * Copyright (C) 2008 Apple 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "core/css/CSSSegmentedFontFace.h" 28 29 #include "RuntimeEnabledFeatures.h" 30 #include "core/css/CSSFontFace.h" 31 #include "platform/fonts/FontCache.h" 32 #include "platform/fonts/FontDescription.h" 33 #include "platform/fonts/SegmentedFontData.h" 34 #include "platform/fonts/SimpleFontData.h" 35 36 namespace WebCore { 37 38 CSSSegmentedFontFace::CSSSegmentedFontFace(CSSFontSelector* fontSelector, FontTraitsMask traitsMask) 39 : m_fontSelector(fontSelector) 40 , m_traitsMask(traitsMask) 41 { 42 } 43 44 CSSSegmentedFontFace::~CSSSegmentedFontFace() 45 { 46 pruneTable(); 47 unsigned size = m_fontFaces.size(); 48 for (unsigned i = 0; i < size; i++) 49 m_fontFaces[i]->clearSegmentedFontFace(); 50 } 51 52 void CSSSegmentedFontFace::pruneTable() 53 { 54 // Make sure the glyph page tree prunes out all uses of this custom font. 55 if (m_fontDataTable.isEmpty()) 56 return; 57 58 m_fontDataTable.clear(); 59 } 60 61 bool CSSSegmentedFontFace::isValid() const 62 { 63 // Valid if at least one font face is valid. 64 unsigned size = m_fontFaces.size(); 65 for (unsigned i = 0; i < size; i++) { 66 if (m_fontFaces[i]->isValid()) 67 return true; 68 } 69 return false; 70 } 71 72 void CSSSegmentedFontFace::fontLoaded(CSSFontFace*) 73 { 74 pruneTable(); 75 76 if (RuntimeEnabledFeatures::fontLoadEventsEnabled() && !isLoading()) { 77 Vector<RefPtr<LoadFontCallback> > callbacks; 78 m_callbacks.swap(callbacks); 79 for (size_t index = 0; index < callbacks.size(); ++index) { 80 if (isLoaded()) 81 callbacks[index]->notifyLoaded(this); 82 else 83 callbacks[index]->notifyError(this); 84 } 85 } 86 } 87 88 void CSSSegmentedFontFace::appendFontFace(PassRefPtr<CSSFontFace> fontFace) 89 { 90 pruneTable(); 91 fontFace->setSegmentedFontFace(this); 92 m_fontFaces.append(fontFace); 93 } 94 95 void CSSSegmentedFontFace::removeFontFace(PassRefPtr<CSSFontFace> fontFace) 96 { 97 size_t index = m_fontFaces.find(fontFace); 98 if (index != kNotFound) { 99 pruneTable(); 100 m_fontFaces.remove(index); 101 fontFace->clearSegmentedFontFace(); 102 } 103 } 104 105 static void appendFontData(SegmentedFontData* newFontData, PassRefPtr<SimpleFontData> prpFaceFontData, const CSSFontFace::UnicodeRangeSet& ranges) 106 { 107 RefPtr<SimpleFontData> faceFontData = prpFaceFontData; 108 unsigned numRanges = ranges.size(); 109 if (!numRanges) { 110 newFontData->appendRange(FontDataRange(0, 0x7FFFFFFF, faceFontData)); 111 return; 112 } 113 114 for (unsigned j = 0; j < numRanges; ++j) 115 newFontData->appendRange(FontDataRange(ranges.rangeAt(j).from(), ranges.rangeAt(j).to(), faceFontData)); 116 } 117 118 PassRefPtr<FontData> CSSSegmentedFontFace::getFontData(const FontDescription& fontDescription) 119 { 120 if (!isValid()) 121 return 0; 122 123 FontTraitsMask desiredTraitsMask = fontDescription.traitsMask(); 124 AtomicString emptyFontFamily = ""; 125 FontCacheKey key = fontDescription.cacheKey(emptyFontFamily, desiredTraitsMask); 126 127 RefPtr<SegmentedFontData>& fontData = m_fontDataTable.add(key.hash(), 0).iterator->value; 128 if (fontData && fontData->numRanges()) 129 return fontData; // No release, we have a reference to an object in the cache which should retain the ref count it has. 130 131 if (!fontData) 132 fontData = SegmentedFontData::create(); 133 134 FontDescription requestedFontDescription(fontDescription); 135 requestedFontDescription.setTraitsMask(m_traitsMask); 136 requestedFontDescription.setSyntheticBold(!(m_traitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask)) && (desiredTraitsMask & (FontWeight600Mask | FontWeight700Mask | FontWeight800Mask | FontWeight900Mask))); 137 requestedFontDescription.setSyntheticItalic(!(m_traitsMask & FontStyleItalicMask) && (desiredTraitsMask & FontStyleItalicMask)); 138 139 for (int i = m_fontFaces.size() - 1; i >= 0; --i) { 140 if (!m_fontFaces[i]->isValid()) 141 continue; 142 if (RefPtr<SimpleFontData> faceFontData = m_fontFaces[i]->getFontData(requestedFontDescription)) { 143 ASSERT(!faceFontData->isSegmented()); 144 #if ENABLE(SVG_FONTS) 145 // For SVG Fonts that specify that they only support the "normal" variant, we will assume they are incapable 146 // of small-caps synthesis and just ignore the font face. 147 if (faceFontData->isSVGFont() && (desiredTraitsMask & FontVariantSmallCapsMask) && !(m_traitsMask & FontVariantSmallCapsMask)) 148 continue; 149 #endif 150 appendFontData(fontData.get(), faceFontData.release(), m_fontFaces[i]->ranges()); 151 } 152 } 153 if (fontData->numRanges()) 154 return fontData; // No release, we have a reference to an object in the cache which should retain the ref count it has. 155 156 return 0; 157 } 158 159 bool CSSSegmentedFontFace::isLoading() const 160 { 161 unsigned size = m_fontFaces.size(); 162 for (unsigned i = 0; i < size; i++) { 163 if (m_fontFaces[i]->loadStatus() == FontFace::Loading) 164 return true; 165 } 166 return false; 167 } 168 169 bool CSSSegmentedFontFace::isLoaded() const 170 { 171 unsigned size = m_fontFaces.size(); 172 for (unsigned i = 0; i < size; i++) { 173 if (m_fontFaces[i]->loadStatus() != FontFace::Loaded) 174 return false; 175 } 176 return true; 177 } 178 179 void CSSSegmentedFontFace::willUseFontData(const FontDescription& fontDescription) 180 { 181 unsigned size = m_fontFaces.size(); 182 for (unsigned i = 0; i < size; i++) 183 m_fontFaces[i]->willUseFontData(fontDescription); 184 } 185 186 bool CSSSegmentedFontFace::checkFont(const String& text) const 187 { 188 unsigned size = m_fontFaces.size(); 189 for (unsigned i = 0; i < size; i++) { 190 if (m_fontFaces[i]->loadStatus() != FontFace::Loaded && m_fontFaces[i]->ranges().intersectsWith(text)) 191 return false; 192 } 193 return true; 194 } 195 196 void CSSSegmentedFontFace::loadFont(const FontDescription& fontDescription, const String& text, PassRefPtr<LoadFontCallback> callback) 197 { 198 unsigned size = m_fontFaces.size(); 199 for (unsigned i = 0; i < size; i++) { 200 if (m_fontFaces[i]->loadStatus() == FontFace::Unloaded && m_fontFaces[i]->ranges().intersectsWith(text)) { 201 RefPtr<SimpleFontData> fontData = m_fontFaces[i]->getFontData(fontDescription); 202 if (fontData->customFontData()) 203 fontData->customFontData()->beginLoadIfNeeded(); 204 } 205 } 206 207 if (callback) { 208 if (isLoading()) 209 m_callbacks.append(callback); 210 else if (isLoaded()) 211 callback->notifyLoaded(this); 212 else 213 callback->notifyError(this); 214 } 215 } 216 217 Vector<RefPtr<FontFace> > CSSSegmentedFontFace::fontFaces(const String& text) const 218 { 219 Vector<RefPtr<FontFace> > fontFaces; 220 unsigned size = m_fontFaces.size(); 221 for (unsigned i = 0; i < size; i++) { 222 if (m_fontFaces[i]->ranges().intersectsWith(text)) 223 fontFaces.append(m_fontFaces[i]->fontFace()); 224 } 225 return fontFaces; 226 } 227 228 } 229