Home | History | Annotate | Download | only in fonts
      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