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 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