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