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 "core/SVGNames.h"
     26 #include "core/XMLNames.h"
     27 #include "core/rendering/RenderObject.h"
     28 #include "core/rendering/svg/SVGTextRunRenderingContext.h"
     29 #include "core/svg/SVGAltGlyphElement.h"
     30 #include "core/svg/SVGFontElement.h"
     31 #include "core/svg/SVGFontFaceElement.h"
     32 #include "core/svg/SVGGlyphElement.h"
     33 #include "platform/fonts/Character.h"
     34 #include "platform/fonts/SVGGlyph.h"
     35 #include "platform/fonts/SimpleFontData.h"
     36 #include "platform/fonts/WidthIterator.h"
     37 #include "platform/text/TextRun.h"
     38 #include "wtf/text/StringBuilder.h"
     39 #include "wtf/unicode/CharacterNames.h"
     40 #include "wtf/unicode/Unicode.h"
     41 
     42 using namespace WTF;
     43 using namespace Unicode;
     44 
     45 namespace blink {
     46 
     47 SVGFontData::SVGFontData(SVGFontFaceElement* fontFaceElement)
     48     : CustomFontData()
     49     , m_svgFontFaceElement(fontFaceElement->createWeakRef())
     50     , m_horizontalOriginX(fontFaceElement->horizontalOriginX())
     51     , m_horizontalOriginY(fontFaceElement->horizontalOriginY())
     52     , m_horizontalAdvanceX(fontFaceElement->horizontalAdvanceX())
     53     , m_verticalOriginX(fontFaceElement->verticalOriginX())
     54     , m_verticalOriginY(fontFaceElement->verticalOriginY())
     55     , m_verticalAdvanceY(fontFaceElement->verticalAdvanceY())
     56 {
     57     ASSERT_ARG(fontFaceElement, fontFaceElement);
     58 }
     59 
     60 SVGFontData::~SVGFontData()
     61 {
     62 }
     63 
     64 void SVGFontData::initializeFontData(SimpleFontData* fontData, float fontSize)
     65 {
     66     ASSERT(fontData);
     67 
     68     SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
     69 
     70     SVGFontElement* svgFontElement = svgFontFaceElement->associatedFontElement();
     71     ASSERT(svgFontElement);
     72     GlyphData missingGlyphData;
     73     missingGlyphData.fontData = fontData;
     74     missingGlyphData.glyph = svgFontElement->missingGlyph();
     75     fontData->setMissingGlyphData(missingGlyphData);
     76 
     77     fontData->setZeroWidthSpaceGlyph(0);
     78     fontData->determinePitch();
     79 
     80     unsigned unitsPerEm = svgFontFaceElement->unitsPerEm();
     81     float scale = scaleEmToUnits(fontSize, unitsPerEm);
     82     float xHeight = svgFontFaceElement->xHeight() * scale;
     83     float ascent = svgFontFaceElement->ascent() * scale;
     84     float descent = svgFontFaceElement->descent() * scale;
     85     float lineGap = 0.1f * fontSize;
     86 
     87     GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(fontData, 0)->page();
     88 
     89     if (!xHeight && glyphPageZero) {
     90         // Fallback if x_heightAttr is not specified for the font element.
     91         Glyph letterXGlyph = glyphPageZero->glyphForCharacter('x');
     92         xHeight = letterXGlyph ? fontData->widthForGlyph(letterXGlyph) : 2 * ascent / 3;
     93     }
     94 
     95     FontMetrics& fontMetrics = fontData->fontMetrics();
     96     fontMetrics.setUnitsPerEm(unitsPerEm);
     97     fontMetrics.setAscent(ascent);
     98     fontMetrics.setDescent(descent);
     99     fontMetrics.setLineGap(lineGap);
    100     fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap));
    101     fontMetrics.setXHeight(xHeight);
    102 
    103     if (!glyphPageZero) {
    104         fontData->setSpaceGlyph(0);
    105         fontData->setSpaceWidth(0);
    106         fontData->setAvgCharWidth(0);
    107         fontData->setMaxCharWidth(ascent);
    108         return;
    109     }
    110 
    111     // Calculate space width.
    112     Glyph spaceGlyph = glyphPageZero->glyphForCharacter(' ');
    113     fontData->setSpaceGlyph(spaceGlyph);
    114     fontData->setSpaceWidth(fontData->widthForGlyph(spaceGlyph));
    115 
    116     // Estimate average character width.
    117     Glyph numeralZeroGlyph = glyphPageZero->glyphForCharacter('0');
    118     fontData->setAvgCharWidth(numeralZeroGlyph ? fontData->widthForGlyph(numeralZeroGlyph) : fontData->spaceWidth());
    119 
    120     // Estimate maximum character width.
    121     Glyph letterWGlyph = glyphPageZero->glyphForCharacter('W');
    122     fontData->setMaxCharWidth(letterWGlyph ? fontData->widthForGlyph(letterWGlyph) : ascent);
    123 }
    124 
    125 float SVGFontData::widthForSVGGlyph(Glyph glyph, float fontSize) const
    126 {
    127     // FIXME: (http://crbug.com/359380) Width calculation may be triggered after removeNode from the current editing impl.
    128     // The retrieved width is not being used, so here we return a dummy value.
    129     if (shouldSkipDrawing())
    130         return 0.0;
    131 
    132     SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
    133 
    134     // RenderView::clearSelection is invoked while removing some element, e.g.
    135     // Document::nodeWillBeRemoved => FrameSelection::nodeWillBeRemoved => RenderView::clearSelection.
    136     // Since recalc style has not been executed yet, RenderStyle might have some reference to
    137     // SVGFontFaceElement which was also removed.
    138     // In this case, use default horizontalAdvanceX instead of associatedFontElement's one.
    139     if (!svgFontFaceElement->inDocument())
    140         return m_horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm());
    141 
    142     SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
    143     ASSERT(associatedFontElement);
    144 
    145     SVGGlyph svgGlyph = associatedFontElement->svgGlyphForGlyph(glyph);
    146     SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, this);
    147     return svgGlyph.horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm());
    148 }
    149 
    150 bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength) const
    151 {
    152     const TextRun& run = iterator.run();
    153     Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms();
    154     ASSERT(int(run.charactersLength()) >= currentCharacter);
    155 
    156     // Associate text with arabic forms, if needed.
    157     String remainingTextInRun;
    158 
    159     if (run.is8Bit()) {
    160         remainingTextInRun = String(run.data8(currentCharacter), run.charactersLength() - currentCharacter);
    161         remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.characters8(), remainingTextInRun.length());
    162     } else {
    163         remainingTextInRun = String(run.data16(currentCharacter), run.charactersLength() - currentCharacter);
    164         remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.characters16(), remainingTextInRun.length());
    165     }
    166 
    167     if (mirror)
    168         remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun);
    169     if (!currentCharacter && arabicForms.isEmpty())
    170         arabicForms = charactersWithArabicForm(remainingTextInRun, mirror);
    171 
    172     SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
    173     SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
    174     ASSERT(associatedFontElement);
    175 
    176     RenderObject* renderObject = 0;
    177     if (TextRun::RenderingContext* renderingContext = run.renderingContext())
    178         renderObject = static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer();
    179 
    180     String language;
    181     bool isVerticalText = false;
    182     Vector<AtomicString> altGlyphNames;
    183 
    184     if (renderObject) {
    185         RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject;
    186         ASSERT(parentRenderObject);
    187 
    188         isVerticalText = parentRenderObject->style()->svgStyle().isVerticalWritingMode();
    189         if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) {
    190             language = parentRenderObjectElement->getAttribute(XMLNames::langAttr);
    191 
    192             if (isSVGAltGlyphElement(*parentRenderObjectElement)) {
    193                 if (!toSVGAltGlyphElement(*parentRenderObjectElement).hasValidGlyphElements(altGlyphNames))
    194                     altGlyphNames.clear();
    195             }
    196         }
    197     }
    198 
    199     Vector<SVGGlyph> glyphs;
    200     size_t altGlyphNamesSize = altGlyphNames.size();
    201     if (altGlyphNamesSize) {
    202         for (size_t index = 0; index < altGlyphNamesSize; ++index)
    203             associatedFontElement->collectGlyphsForAltGlyphReference(altGlyphNames[index], glyphs);
    204 
    205         // Assign the unicodeStringLength now that its known.
    206         size_t glyphsSize = glyphs.size();
    207         for (size_t i = 0; i < glyphsSize; ++i)
    208             glyphs[i].unicodeStringLength = run.length();
    209 
    210         // Do not check alt glyphs for compatibility. Just return the first one.
    211         // Later code will fail if we do not do this and the glyph is incompatible.
    212         if (glyphsSize) {
    213             SVGGlyph& svgGlyph = glyphs[0];
    214             glyphData.glyph = svgGlyph.tableEntry;
    215             advanceLength = svgGlyph.unicodeStringLength;
    216             return true;
    217         }
    218     } else
    219         associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs);
    220 
    221     size_t glyphsSize = glyphs.size();
    222     for (size_t i = 0; i < glyphsSize; ++i) {
    223         SVGGlyph& svgGlyph = glyphs[i];
    224         if (svgGlyph.isPartOfLigature)
    225             continue;
    226         if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength))
    227             continue;
    228         glyphData.glyph = svgGlyph.tableEntry;
    229         advanceLength = svgGlyph.unicodeStringLength;
    230         return true;
    231     }
    232 
    233     return false;
    234 }
    235 
    236 bool SVGFontData::fillSVGGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) const
    237 {
    238     ASSERT(fontData->isCustomFont());
    239     ASSERT(fontData->isSVGFont());
    240 
    241     SVGFontFaceElement* fontFaceElement = this->svgFontFaceElement();
    242     SVGFontElement* fontElement = fontFaceElement->associatedFontElement();
    243     ASSERT(fontElement);
    244 
    245     if (bufferLength == length)
    246         return fillBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData);
    247 
    248     ASSERT(bufferLength == 2 * length);
    249     return fillNonBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData);
    250 }
    251 
    252 bool SVGFontData::fillBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
    253 {
    254     bool haveGlyphs = false;
    255     Vector<SVGGlyph> glyphs;
    256     for (unsigned i = 0; i < length; ++i) {
    257         String lookupString(buffer + i, 1);
    258         fontElement->collectGlyphsForString(lookupString, glyphs);
    259         if (glyphs.isEmpty())
    260             continue;
    261 
    262         // Associate entry in glyph page with first valid SVGGlyph.
    263         // If there are multiple valid ones, just take the first one. WidthIterator will take
    264         // care of matching to the correct glyph, if multiple ones are available, as that's
    265         // only possible within the context of a string (eg. arabic form matching).
    266         haveGlyphs = true;
    267         pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
    268         glyphs.clear();
    269     }
    270 
    271     return haveGlyphs;
    272 }
    273 
    274 bool SVGFontData::fillNonBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
    275 {
    276     bool haveGlyphs = false;
    277     Vector<SVGGlyph> glyphs;
    278     for (unsigned i = 0; i < length; ++i) {
    279         // Each character here consists of a surrogate pair
    280         String lookupString(buffer + i * 2, 2);
    281         fontElement->collectGlyphsForString(lookupString, glyphs);
    282         if (glyphs.isEmpty())
    283             continue;
    284 
    285         // Associate entry in glyph page with first valid SVGGlyph.
    286         // If there are multiple valid ones, just take the first one. WidthIterator will take
    287         // care of matching to the correct glyph, if multiple ones are available, as that's
    288         // only possible within the context of a string (eg. arabic form matching).
    289         haveGlyphs = true;
    290         pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
    291         glyphs.clear();
    292     }
    293 
    294     return haveGlyphs;
    295 }
    296 
    297 String SVGFontData::createStringWithMirroredCharacters(const String& string) const
    298 {
    299     if (string.isEmpty())
    300         return emptyString();
    301 
    302     unsigned length = string.length();
    303 
    304     StringBuilder mirroredCharacters;
    305     mirroredCharacters.reserveCapacity(length);
    306 
    307     if (string.is8Bit()) {
    308         const LChar* characters = string.characters8();
    309         for (unsigned i = 0; i < length; ++i)
    310             mirroredCharacters.append(mirroredChar(characters[i]));
    311     } else {
    312         const UChar* characters = string.characters16();
    313         unsigned i = 0;
    314         while (i < length) {
    315             UChar32 character;
    316             U16_NEXT(characters, i, length, character);
    317             mirroredCharacters.append(mirroredChar(character));
    318         }
    319     }
    320 
    321     return mirroredCharacters.toString();
    322 }
    323 
    324 SVGFontFaceElement* SVGFontData::svgFontFaceElement() const
    325 {
    326     // FIXME: SVGFontData should be only used from the document with the SVGFontFaceElement.
    327     RELEASE_ASSERT(m_svgFontFaceElement && m_svgFontFaceElement->inDocument());
    328     return m_svgFontFaceElement.get();
    329 }
    330 
    331 bool SVGFontData::shouldSkipDrawing() const
    332 {
    333     // FIXME: (http://crbug.com/359380) Glyph may be referenced after removeNode from the current editing impl.
    334     return !m_svgFontFaceElement || !m_svgFontFaceElement->inDocument();
    335 }
    336 
    337 } // namespace blink
    338 
    339 #endif
    340