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