Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  *
      4  * This library is free software; you can redistribute it and/or
      5  * modify it under the terms of the GNU Library General Public
      6  * License as published by the Free Software Foundation; either
      7  * version 2 of the License, or (at your option) any later version.
      8  *
      9  * This library is distributed in the hope that it will be useful,
     10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12  * Library General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Library General Public License
     15  * along with this library; see the file COPYING.LIB.  If not, write to
     16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     17  * Boston, MA 02110-1301, USA.
     18  */
     19 
     20 #include "config.h"
     21 
     22 #if ENABLE(SVG_FONTS)
     23 #include "core/svg/SVGFontData.h"
     24 
     25 #include "SVGNames.h"
     26 #include "XMLNames.h"
     27 #include "core/platform/graphics/SVGGlyph.h"
     28 #include "core/platform/graphics/TextRun.h"
     29 #include "core/platform/graphics/WidthIterator.h"
     30 #include "core/rendering/RenderObject.h"
     31 #include "core/rendering/svg/SVGTextRunRenderingContext.h"
     32 #include "core/svg/SVGAltGlyphElement.h"
     33 #include "core/svg/SVGFontElement.h"
     34 #include "core/svg/SVGFontFaceElement.h"
     35 #include "core/svg/SVGGlyphElement.h"
     36 #include "wtf/text/StringBuilder.h"
     37 #include "wtf/unicode/CharacterNames.h"
     38 #include "wtf/unicode/Unicode.h"
     39 
     40 using namespace WTF;
     41 using namespace Unicode;
     42 
     43 namespace WebCore {
     44 
     45 SVGFontData::SVGFontData(SVGFontFaceElement* fontFaceElement)
     46     : m_svgFontFaceElement(fontFaceElement)
     47     , m_horizontalOriginX(fontFaceElement->horizontalOriginX())
     48     , m_horizontalOriginY(fontFaceElement->horizontalOriginY())
     49     , m_horizontalAdvanceX(fontFaceElement->horizontalAdvanceX())
     50     , m_verticalOriginX(fontFaceElement->verticalOriginX())
     51     , m_verticalOriginY(fontFaceElement->verticalOriginY())
     52     , m_verticalAdvanceY(fontFaceElement->verticalAdvanceY())
     53 {
     54     ASSERT_ARG(fontFaceElement, fontFaceElement);
     55 }
     56 
     57 void SVGFontData::initializeFontData(SimpleFontData* fontData, float fontSize)
     58 {
     59     ASSERT(fontData);
     60 
     61     SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
     62     ASSERT(svgFontFaceElement);
     63 
     64     SVGFontElement* svgFontElement = svgFontFaceElement->associatedFontElement();
     65     ASSERT(svgFontElement);
     66     GlyphData missingGlyphData;
     67     missingGlyphData.fontData = fontData;
     68     missingGlyphData.glyph = svgFontElement->missingGlyph();
     69     fontData->setMissingGlyphData(missingGlyphData);
     70 
     71     fontData->setZeroWidthSpaceGlyph(0);
     72     fontData->determinePitch();
     73 
     74     unsigned unitsPerEm = svgFontFaceElement->unitsPerEm();
     75     float scale = scaleEmToUnits(fontSize, unitsPerEm);
     76     float xHeight = svgFontFaceElement->xHeight() * scale;
     77     float ascent = svgFontFaceElement->ascent() * scale;
     78     float descent = svgFontFaceElement->descent() * scale;
     79     float lineGap = 0.1f * fontSize;
     80 
     81     GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(fontData, 0)->page();
     82 
     83     if (!xHeight && glyphPageZero) {
     84         // Fallback if x_heightAttr is not specified for the font element.
     85         Glyph letterXGlyph = glyphPageZero->glyphDataForCharacter('x').glyph;
     86         xHeight = letterXGlyph ? fontData->widthForGlyph(letterXGlyph) : 2 * ascent / 3;
     87     }
     88 
     89     FontMetrics& fontMetrics = fontData->fontMetrics();
     90     fontMetrics.setUnitsPerEm(unitsPerEm);
     91     fontMetrics.setAscent(ascent);
     92     fontMetrics.setDescent(descent);
     93     fontMetrics.setLineGap(lineGap);
     94     fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap));
     95     fontMetrics.setXHeight(xHeight);
     96 
     97     if (!glyphPageZero) {
     98         fontData->setSpaceGlyph(0);
     99         fontData->setSpaceWidth(0);
    100         fontData->setAvgCharWidth(0);
    101         fontData->setMaxCharWidth(ascent);
    102         return;
    103     }
    104 
    105     // Calculate space width.
    106     Glyph spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph;
    107     fontData->setSpaceGlyph(spaceGlyph);
    108     fontData->setSpaceWidth(fontData->widthForGlyph(spaceGlyph));
    109 
    110     // Estimate average character width.
    111     Glyph numeralZeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph;
    112     fontData->setAvgCharWidth(numeralZeroGlyph ? fontData->widthForGlyph(numeralZeroGlyph) : fontData->spaceWidth());
    113 
    114     // Estimate maximum character width.
    115     Glyph letterWGlyph = glyphPageZero->glyphDataForCharacter('W').glyph;
    116     fontData->setMaxCharWidth(letterWGlyph ? fontData->widthForGlyph(letterWGlyph) : ascent);
    117 }
    118 
    119 float SVGFontData::widthForSVGGlyph(Glyph glyph, float fontSize) const
    120 {
    121     SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
    122     ASSERT(svgFontFaceElement);
    123 
    124     SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
    125     ASSERT(associatedFontElement);
    126 
    127     SVGGlyph svgGlyph = associatedFontElement->svgGlyphForGlyph(glyph);
    128     SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, this);
    129     return svgGlyph.horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm());
    130 }
    131 
    132 bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength) const
    133 {
    134     const TextRun& run = iterator.run();
    135     Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms();
    136     ASSERT(int(run.charactersLength()) >= currentCharacter);
    137 
    138     // Associate text with arabic forms, if needed.
    139     String remainingTextInRun;
    140 
    141     if (run.is8Bit()) {
    142         remainingTextInRun = String(run.data8(currentCharacter), run.charactersLength() - currentCharacter);
    143         remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters8(), remainingTextInRun.length());
    144     } else {
    145         remainingTextInRun = String(run.data16(currentCharacter), run.charactersLength() - currentCharacter);
    146         remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters16(), remainingTextInRun.length());
    147     }
    148 
    149     if (mirror)
    150         remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun);
    151     if (!currentCharacter && arabicForms.isEmpty())
    152         arabicForms = charactersWithArabicForm(remainingTextInRun, mirror);
    153 
    154     SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
    155     ASSERT(svgFontFaceElement);
    156 
    157     SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
    158     ASSERT(associatedFontElement);
    159 
    160     RenderObject* renderObject = 0;
    161     if (TextRun::RenderingContext* renderingContext = run.renderingContext())
    162         renderObject = static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer();
    163 
    164     String language;
    165     bool isVerticalText = false;
    166     Vector<String> altGlyphNames;
    167 
    168     if (renderObject) {
    169         RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject;
    170         ASSERT(parentRenderObject);
    171 
    172         isVerticalText = parentRenderObject->style()->svgStyle()->isVerticalWritingMode();
    173         if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) {
    174             language = parentRenderObjectElement->getAttribute(XMLNames::langAttr);
    175 
    176             if (parentRenderObjectElement->hasTagName(SVGNames::altGlyphTag)) {
    177                 SVGAltGlyphElement* altGlyph = static_cast<SVGAltGlyphElement*>(parentRenderObjectElement);
    178                 if (!altGlyph->hasValidGlyphElements(altGlyphNames))
    179                     altGlyphNames.clear();
    180             }
    181         }
    182     }
    183 
    184     Vector<SVGGlyph> glyphs;
    185     size_t altGlyphNamesSize = altGlyphNames.size();
    186     if (altGlyphNamesSize) {
    187         for (size_t index = 0; index < altGlyphNamesSize; ++index)
    188             associatedFontElement->collectGlyphsForGlyphName(altGlyphNames[index], glyphs);
    189 
    190         // Assign the unicodeStringLength now that its known.
    191         size_t glyphsSize = glyphs.size();
    192         for (size_t i = 0; i < glyphsSize; ++i)
    193             glyphs[i].unicodeStringLength = run.length();
    194 
    195         // Do not check alt glyphs for compatibility. Just return the first one.
    196         // Later code will fail if we do not do this and the glyph is incompatible.
    197         if (glyphsSize) {
    198             SVGGlyph& svgGlyph = glyphs[0];
    199             iterator.setLastGlyphName(svgGlyph.glyphName);
    200             glyphData.glyph = svgGlyph.tableEntry;
    201             advanceLength = svgGlyph.unicodeStringLength;
    202             return true;
    203         }
    204     } else
    205         associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs);
    206 
    207     size_t glyphsSize = glyphs.size();
    208     for (size_t i = 0; i < glyphsSize; ++i) {
    209         SVGGlyph& svgGlyph = glyphs[i];
    210         if (svgGlyph.isPartOfLigature)
    211             continue;
    212         if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength))
    213             continue;
    214         iterator.setLastGlyphName(svgGlyph.glyphName);
    215         glyphData.glyph = svgGlyph.tableEntry;
    216         advanceLength = svgGlyph.unicodeStringLength;
    217         return true;
    218     }
    219 
    220     iterator.setLastGlyphName(String());
    221     return false;
    222 }
    223 
    224 bool SVGFontData::fillSVGGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) const
    225 {
    226     ASSERT(fontData->isCustomFont());
    227     ASSERT(fontData->isSVGFont());
    228 
    229     SVGFontFaceElement* fontFaceElement = this->svgFontFaceElement();
    230     ASSERT(fontFaceElement);
    231 
    232     SVGFontElement* fontElement = fontFaceElement->associatedFontElement();
    233     ASSERT(fontElement);
    234 
    235     if (bufferLength == length)
    236         return fillBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData);
    237 
    238     ASSERT(bufferLength == 2 * length);
    239     return fillNonBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData);
    240 }
    241 
    242 bool SVGFontData::fillBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
    243 {
    244     bool haveGlyphs = false;
    245     Vector<SVGGlyph> glyphs;
    246     for (unsigned i = 0; i < length; ++i) {
    247         String lookupString(buffer + i, 1);
    248         fontElement->collectGlyphsForString(lookupString, glyphs);
    249         if (glyphs.isEmpty()) {
    250             pageToFill->setGlyphDataForIndex(offset + i, 0, 0);
    251             continue;
    252         }
    253 
    254         // Associate entry in glyph page with first valid SVGGlyph.
    255         // If there are multiple valid ones, just take the first one. WidthIterator will take
    256         // care of matching to the correct glyph, if multiple ones are available, as that's
    257         // only possible within the context of a string (eg. arabic form matching).
    258         haveGlyphs = true;
    259         pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
    260         glyphs.clear();
    261     }
    262 
    263     return haveGlyphs;
    264 }
    265 
    266 bool SVGFontData::fillNonBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
    267 {
    268     bool haveGlyphs = false;
    269     Vector<SVGGlyph> glyphs;
    270     for (unsigned i = 0; i < length; ++i) {
    271         // Each character here consists of a surrogate pair
    272         String lookupString(buffer + i * 2, 2);
    273         fontElement->collectGlyphsForString(lookupString, glyphs);
    274         if (glyphs.isEmpty()) {
    275             pageToFill->setGlyphDataForIndex(offset + i, 0, 0);
    276             continue;
    277         }
    278 
    279         // Associate entry in glyph page with first valid SVGGlyph.
    280         // If there are multiple valid ones, just take the first one. WidthIterator will take
    281         // care of matching to the correct glyph, if multiple ones are available, as that's
    282         // only possible within the context of a string (eg. arabic form matching).
    283         haveGlyphs = true;
    284         pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
    285         glyphs.clear();
    286     }
    287 
    288     return haveGlyphs;
    289 }
    290 
    291 String SVGFontData::createStringWithMirroredCharacters(const String& string) const
    292 {
    293     if (string.isEmpty())
    294         return emptyString();
    295 
    296     unsigned length = string.length();
    297 
    298     StringBuilder mirroredCharacters;
    299     mirroredCharacters.reserveCapacity(length);
    300 
    301     if (string.is8Bit()) {
    302         const LChar* characters = string.characters8();
    303         for (unsigned i = 0; i < length; ++i)
    304             mirroredCharacters.append(mirroredChar(characters[i]));
    305     } else {
    306         const UChar* characters = string.characters16();
    307         unsigned i = 0;
    308         while (i < length) {
    309             UChar32 character;
    310             U16_NEXT(characters, i, length, character);
    311             mirroredCharacters.append(mirroredChar(character));
    312         }
    313     }
    314 
    315     return mirroredCharacters.toString();
    316 }
    317 
    318 } // namespace WebCore
    319 
    320 #endif
    321