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