1 /* 2 * Copyright (C) 2005, 2008, 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2006 Alexey Proskuryakov 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "config.h" 31 #include "SimpleFontData.h" 32 33 #include "Font.h" 34 #include "FontCache.h" 35 36 #if ENABLE(SVG_FONTS) 37 #include "SVGFontData.h" 38 #include "SVGFontElement.h" 39 #include "SVGFontFaceElement.h" 40 #include "SVGGlyphElement.h" 41 #endif 42 43 #include <wtf/MathExtras.h> 44 #include <wtf/UnusedParam.h> 45 46 using namespace std; 47 48 namespace WebCore { 49 50 SimpleFontData::SimpleFontData(const FontPlatformData& platformData, bool isCustomFont, bool isLoading, bool isTextOrientationFallback) 51 : m_maxCharWidth(-1) 52 , m_avgCharWidth(-1) 53 , m_platformData(platformData) 54 , m_treatAsFixedPitch(false) 55 , m_isCustomFont(isCustomFont) 56 , m_isLoading(isLoading) 57 , m_isTextOrientationFallback(isTextOrientationFallback) 58 , m_isBrokenIdeographFallback(false) 59 , m_hasVerticalGlyphs(false) 60 { 61 platformInit(); 62 platformGlyphInit(); 63 platformCharWidthInit(); 64 } 65 66 #if ENABLE(SVG_FONTS) 67 SimpleFontData::SimpleFontData(PassOwnPtr<SVGFontData> svgFontData, int size, bool syntheticBold, bool syntheticItalic) 68 : m_platformData(FontPlatformData(size, syntheticBold, syntheticItalic)) 69 , m_treatAsFixedPitch(false) 70 , m_svgFontData(svgFontData) 71 , m_isCustomFont(true) 72 , m_isLoading(false) 73 , m_isTextOrientationFallback(false) 74 , m_isBrokenIdeographFallback(false) 75 , m_hasVerticalGlyphs(false) 76 { 77 SVGFontFaceElement* svgFontFaceElement = m_svgFontData->svgFontFaceElement(); 78 unsigned unitsPerEm = svgFontFaceElement->unitsPerEm(); 79 80 float scale = size; 81 if (unitsPerEm) 82 scale /= unitsPerEm; 83 84 float xHeight = svgFontFaceElement->xHeight() * scale; 85 float ascent = svgFontFaceElement->ascent() * scale; 86 float descent = svgFontFaceElement->descent() * scale; 87 float lineGap = 0.1f * size; 88 89 SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); 90 if (!xHeight) { 91 // Fallback if x_heightAttr is not specified for the font element. 92 Vector<SVGGlyphIdentifier> letterXGlyphs; 93 associatedFontElement->getGlyphIdentifiersForString(String("x", 1), letterXGlyphs); 94 xHeight = letterXGlyphs.isEmpty() ? 2 * ascent / 3 : letterXGlyphs.first().horizontalAdvanceX * scale; 95 } 96 97 m_fontMetrics.setUnitsPerEm(unitsPerEm); 98 m_fontMetrics.setAscent(ascent); 99 m_fontMetrics.setDescent(descent); 100 m_fontMetrics.setLineGap(lineGap); 101 m_fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap)); 102 m_fontMetrics.setXHeight(xHeight); 103 104 Vector<SVGGlyphIdentifier> spaceGlyphs; 105 associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs); 106 m_spaceWidth = spaceGlyphs.isEmpty() ? xHeight : spaceGlyphs.first().horizontalAdvanceX * scale; 107 108 Vector<SVGGlyphIdentifier> numeralZeroGlyphs; 109 associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs); 110 m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : numeralZeroGlyphs.first().horizontalAdvanceX * scale; 111 112 Vector<SVGGlyphIdentifier> letterWGlyphs; 113 associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs); 114 m_maxCharWidth = letterWGlyphs.isEmpty() ? ascent : letterWGlyphs.first().horizontalAdvanceX * scale; 115 116 // FIXME: is there a way we can get the space glyph from the SVGGlyphIdentifier above? 117 m_spaceGlyph = 0; 118 m_zeroWidthSpaceGlyph = 0; 119 determinePitch(); 120 m_missingGlyphData.fontData = this; 121 m_missingGlyphData.glyph = 0; 122 } 123 #endif 124 125 #if !PLATFORM(QT) 126 // Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font. 127 void SimpleFontData::initCharWidths() 128 { 129 GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); 130 131 // Treat the width of a '0' as the avgCharWidth. 132 if (m_avgCharWidth <= 0.f && glyphPageZero) { 133 static const UChar32 digitZeroChar = '0'; 134 Glyph digitZeroGlyph = glyphPageZero->glyphDataForCharacter(digitZeroChar).glyph; 135 if (digitZeroGlyph) 136 m_avgCharWidth = widthForGlyph(digitZeroGlyph); 137 } 138 139 // If we can't retrieve the width of a '0', fall back to the x height. 140 if (m_avgCharWidth <= 0.f) 141 m_avgCharWidth = m_fontMetrics.xHeight(); 142 143 if (m_maxCharWidth <= 0.f) 144 m_maxCharWidth = max(m_avgCharWidth, m_fontMetrics.floatAscent()); 145 } 146 147 void SimpleFontData::platformGlyphInit() 148 { 149 GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); 150 if (!glyphPageZero) { 151 LOG_ERROR("Failed to get glyph page zero."); 152 m_spaceGlyph = 0; 153 m_spaceWidth = 0; 154 determinePitch(); 155 m_zeroWidthSpaceGlyph = 0; 156 m_missingGlyphData.fontData = this; 157 m_missingGlyphData.glyph = 0; 158 return; 159 } 160 161 m_zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph; 162 163 // Nasty hack to determine if we should round or ceil space widths. 164 // If the font is monospace or fake monospace we ceil to ensure that 165 // every character and the space are the same width. Otherwise we round. 166 m_spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph; 167 float width = widthForGlyph(m_spaceGlyph); 168 m_spaceWidth = width; 169 determinePitch(); 170 171 // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is shared with SPACE. 172 // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph. 173 // See <http://bugs.webkit.org/show_bug.cgi?id=13178> 174 // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0, 175 // are mapped to the ZERO WIDTH SPACE glyph. 176 if (m_zeroWidthSpaceGlyph == m_spaceGlyph) { 177 m_zeroWidthSpaceGlyph = 0; 178 LOG_ERROR("Font maps SPACE and ZERO WIDTH SPACE to the same glyph. Glyph width will not be overridden."); 179 } 180 181 m_missingGlyphData.fontData = this; 182 m_missingGlyphData.glyph = 0; 183 } 184 #endif 185 186 SimpleFontData::~SimpleFontData() 187 { 188 #if ENABLE(SVG_FONTS) 189 if (!m_svgFontData || !m_svgFontData->svgFontFaceElement()) 190 #endif 191 platformDestroy(); 192 193 if (!isCustomFont()) 194 GlyphPageTreeNode::pruneTreeFontData(this); 195 } 196 197 const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const 198 { 199 return this; 200 } 201 202 bool SimpleFontData::isSegmented() const 203 { 204 return false; 205 } 206 207 SimpleFontData* SimpleFontData::verticalRightOrientationFontData() const 208 { 209 if (!m_derivedFontData) 210 m_derivedFontData = DerivedFontData::create(isCustomFont()); 211 if (!m_derivedFontData->verticalRightOrientation) { 212 FontPlatformData verticalRightPlatformData(m_platformData); 213 verticalRightPlatformData.setOrientation(Horizontal); 214 m_derivedFontData->verticalRightOrientation = new SimpleFontData(verticalRightPlatformData, isCustomFont(), false, true); 215 } 216 return m_derivedFontData->verticalRightOrientation.get(); 217 } 218 219 SimpleFontData* SimpleFontData::uprightOrientationFontData() const 220 { 221 if (!m_derivedFontData) 222 m_derivedFontData = DerivedFontData::create(isCustomFont()); 223 if (!m_derivedFontData->uprightOrientation) 224 m_derivedFontData->uprightOrientation = new SimpleFontData(m_platformData, isCustomFont(), false, true); 225 return m_derivedFontData->uprightOrientation.get(); 226 } 227 228 SimpleFontData* SimpleFontData::brokenIdeographFontData() const 229 { 230 if (!m_derivedFontData) 231 m_derivedFontData = DerivedFontData::create(isCustomFont()); 232 if (!m_derivedFontData->brokenIdeograph) { 233 m_derivedFontData->brokenIdeograph = new SimpleFontData(m_platformData, isCustomFont(), false); 234 m_derivedFontData->brokenIdeograph->m_isBrokenIdeographFallback = true; 235 } 236 return m_derivedFontData->brokenIdeograph.get(); 237 } 238 239 #ifndef NDEBUG 240 String SimpleFontData::description() const 241 { 242 if (isSVGFont()) 243 return "[SVG font]"; 244 if (isCustomFont()) 245 return "[custom font]"; 246 247 return platformData().description(); 248 } 249 #endif 250 251 PassOwnPtr<SimpleFontData::DerivedFontData> SimpleFontData::DerivedFontData::create(bool forCustomFont) 252 { 253 return adoptPtr(new DerivedFontData(forCustomFont)); 254 } 255 256 SimpleFontData::DerivedFontData::~DerivedFontData() 257 { 258 if (!forCustomFont) 259 return; 260 261 if (smallCaps) 262 GlyphPageTreeNode::pruneTreeCustomFontData(smallCaps.get()); 263 if (emphasisMark) 264 GlyphPageTreeNode::pruneTreeCustomFontData(emphasisMark.get()); 265 if (brokenIdeograph) 266 GlyphPageTreeNode::pruneTreeCustomFontData(brokenIdeograph.get()); 267 if (verticalRightOrientation) 268 GlyphPageTreeNode::pruneTreeCustomFontData(verticalRightOrientation.get()); 269 if (uprightOrientation) 270 GlyphPageTreeNode::pruneTreeCustomFontData(uprightOrientation.get()); 271 } 272 273 } // namespace WebCore 274