• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
46 using namespace std;
47 
48 namespace WebCore {
49 
SimpleFontData(const FontPlatformData & f,bool customFont,bool loading,SVGFontData * svgFontData)50 SimpleFontData::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.
initCharWidths()110 void 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 
platformGlyphInit()130 void 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 
~SimpleFontData()171 SimpleFontData::~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 
fontDataForCharacter(UChar32) const185 const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const
186 {
187     return this;
188 }
189 
isSegmented() const190 bool SimpleFontData::isSegmented() const
191 {
192     return false;
193 }
194 
195 #ifndef NDEBUG
description() const196 String 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