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