1 /* 2 * Copyright (C) 2007, 2008, 2010 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 "CSSFontFaceSource.h" 28 29 #include "CachedFont.h" 30 #include "CSSFontFace.h" 31 #include "CSSFontSelector.h" 32 #include "CachedResourceLoader.h" 33 #include "FontCache.h" 34 #include "FontDescription.h" 35 #include "GlyphPageTreeNode.h" 36 #include "SimpleFontData.h" 37 38 #if ENABLE(SVG_FONTS) 39 #include "FontCustomPlatformData.h" 40 #include "SVGFontData.h" 41 #include "SVGFontElement.h" 42 #include "SVGFontFaceElement.h" 43 #include "SVGNames.h" 44 #include "SVGURIReference.h" 45 #endif 46 47 namespace WebCore { 48 49 CSSFontFaceSource::CSSFontFaceSource(const String& str, CachedFont* font) 50 : m_string(str) 51 , m_font(font) 52 , m_face(0) 53 #if ENABLE(SVG_FONTS) 54 , m_hasExternalSVGFont(false) 55 #endif 56 { 57 if (m_font) 58 m_font->addClient(this); 59 } 60 61 CSSFontFaceSource::~CSSFontFaceSource() 62 { 63 if (m_font) 64 m_font->removeClient(this); 65 pruneTable(); 66 } 67 68 void CSSFontFaceSource::pruneTable() 69 { 70 if (m_fontDataTable.isEmpty()) 71 return; 72 73 HashMap<unsigned, SimpleFontData*>::iterator end = m_fontDataTable.end(); 74 for (HashMap<unsigned, SimpleFontData*>::iterator it = m_fontDataTable.begin(); it != end; ++it) 75 m_face->retireCustomFont(it->second); 76 77 m_fontDataTable.clear(); 78 } 79 80 bool CSSFontFaceSource::isLoaded() const 81 { 82 if (m_font) 83 return m_font->isLoaded(); 84 return true; 85 } 86 87 bool CSSFontFaceSource::isValid() const 88 { 89 if (m_font) 90 return !m_font->errorOccurred(); 91 return true; 92 } 93 94 void CSSFontFaceSource::fontLoaded(CachedFont*) 95 { 96 pruneTable(); 97 if (m_face) 98 m_face->fontLoaded(this); 99 } 100 101 SimpleFontData* CSSFontFaceSource::getFontData(const FontDescription& fontDescription, bool syntheticBold, bool syntheticItalic, CSSFontSelector* fontSelector) 102 { 103 // If the font hasn't loaded or an error occurred, then we've got nothing. 104 if (!isValid()) 105 return 0; 106 107 #if ENABLE(SVG_FONTS) 108 if (!m_font && !m_svgFontFaceElement) { 109 #else 110 if (!m_font) { 111 #endif 112 SimpleFontData* fontData = fontCache()->getCachedFontData(fontDescription, m_string); 113 114 // We're local. Just return a SimpleFontData from the normal cache. 115 return fontData; 116 } 117 118 // See if we have a mapping in our FontData cache. 119 unsigned hashKey = (fontDescription.computedPixelSize() + 1) << 6 | fontDescription.widthVariant() << 4 120 | (fontDescription.textOrientation() == TextOrientationUpright ? 8 : 0) | (fontDescription.orientation() == Vertical ? 4 : 0) | (syntheticBold ? 2 : 0) | (syntheticItalic ? 1 : 0); 121 if (SimpleFontData* cachedData = m_fontDataTable.get(hashKey)) 122 return cachedData; 123 124 OwnPtr<SimpleFontData> fontData; 125 126 // If we are still loading, then we let the system pick a font. 127 if (isLoaded()) { 128 if (m_font) { 129 #if ENABLE(SVG_FONTS) 130 if (m_hasExternalSVGFont) { 131 // For SVG fonts parse the external SVG document, and extract the <font> element. 132 if (!m_font->ensureSVGFontData()) 133 return 0; 134 135 if (!m_externalSVGFontElement) 136 m_externalSVGFontElement = m_font->getSVGFontById(SVGURIReference::getTarget(m_string)); 137 138 if (!m_externalSVGFontElement) 139 return 0; 140 141 SVGFontFaceElement* fontFaceElement = 0; 142 143 // Select first <font-face> child 144 for (Node* fontChild = m_externalSVGFontElement->firstChild(); fontChild; fontChild = fontChild->nextSibling()) { 145 if (fontChild->hasTagName(SVGNames::font_faceTag)) { 146 fontFaceElement = static_cast<SVGFontFaceElement*>(fontChild); 147 break; 148 } 149 } 150 151 if (fontFaceElement) { 152 if (!m_svgFontFaceElement) { 153 // We're created using a CSS @font-face rule, that means we're not associated with a SVGFontFaceElement. 154 // Use the imported <font-face> tag as referencing font-face element for these cases. 155 m_svgFontFaceElement = fontFaceElement; 156 } 157 158 fontData.set(new SimpleFontData(adoptPtr(new SVGFontData(fontFaceElement)), fontDescription.computedPixelSize(), syntheticBold, syntheticItalic)); 159 } 160 } else 161 #endif 162 { 163 // Create new FontPlatformData from our CGFontRef, point size and ATSFontRef. 164 if (!m_font->ensureCustomFontData()) 165 return 0; 166 167 fontData.set(new SimpleFontData(m_font->platformDataFromCustomData(fontDescription.computedPixelSize(), syntheticBold, syntheticItalic, fontDescription.orientation(), 168 fontDescription.textOrientation(), fontDescription.widthVariant(), fontDescription.renderingMode()), true, false)); 169 } 170 } else { 171 #if ENABLE(SVG_FONTS) 172 // In-Document SVG Fonts 173 if (m_svgFontFaceElement) 174 fontData.set(new SimpleFontData(adoptPtr(new SVGFontData(m_svgFontFaceElement.get())), fontDescription.computedPixelSize(), syntheticBold, syntheticItalic)); 175 #endif 176 } 177 } else { 178 // Kick off the load now. 179 if (CachedResourceLoader* cachedResourceLoader = fontSelector->cachedResourceLoader()) 180 m_font->beginLoadIfNeeded(cachedResourceLoader); 181 // FIXME: m_string is a URL so it makes no sense to pass it as a family name. 182 SimpleFontData* tempData = fontCache()->getCachedFontData(fontDescription, m_string); 183 if (!tempData) 184 tempData = fontCache()->getLastResortFallbackFont(fontDescription); 185 186 fontData.set(new SimpleFontData(tempData->platformData(), true, true)); 187 } 188 189 SimpleFontData* fontDataRawPtr = fontData.leakPtr(); 190 m_fontDataTable.set(hashKey, fontDataRawPtr); 191 192 return fontDataRawPtr; 193 } 194 195 #if ENABLE(SVG_FONTS) 196 SVGFontFaceElement* CSSFontFaceSource::svgFontFaceElement() const 197 { 198 return m_svgFontFaceElement.get(); 199 } 200 201 void CSSFontFaceSource::setSVGFontFaceElement(PassRefPtr<SVGFontFaceElement> element) 202 { 203 m_svgFontFaceElement = element; 204 } 205 206 bool CSSFontFaceSource::isSVGFontFaceSource() const 207 { 208 return m_svgFontFaceElement || m_hasExternalSVGFont; 209 } 210 #endif 211 212 } 213