OLD | NEW |
| (Empty) |
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 "core/platform/graphics/SimpleFontData.h" | |
32 | |
33 | |
34 #include "wtf/MathExtras.h" | |
35 | |
36 using namespace std; | |
37 | |
38 namespace WebCore { | |
39 | |
40 const float smallCapsFontSizeMultiplier = 0.7f; | |
41 const float emphasisMarkFontSizeMultiplier = 0.5f; | |
42 | |
43 SimpleFontData::SimpleFontData(const FontPlatformData& platformData, PassRefPtr<
CustomFontData> customData, bool isTextOrientationFallback) | |
44 : m_maxCharWidth(-1) | |
45 , m_avgCharWidth(-1) | |
46 , m_platformData(platformData) | |
47 , m_treatAsFixedPitch(false) | |
48 , m_isTextOrientationFallback(isTextOrientationFallback) | |
49 , m_isBrokenIdeographFallback(false) | |
50 #if ENABLE(OPENTYPE_VERTICAL) | |
51 , m_verticalData(0) | |
52 #endif | |
53 , m_hasVerticalGlyphs(false) | |
54 , m_customFontData(customData) | |
55 { | |
56 platformInit(); | |
57 platformGlyphInit(); | |
58 platformCharWidthInit(); | |
59 #if ENABLE(OPENTYPE_VERTICAL) | |
60 if (platformData.orientation() == Vertical && !isTextOrientationFallback) { | |
61 m_verticalData = platformData.verticalData(); | |
62 m_hasVerticalGlyphs = m_verticalData.get() && m_verticalData->hasVertica
lMetrics(); | |
63 } | |
64 #endif | |
65 } | |
66 | |
67 SimpleFontData::SimpleFontData(PassRefPtr<CustomFontData> customData, float font
Size, bool syntheticBold, bool syntheticItalic) | |
68 : m_platformData(FontPlatformData(fontSize, syntheticBold, syntheticItalic)) | |
69 , m_treatAsFixedPitch(false) | |
70 , m_isTextOrientationFallback(false) | |
71 , m_isBrokenIdeographFallback(false) | |
72 #if ENABLE(OPENTYPE_VERTICAL) | |
73 , m_verticalData(0) | |
74 #endif | |
75 , m_hasVerticalGlyphs(false) | |
76 , m_customFontData(customData) | |
77 { | |
78 if (m_customFontData) | |
79 m_customFontData->initializeFontData(this, fontSize); | |
80 } | |
81 | |
82 // Estimates of avgCharWidth and maxCharWidth for platforms that don't support a
ccessing these values from the font. | |
83 void SimpleFontData::initCharWidths() | |
84 { | |
85 GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); | |
86 | |
87 // Treat the width of a '0' as the avgCharWidth. | |
88 if (m_avgCharWidth <= 0.f && glyphPageZero) { | |
89 static const UChar32 digitZeroChar = '0'; | |
90 Glyph digitZeroGlyph = glyphPageZero->glyphForCharacter(digitZeroChar); | |
91 if (digitZeroGlyph) | |
92 m_avgCharWidth = widthForGlyph(digitZeroGlyph); | |
93 } | |
94 | |
95 // If we can't retrieve the width of a '0', fall back to the x height. | |
96 if (m_avgCharWidth <= 0.f) | |
97 m_avgCharWidth = m_fontMetrics.xHeight(); | |
98 | |
99 if (m_maxCharWidth <= 0.f) | |
100 m_maxCharWidth = max(m_avgCharWidth, m_fontMetrics.floatAscent()); | |
101 } | |
102 | |
103 void SimpleFontData::platformGlyphInit() | |
104 { | |
105 GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page(); | |
106 if (!glyphPageZero) { | |
107 WTF_LOG_ERROR("Failed to get glyph page zero."); | |
108 m_spaceGlyph = 0; | |
109 m_spaceWidth = 0; | |
110 m_zeroGlyph = 0; | |
111 m_adjustedSpaceWidth = 0; | |
112 determinePitch(); | |
113 m_zeroWidthSpaceGlyph = 0; | |
114 m_missingGlyphData.fontData = this; | |
115 m_missingGlyphData.glyph = 0; | |
116 return; | |
117 } | |
118 | |
119 m_zeroWidthSpaceGlyph = glyphPageZero->glyphForCharacter(0); | |
120 | |
121 // Nasty hack to determine if we should round or ceil space widths. | |
122 // If the font is monospace or fake monospace we ceil to ensure that | |
123 // every character and the space are the same width. Otherwise we round. | |
124 m_spaceGlyph = glyphPageZero->glyphForCharacter(' '); | |
125 float width = widthForGlyph(m_spaceGlyph); | |
126 m_spaceWidth = width; | |
127 m_zeroGlyph = glyphPageZero->glyphForCharacter('0'); | |
128 m_fontMetrics.setZeroWidth(widthForGlyph(m_zeroGlyph)); | |
129 determinePitch(); | |
130 m_adjustedSpaceWidth = m_treatAsFixedPitch ? ceilf(width) : roundf(width); | |
131 | |
132 // Force the glyph for ZERO WIDTH SPACE to have zero width, unless it is sha
red with SPACE. | |
133 // Helvetica is an example of a non-zero width ZERO WIDTH SPACE glyph. | |
134 // See <http://bugs.webkit.org/show_bug.cgi?id=13178> | |
135 // Ask for the glyph for 0 to avoid paging in ZERO WIDTH SPACE. Control char
acters, including 0, | |
136 // are mapped to the ZERO WIDTH SPACE glyph. | |
137 if (m_zeroWidthSpaceGlyph == m_spaceGlyph) { | |
138 m_zeroWidthSpaceGlyph = 0; | |
139 WTF_LOG_ERROR("Font maps SPACE and ZERO WIDTH SPACE to the same glyph. G
lyph width will not be overridden."); | |
140 } | |
141 | |
142 m_missingGlyphData.fontData = this; | |
143 m_missingGlyphData.glyph = 0; | |
144 } | |
145 | |
146 SimpleFontData::~SimpleFontData() | |
147 { | |
148 if (!isSVGFont()) | |
149 platformDestroy(); | |
150 | |
151 if (isCustomFont()) | |
152 GlyphPageTreeNode::pruneTreeCustomFontData(this); | |
153 else | |
154 GlyphPageTreeNode::pruneTreeFontData(this); | |
155 } | |
156 | |
157 const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const | |
158 { | |
159 return this; | |
160 } | |
161 | |
162 Glyph SimpleFontData::glyphForCharacter(UChar32 character) const | |
163 { | |
164 GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(this, character /
GlyphPage::size); | |
165 return node->page() ? node->page()->glyphAt(character % GlyphPage::size) : 0
; | |
166 } | |
167 | |
168 bool SimpleFontData::isSegmented() const | |
169 { | |
170 return false; | |
171 } | |
172 | |
173 PassRefPtr<SimpleFontData> SimpleFontData::verticalRightOrientationFontData() co
nst | |
174 { | |
175 if (!m_derivedFontData) | |
176 m_derivedFontData = DerivedFontData::create(isCustomFont()); | |
177 if (!m_derivedFontData->verticalRightOrientation) { | |
178 FontPlatformData verticalRightPlatformData(m_platformData); | |
179 verticalRightPlatformData.setOrientation(Horizontal); | |
180 m_derivedFontData->verticalRightOrientation = create(verticalRightPlatfo
rmData, isCustomFont() ? CustomFontData::create(false): 0, true); | |
181 } | |
182 return m_derivedFontData->verticalRightOrientation; | |
183 } | |
184 | |
185 PassRefPtr<SimpleFontData> SimpleFontData::uprightOrientationFontData() const | |
186 { | |
187 if (!m_derivedFontData) | |
188 m_derivedFontData = DerivedFontData::create(isCustomFont()); | |
189 if (!m_derivedFontData->uprightOrientation) | |
190 m_derivedFontData->uprightOrientation = create(m_platformData, isCustomF
ont() ? CustomFontData::create(false): 0, true); | |
191 return m_derivedFontData->uprightOrientation; | |
192 } | |
193 | |
194 PassRefPtr<SimpleFontData> SimpleFontData::smallCapsFontData(const FontDescripti
on& fontDescription) const | |
195 { | |
196 if (!m_derivedFontData) | |
197 m_derivedFontData = DerivedFontData::create(isCustomFont()); | |
198 if (!m_derivedFontData->smallCaps) | |
199 m_derivedFontData->smallCaps = createScaledFontData(fontDescription, sma
llCapsFontSizeMultiplier); | |
200 | |
201 return m_derivedFontData->smallCaps; | |
202 } | |
203 | |
204 PassRefPtr<SimpleFontData> SimpleFontData::emphasisMarkFontData(const FontDescri
ption& fontDescription) const | |
205 { | |
206 if (!m_derivedFontData) | |
207 m_derivedFontData = DerivedFontData::create(isCustomFont()); | |
208 if (!m_derivedFontData->emphasisMark) | |
209 m_derivedFontData->emphasisMark = createScaledFontData(fontDescription,
emphasisMarkFontSizeMultiplier); | |
210 | |
211 return m_derivedFontData->emphasisMark; | |
212 } | |
213 | |
214 PassRefPtr<SimpleFontData> SimpleFontData::brokenIdeographFontData() const | |
215 { | |
216 if (!m_derivedFontData) | |
217 m_derivedFontData = DerivedFontData::create(isCustomFont()); | |
218 if (!m_derivedFontData->brokenIdeograph) { | |
219 m_derivedFontData->brokenIdeograph = create(m_platformData, isCustomFont
() ? CustomFontData::create(false): 0); | |
220 m_derivedFontData->brokenIdeograph->m_isBrokenIdeographFallback = true; | |
221 } | |
222 return m_derivedFontData->brokenIdeograph; | |
223 } | |
224 | |
225 #ifndef NDEBUG | |
226 String SimpleFontData::description() const | |
227 { | |
228 if (isSVGFont()) | |
229 return "[SVG font]"; | |
230 if (isCustomFont()) | |
231 return "[custom font]"; | |
232 | |
233 return platformData().description(); | |
234 } | |
235 #endif | |
236 | |
237 PassOwnPtr<SimpleFontData::DerivedFontData> SimpleFontData::DerivedFontData::cre
ate(bool forCustomFont) | |
238 { | |
239 return adoptPtr(new DerivedFontData(forCustomFont)); | |
240 } | |
241 | |
242 SimpleFontData::DerivedFontData::~DerivedFontData() | |
243 { | |
244 if (!forCustomFont) | |
245 return; | |
246 | |
247 if (smallCaps) | |
248 GlyphPageTreeNode::pruneTreeCustomFontData(smallCaps.get()); | |
249 if (emphasisMark) | |
250 GlyphPageTreeNode::pruneTreeCustomFontData(emphasisMark.get()); | |
251 if (brokenIdeograph) | |
252 GlyphPageTreeNode::pruneTreeCustomFontData(brokenIdeograph.get()); | |
253 if (verticalRightOrientation) | |
254 GlyphPageTreeNode::pruneTreeCustomFontData(verticalRightOrientation.get(
)); | |
255 if (uprightOrientation) | |
256 GlyphPageTreeNode::pruneTreeCustomFontData(uprightOrientation.get()); | |
257 } | |
258 | |
259 PassRefPtr<SimpleFontData> SimpleFontData::createScaledFontData(const FontDescri
ption& fontDescription, float scaleFactor) const | |
260 { | |
261 // FIXME: Support scaled SVG fonts. Given that SVG is scalable in general th
is should be achievable. | |
262 if (isSVGFont()) | |
263 return 0; | |
264 | |
265 return platformCreateScaledFontData(fontDescription, scaleFactor); | |
266 } | |
267 | |
268 } // namespace WebCore | |
OLD | NEW |