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