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(nullptr)
     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(nullptr)
     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     // As GlyphPage::size is power of 2 so shifting is valid
    164     GlyphPageTreeNode* node = GlyphPageTreeNode::getRootChild(this, character >> GlyphPage::sizeBits);
    165     return node->page() ? node->page()->glyphAt(character & 0xFF) : 0;
    166 }
    167 
    168 bool SimpleFontData::isSegmented() const
    169 {
    170     return false;
    171 }
    172 
    173 PassRefPtr<SimpleFontData> SimpleFontData::verticalRightOrientationFontData() const
    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(verticalRightPlatformData, isCustomFont() ? CustomFontData::create(): nullptr, 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, isCustomFont() ? CustomFontData::create(): nullptr, true);
    191     return m_derivedFontData->uprightOrientation;
    192 }
    193 
    194 PassRefPtr<SimpleFontData> SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
    195 {
    196     if (!m_derivedFontData)
    197         m_derivedFontData = DerivedFontData::create(isCustomFont());
    198     if (!m_derivedFontData->smallCaps)
    199         m_derivedFontData->smallCaps = createScaledFontData(fontDescription, smallCapsFontSizeMultiplier);
    200 
    201     return m_derivedFontData->smallCaps;
    202 }
    203 
    204 PassRefPtr<SimpleFontData> SimpleFontData::emphasisMarkFontData(const FontDescription& 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(): nullptr);
    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::create(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 FontDescription& fontDescription, float scaleFactor) const
    260 {
    261     // FIXME: Support scaled SVG fonts. Given that SVG is scalable in general this should be achievable.
    262     if (isSVGFont())
    263         return nullptr;
    264 
    265     return platformCreateScaledFontData(fontDescription, scaleFactor);
    266 }
    267 
    268 } // namespace WebCore
    269