Home | History | Annotate | Download | only in chromium
      1 /*
      2  * Copyright (c) 2008, 2009, Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "SimpleFontData.h"
     33 
     34 #include "Font.h"
     35 #include "FontCache.h"
     36 #include "FloatRect.h"
     37 #include "FontDescription.h"
     38 #include "Logging.h"
     39 #include "VDMXParser.h"
     40 
     41 #include "SkFontHost.h"
     42 #include "SkPaint.h"
     43 #include "SkTime.h"
     44 #include "SkTypeface.h"
     45 #include "SkTypes.h"
     46 
     47 namespace WebCore {
     48 
     49 // Smallcaps versions of fonts are 70% the size of the normal font.
     50 static const float smallCapsFraction = 0.7f;
     51 static const float emphasisMarkFraction = .5;
     52 // This is the largest VDMX table which we'll try to load and parse.
     53 static const size_t maxVDMXTableSize = 1024 * 1024;  // 1 MB
     54 
     55 void SimpleFontData::platformInit()
     56 {
     57     if (!m_platformData.size()) {
     58         m_fontMetrics.reset();
     59         m_avgCharWidth = 0;
     60         m_maxCharWidth = 0;
     61         return;
     62     }
     63 
     64     SkPaint paint;
     65     SkPaint::FontMetrics metrics;
     66 
     67     m_platformData.setupPaint(&paint);
     68     paint.getFontMetrics(&metrics);
     69     const SkFontID fontID = m_platformData.uniqueID();
     70 
     71     static const uint32_t vdmxTag = SkSetFourByteTag('V', 'D', 'M', 'X');
     72     int pixelSize = m_platformData.size() + 0.5;
     73     int vdmxAscent, vdmxDescent;
     74     bool isVDMXValid = false;
     75 
     76     size_t vdmxSize = SkFontHost::GetTableSize(fontID, vdmxTag);
     77     if (vdmxSize && vdmxSize < maxVDMXTableSize) {
     78         uint8_t* vdmxTable = (uint8_t*) fastMalloc(vdmxSize);
     79         if (vdmxTable
     80             && SkFontHost::GetTableData(fontID, vdmxTag, 0, vdmxSize, vdmxTable) == vdmxSize
     81             && parseVDMX(&vdmxAscent, &vdmxDescent, vdmxTable, vdmxSize, pixelSize))
     82             isVDMXValid = true;
     83         fastFree(vdmxTable);
     84     }
     85 
     86     float ascent;
     87     float descent;
     88 
     89     // Beware those who step here: This code is designed to match Win32 font
     90     // metrics *exactly*.
     91     if (isVDMXValid) {
     92         ascent = vdmxAscent;
     93         descent = -vdmxDescent;
     94     } else {
     95         SkScalar height = -metrics.fAscent + metrics.fDescent + metrics.fLeading;
     96         ascent = SkScalarRound(-metrics.fAscent);
     97         descent = SkScalarRound(height) - ascent;
     98     }
     99 
    100     m_fontMetrics.setAscent(ascent);
    101     m_fontMetrics.setDescent(descent);
    102 
    103     float xHeight;
    104     if (metrics.fXHeight)
    105         xHeight = metrics.fXHeight;
    106     else {
    107         // hack taken from the Windows port
    108         xHeight = ascent * 0.56f;
    109     }
    110 
    111     float lineGap = SkScalarToFloat(metrics.fLeading);
    112     m_fontMetrics.setLineGap(lineGap);
    113     m_fontMetrics.setXHeight(xHeight);
    114     m_fontMetrics.setLineSpacing(lroundf(ascent) + lroundf(descent) + lroundf(lineGap));
    115 
    116     if (platformData().orientation() == Vertical && !isTextOrientationFallback()) {
    117         static const uint32_t vheaTag = SkSetFourByteTag('v', 'h', 'e', 'a');
    118         static const uint32_t vorgTag = SkSetFourByteTag('V', 'O', 'R', 'G');
    119         size_t vheaSize = SkFontHost::GetTableSize(fontID, vheaTag);
    120         size_t vorgSize = SkFontHost::GetTableSize(fontID, vorgTag);
    121         if ((vheaSize > 0) || (vorgSize > 0))
    122             m_hasVerticalGlyphs = true;
    123     }
    124 
    125     // In WebKit/WebCore/platform/graphics/SimpleFontData.cpp, m_spaceWidth is
    126     // calculated for us, but we need to calculate m_maxCharWidth and
    127     // m_avgCharWidth in order for text entry widgets to be sized correctly.
    128 
    129     SkScalar xRange = metrics.fXMax - metrics.fXMin;
    130     m_maxCharWidth = SkScalarRound(xRange * SkScalarRound(m_platformData.size()));
    131 
    132     if (metrics.fAvgCharWidth)
    133         m_avgCharWidth = SkScalarRound(metrics.fAvgCharWidth);
    134     else {
    135         m_avgCharWidth = xHeight;
    136 
    137         GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(this, 0)->page();
    138 
    139         if (glyphPageZero) {
    140             static const UChar32 x_char = 'x';
    141             const Glyph xGlyph = glyphPageZero->glyphDataForCharacter(x_char).glyph;
    142 
    143             if (xGlyph)
    144                 m_avgCharWidth = widthForGlyph(xGlyph);
    145         }
    146     }
    147 }
    148 
    149 void SimpleFontData::platformCharWidthInit()
    150 {
    151     // charwidths are set in platformInit.
    152 }
    153 
    154 void SimpleFontData::platformDestroy()
    155 {
    156 }
    157 
    158 SimpleFontData* SimpleFontData::scaledFontData(const FontDescription& fontDescription, float scaleFactor) const
    159 {
    160     const float scaledSize = lroundf(fontDescription.computedSize() * scaleFactor);
    161     return new SimpleFontData(FontPlatformData(m_platformData, scaledSize), isCustomFont(), false);
    162 }
    163 
    164 SimpleFontData* SimpleFontData::smallCapsFontData(const FontDescription& fontDescription) const
    165 {
    166     if (!m_derivedFontData)
    167         m_derivedFontData = DerivedFontData::create(isCustomFont());
    168     if (!m_derivedFontData->smallCaps)
    169         m_derivedFontData->smallCaps = scaledFontData(fontDescription, smallCapsFraction);
    170 
    171     return m_derivedFontData->smallCaps.get();
    172 }
    173 
    174 SimpleFontData* SimpleFontData::emphasisMarkFontData(const FontDescription& fontDescription) const
    175 {
    176     if (!m_derivedFontData)
    177         m_derivedFontData = DerivedFontData::create(isCustomFont());
    178     if (!m_derivedFontData->emphasisMark)
    179         m_derivedFontData->emphasisMark = scaledFontData(fontDescription, emphasisMarkFraction);
    180 
    181     return m_derivedFontData->emphasisMark.get();
    182 }
    183 
    184 bool SimpleFontData::containsCharacters(const UChar* characters, int length) const
    185 {
    186     SkPaint paint;
    187     static const unsigned maxBufferCount = 64;
    188     uint16_t glyphs[maxBufferCount];
    189 
    190     m_platformData.setupPaint(&paint);
    191     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
    192 
    193     while (length > 0) {
    194         int n = SkMin32(length, SK_ARRAY_COUNT(glyphs));
    195 
    196         // textToGlyphs takes a byte count so we double the character count.
    197         int count = paint.textToGlyphs(characters, n * 2, glyphs);
    198         for (int i = 0; i < count; i++) {
    199             if (0 == glyphs[i])
    200                 return false;       // missing glyph
    201         }
    202 
    203         characters += n;
    204         length -= n;
    205     }
    206 
    207     return true;
    208 }
    209 
    210 void SimpleFontData::determinePitch()
    211 {
    212     m_treatAsFixedPitch = platformData().isFixedPitch();
    213 }
    214 
    215 FloatRect SimpleFontData::platformBoundsForGlyph(Glyph) const
    216 {
    217     return FloatRect();
    218 }
    219 
    220 float SimpleFontData::platformWidthForGlyph(Glyph glyph) const
    221 {
    222     if (!m_platformData.size())
    223         return 0;
    224 
    225     SkASSERT(sizeof(glyph) == 2);   // compile-time assert
    226 
    227     SkPaint paint;
    228 
    229     m_platformData.setupPaint(&paint);
    230 
    231     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    232     SkScalar width = paint.measureText(&glyph, 2);
    233 
    234     // Though WebKit supports non-integral advances, Skia only supports them
    235     // for "subpixel" (distinct from LCD subpixel antialiasing) text, which
    236     // we don't use.
    237     return round(SkScalarToFloat(width));
    238 }
    239 
    240 }  // namespace WebCore
    241