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