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 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 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. 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 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 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 151 const SimpleFontData* SimpleFontData::fontDataForCharacter(UChar32) const 152 { 153 return this; 154 } 155 156 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 163 bool SimpleFontData::isSegmented() const 164 { 165 return false; 166 } 167 168 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 180 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 189 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 199 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 209 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 220 PassOwnPtr<SimpleFontData::DerivedFontData> SimpleFontData::DerivedFontData::create(bool forCustomFont) 221 { 222 return adoptPtr(new DerivedFontData(forCustomFont)); 223 } 224 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 242 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