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 
SimpleFontData(const FontPlatformData & platformData,bool isCustomFont,bool isLoading,bool isTextOrientationFallback)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)
SimpleFontData(PassOwnPtr<SVGFontData> svgFontData,int size,bool syntheticBold,bool syntheticItalic)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<SVGGlyph> 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<SVGGlyph> spaceGlyphs;
105     associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs);
106     m_spaceWidth = spaceGlyphs.isEmpty() ? xHeight : spaceGlyphs.first().horizontalAdvanceX * scale;
107 
108     Vector<SVGGlyph> numeralZeroGlyphs;
109     associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs);
110     m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : numeralZeroGlyphs.first().horizontalAdvanceX * scale;
111 
112     Vector<SVGGlyph> 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 SVGGlyph 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) && !HAVE(QRAWFONT))
126 // Estimates of avgCharWidth and maxCharWidth for platforms that don't support accessing these values from the font.
initCharWidths()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 
platformGlyphInit()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 
~SimpleFontData()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 
fontDataForCharacter(UChar32) const197 const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const
198 {
199     return this;
200 }
201 
isSegmented() const202 bool SimpleFontData::isSegmented() const
203 {
204     return false;
205 }
206 
verticalRightOrientationFontData() const207 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 = adoptPtr(new SimpleFontData(verticalRightPlatformData, isCustomFont(), false, true));
215     }
216     return m_derivedFontData->verticalRightOrientation.get();
217 }
218 
uprightOrientationFontData() const219 SimpleFontData* SimpleFontData::uprightOrientationFontData() const
220 {
221     if (!m_derivedFontData)
222         m_derivedFontData = DerivedFontData::create(isCustomFont());
223     if (!m_derivedFontData->uprightOrientation)
224         m_derivedFontData->uprightOrientation = adoptPtr(new SimpleFontData(m_platformData, isCustomFont(), false, true));
225     return m_derivedFontData->uprightOrientation.get();
226 }
227 
brokenIdeographFontData() const228 SimpleFontData* SimpleFontData::brokenIdeographFontData() const
229 {
230     if (!m_derivedFontData)
231         m_derivedFontData = DerivedFontData::create(isCustomFont());
232     if (!m_derivedFontData->brokenIdeograph) {
233         m_derivedFontData->brokenIdeograph = adoptPtr(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
description() const240 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 
create(bool forCustomFont)251 PassOwnPtr<SimpleFontData::DerivedFontData> SimpleFontData::DerivedFontData::create(bool forCustomFont)
252 {
253     return adoptPtr(new DerivedFontData(forCustomFont));
254 }
255 
~DerivedFontData()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