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