1/* 2 * Copyright (C) 2005, 2008 Apple Computer, 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 46using namespace std; 47 48namespace WebCore { 49 50SimpleFontData::SimpleFontData(const FontPlatformData& f, bool customFont, bool loading, SVGFontData* svgFontData) 51 : m_maxCharWidth(-1) 52 , m_avgCharWidth(-1) 53 , m_unitsPerEm(defaultUnitsPerEm) 54 , m_platformData(f) 55 , m_treatAsFixedPitch(false) 56#if ENABLE(SVG_FONTS) 57 , m_svgFontData(svgFontData) 58#endif 59 , m_isCustomFont(customFont) 60 , m_isLoading(loading) 61 , m_smallCapsFontData(0) 62{ 63#if !ENABLE(SVG_FONTS) 64 UNUSED_PARAM(svgFontData); 65#else 66 if (SVGFontFaceElement* svgFontFaceElement = svgFontData ? svgFontData->svgFontFaceElement() : 0) { 67 m_unitsPerEm = svgFontFaceElement->unitsPerEm(); 68 69 double scale = f.size(); 70 if (m_unitsPerEm) 71 scale /= m_unitsPerEm; 72 73 m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale); 74 m_descent = static_cast<int>(svgFontFaceElement->descent() * scale); 75 m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale); 76 m_lineGap = 0.1f * f.size(); 77 m_lineSpacing = m_ascent + m_descent + m_lineGap; 78 79 SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); 80 81 Vector<SVGGlyphIdentifier> spaceGlyphs; 82 associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs); 83 m_spaceWidth = spaceGlyphs.isEmpty() ? m_xHeight : static_cast<float>(spaceGlyphs.first().horizontalAdvanceX * scale); 84 85 Vector<SVGGlyphIdentifier> numeralZeroGlyphs; 86 associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs); 87 m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : static_cast<float>(numeralZeroGlyphs.first().horizontalAdvanceX * scale); 88 89 Vector<SVGGlyphIdentifier> letterWGlyphs; 90 associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs); 91 m_maxCharWidth = letterWGlyphs.isEmpty() ? m_ascent : static_cast<float>(letterWGlyphs.first().horizontalAdvanceX * scale); 92 93 // FIXME: is there a way we can get the space glyph from the SVGGlyphIdentifier above? 94 m_spaceGlyph = 0; 95 determinePitch(); 96 m_adjustedSpaceWidth = roundf(m_spaceWidth); 97 m_missingGlyphData.fontData = this; 98 m_missingGlyphData.glyph = 0; 99 return; 100 } 101#endif 102 103 platformInit(); 104 platformGlyphInit(); 105 platformCharWidthInit(); 106} 107 108#if !PLATFORM(QT) 109// Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font. 110void SimpleFontData::initCharWidths() 111{ 112 GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); 113 114 // Treat the width of a '0' as the avgCharWidth. 115 if (m_avgCharWidth <= 0.f && glyphPageZero) { 116 static const UChar32 digitZeroChar = '0'; 117 Glyph digitZeroGlyph = glyphPageZero->glyphDataForCharacter(digitZeroChar).glyph; 118 if (digitZeroGlyph) 119 m_avgCharWidth = widthForGlyph(digitZeroGlyph); 120 } 121 122 // If we can't retrieve the width of a '0', fall back to the x height. 123 if (m_avgCharWidth <= 0.f) 124 m_avgCharWidth = m_xHeight; 125 126 if (m_maxCharWidth <= 0.f) 127 m_maxCharWidth = max<float>(m_avgCharWidth, m_ascent); 128} 129 130void SimpleFontData::platformGlyphInit() 131{ 132 GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); 133 if (!glyphPageZero) { 134 LOG_ERROR("Failed to get glyph page zero."); 135 m_spaceGlyph = 0; 136 m_spaceWidth = 0; 137 m_adjustedSpaceWidth = 0; 138 determinePitch(); 139 m_missingGlyphData.fontData = this; 140 m_missingGlyphData.glyph = 0; 141 return; 142 } 143 144 // Nasty hack to determine if we should round or ceil space widths. 145 // If the font is monospace or fake monospace we ceil to ensure that 146 // every character and the space are the same width. Otherwise we round. 147 m_spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph; 148 float width = widthForGlyph(m_spaceGlyph); 149 m_spaceWidth = width; 150 determinePitch(); 151 m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width); 152 153 // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is shared with SPACE. 154 // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph. 155 // See <http://bugs.webkit.org/show_bug.cgi?id=13178> 156 // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control characters, including 0, 157 // are mapped to the ZERO WIDTH SPACE glyph. 158 Glyph zeroWidthSpaceGlyph = glyphPageZero->glyphDataForCharacter(0).glyph; 159 if (zeroWidthSpaceGlyph) { 160 if (zeroWidthSpaceGlyph != m_spaceGlyph) 161 m_glyphToWidthMap.setWidthForGlyph(zeroWidthSpaceGlyph, 0); 162 else 163 LOG_ERROR("Font maps SPACE and ZERO WIDTH SPACE to the same glyph. Glyph width not overridden."); 164 } 165 166 m_missingGlyphData.fontData = this; 167 m_missingGlyphData.glyph = 0; 168} 169#endif 170 171SimpleFontData::~SimpleFontData() 172{ 173#if ENABLE(SVG_FONTS) 174 if (!m_svgFontData || !m_svgFontData->svgFontFaceElement()) 175#endif 176 platformDestroy(); 177 178 if (!isCustomFont()) { 179 if (m_smallCapsFontData) 180 fontCache()->releaseFontData(m_smallCapsFontData); 181 GlyphPageTreeNode::pruneTreeFontData(this); 182 } 183} 184 185const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const 186{ 187 return this; 188} 189 190bool SimpleFontData::isSegmented() const 191{ 192 return false; 193} 194 195#ifndef NDEBUG 196String SimpleFontData::description() const 197{ 198 if (isSVGFont()) 199 return "[SVG font]"; 200 if (isCustomFont()) 201 return "[custom font]"; 202 203 return platformData().description(); 204} 205#endif 206 207} // namespace WebCore 208