WebCore/svg/SVGFontFaceElement.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     1 /*
       
     2    Copyright (C) 2007 Eric Seidel <eric@webkit.org>
       
     3    Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
       
     4    Copyright (C) 2008 Apple Inc. All rights reserved.
       
     5     
       
     6    This library is free software; you can redistribute it and/or
       
     7    modify it under the terms of the GNU Library General Public
       
     8    License as published by the Free Software Foundation; either
       
     9    version 2 of the License, or (at your option) any later version.
       
    10 
       
    11    This library is distributed in the hope that it will be useful,
       
    12    but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    14    Library General Public License for more details.
       
    15 
       
    16    You should have received a copy of the GNU Library General Public License
       
    17    along with this library; see the file COPYING.LIB.  If not, write to
       
    18    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
       
    19    Boston, MA 02110-1301, USA.
       
    20 */
       
    21 
       
    22 #include "config.h"
       
    23 
       
    24 #if ENABLE(SVG_FONTS)
       
    25 #include "SVGFontFaceElement.h"
       
    26 
       
    27 #include "Attribute.h"
       
    28 #include "CSSFontFaceRule.h"
       
    29 #include "CSSFontFaceSrcValue.h"
       
    30 #include "CSSParser.h"
       
    31 #include "CSSProperty.h"
       
    32 #include "CSSPropertyNames.h"
       
    33 #include "CSSStyleSelector.h"
       
    34 #include "CSSStyleSheet.h"
       
    35 #include "CSSValueKeywords.h"
       
    36 #include "CSSValueList.h"
       
    37 #include "Document.h"
       
    38 #include "Font.h"
       
    39 #include "SVGFontElement.h"
       
    40 #include "SVGFontFaceSrcElement.h"
       
    41 #include "SVGGlyphElement.h"
       
    42 #include "SVGNames.h"
       
    43 #include <math.h>
       
    44 
       
    45 namespace WebCore {
       
    46 
       
    47 using namespace SVGNames;
       
    48 
       
    49 SVGFontFaceElement::SVGFontFaceElement(const QualifiedName& tagName, Document* doc)
       
    50     : SVGElement(tagName, doc)
       
    51     , m_fontFaceRule(CSSFontFaceRule::create())
       
    52     , m_styleDeclaration(CSSMutableStyleDeclaration::create())
       
    53 {
       
    54     m_styleDeclaration->setParent(document()->mappedElementSheet());
       
    55     m_styleDeclaration->setStrictParsing(true);
       
    56     m_fontFaceRule->setDeclaration(m_styleDeclaration.get());
       
    57 }
       
    58 
       
    59 SVGFontFaceElement::~SVGFontFaceElement()
       
    60 {
       
    61 }
       
    62 
       
    63 static int cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
       
    64 {
       
    65     if (!attrName.namespaceURI().isNull())
       
    66         return 0;
       
    67     
       
    68     static HashMap<AtomicStringImpl*, int>* propertyNameToIdMap = 0;
       
    69     if (!propertyNameToIdMap) {
       
    70         propertyNameToIdMap = new HashMap<AtomicStringImpl*, int>;
       
    71         // This is a list of all @font-face CSS properties which are exposed as SVG XML attributes
       
    72         // Those commented out are not yet supported by WebCore's style system
       
    73         //mapAttributeToCSSProperty(propertyNameToIdMap, accent_heightAttr);
       
    74         //mapAttributeToCSSProperty(propertyNameToIdMap, alphabeticAttr);
       
    75         //mapAttributeToCSSProperty(propertyNameToIdMap, ascentAttr);
       
    76         //mapAttributeToCSSProperty(propertyNameToIdMap, bboxAttr);
       
    77         //mapAttributeToCSSProperty(propertyNameToIdMap, cap_heightAttr);
       
    78         //mapAttributeToCSSProperty(propertyNameToIdMap, descentAttr);
       
    79         mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
       
    80         mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
       
    81         mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
       
    82         mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
       
    83         mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
       
    84         mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
       
    85         //mapAttributeToCSSProperty(propertyNameToIdMap, hangingAttr);
       
    86         //mapAttributeToCSSProperty(propertyNameToIdMap, ideographicAttr);
       
    87         //mapAttributeToCSSProperty(propertyNameToIdMap, mathematicalAttr);
       
    88         //mapAttributeToCSSProperty(propertyNameToIdMap, overline_positionAttr);
       
    89         //mapAttributeToCSSProperty(propertyNameToIdMap, overline_thicknessAttr);
       
    90         //mapAttributeToCSSProperty(propertyNameToIdMap, panose_1Attr);
       
    91         //mapAttributeToCSSProperty(propertyNameToIdMap, slopeAttr);
       
    92         //mapAttributeToCSSProperty(propertyNameToIdMap, stemhAttr);
       
    93         //mapAttributeToCSSProperty(propertyNameToIdMap, stemvAttr);
       
    94         //mapAttributeToCSSProperty(propertyNameToIdMap, strikethrough_positionAttr);
       
    95         //mapAttributeToCSSProperty(propertyNameToIdMap, strikethrough_thicknessAttr);
       
    96         //mapAttributeToCSSProperty(propertyNameToIdMap, underline_positionAttr);
       
    97         //mapAttributeToCSSProperty(propertyNameToIdMap, underline_thicknessAttr);
       
    98         //mapAttributeToCSSProperty(propertyNameToIdMap, unicode_rangeAttr);
       
    99         //mapAttributeToCSSProperty(propertyNameToIdMap, units_per_emAttr);
       
   100         //mapAttributeToCSSProperty(propertyNameToIdMap, v_alphabeticAttr);
       
   101         //mapAttributeToCSSProperty(propertyNameToIdMap, v_hangingAttr);
       
   102         //mapAttributeToCSSProperty(propertyNameToIdMap, v_ideographicAttr);
       
   103         //mapAttributeToCSSProperty(propertyNameToIdMap, v_mathematicalAttr);
       
   104         //mapAttributeToCSSProperty(propertyNameToIdMap, widthsAttr);
       
   105         //mapAttributeToCSSProperty(propertyNameToIdMap, x_heightAttr);
       
   106     }
       
   107     
       
   108     return propertyNameToIdMap->get(attrName.localName().impl());
       
   109 }
       
   110 
       
   111 void SVGFontFaceElement::parseMappedAttribute(Attribute* attr)
       
   112 {    
       
   113     int propId = cssPropertyIdForSVGAttributeName(attr->name());
       
   114     if (propId > 0) {
       
   115         m_styleDeclaration->setProperty(propId, attr->value(), false);
       
   116         if (inDocument())
       
   117             rebuildFontFace();
       
   118         return;
       
   119     }
       
   120     
       
   121     SVGElement::parseMappedAttribute(attr);
       
   122 }
       
   123 
       
   124 unsigned SVGFontFaceElement::unitsPerEm() const
       
   125 {
       
   126     const AtomicString& value = getAttribute(units_per_emAttr);
       
   127     if (value.isEmpty())
       
   128         return defaultUnitsPerEm;
       
   129 
       
   130     return static_cast<unsigned>(ceilf(value.toFloat()));
       
   131 }
       
   132 
       
   133 int SVGFontFaceElement::xHeight() const
       
   134 {
       
   135     return static_cast<int>(ceilf(getAttribute(x_heightAttr).toFloat()));
       
   136 }
       
   137 
       
   138 float SVGFontFaceElement::horizontalOriginX() const
       
   139 {
       
   140     if (!m_fontElement)
       
   141         return 0.0f;
       
   142 
       
   143     // Spec: The X-coordinate in the font coordinate system of the origin of a glyph to be used when
       
   144     // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
       
   145     // If the attribute is not specified, the effect is as if a value of "0" were specified.
       
   146     return m_fontElement->getAttribute(horiz_origin_xAttr).toFloat();
       
   147 }
       
   148 
       
   149 float SVGFontFaceElement::horizontalOriginY() const
       
   150 {
       
   151     if (!m_fontElement)
       
   152         return 0.0f;
       
   153 
       
   154     // Spec: The Y-coordinate in the font coordinate system of the origin of a glyph to be used when
       
   155     // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
       
   156     // If the attribute is not specified, the effect is as if a value of "0" were specified.
       
   157     return m_fontElement->getAttribute(horiz_origin_yAttr).toFloat();
       
   158 }
       
   159 
       
   160 float SVGFontFaceElement::horizontalAdvanceX() const
       
   161 {
       
   162     if (!m_fontElement)
       
   163         return 0.0f;
       
   164 
       
   165     // Spec: The default horizontal advance after rendering a glyph in horizontal orientation. Glyph
       
   166     // widths are required to be non-negative, even if the glyph is typically rendered right-to-left,
       
   167     // as in Hebrew and Arabic scripts.
       
   168     return m_fontElement->getAttribute(horiz_adv_xAttr).toFloat();
       
   169 }
       
   170 
       
   171 float SVGFontFaceElement::verticalOriginX() const
       
   172 {
       
   173     if (!m_fontElement)
       
   174         return 0.0f;
       
   175 
       
   176     // Spec: The default X-coordinate in the font coordinate system of the origin of a glyph to be used when
       
   177     // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
       
   178     // were set to half of the effective value of attribute horiz-adv-x.
       
   179     const AtomicString& value = m_fontElement->getAttribute(vert_origin_xAttr);
       
   180     if (value.isEmpty())
       
   181         return horizontalAdvanceX() / 2.0f;
       
   182 
       
   183     return value.toFloat();
       
   184 }
       
   185 
       
   186 float SVGFontFaceElement::verticalOriginY() const
       
   187 {
       
   188     if (!m_fontElement)
       
   189         return 0.0f;
       
   190 
       
   191     // Spec: The default Y-coordinate in the font coordinate system of the origin of a glyph to be used when
       
   192     // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
       
   193     // were set to the position specified by the font's ascent attribute.             
       
   194     const AtomicString& value = m_fontElement->getAttribute(vert_origin_yAttr);
       
   195     if (value.isEmpty())
       
   196         return ascent();
       
   197 
       
   198     return value.toFloat();
       
   199 }
       
   200 
       
   201 float SVGFontFaceElement::verticalAdvanceY() const
       
   202 {
       
   203     if (!m_fontElement)
       
   204         return 0.0f;
       
   205 
       
   206     // Spec: The default vertical advance after rendering a glyph in vertical orientation. If the attribute is
       
   207     // not specified, the effect is as if a value equivalent of one em were specified (see units-per-em).                    
       
   208     const AtomicString& value = m_fontElement->getAttribute(vert_adv_yAttr);
       
   209        if (value.isEmpty())
       
   210         return 1.0f;
       
   211 
       
   212     return value.toFloat();
       
   213 }
       
   214 
       
   215 int SVGFontFaceElement::ascent() const
       
   216 {
       
   217     // Spec: Same syntax and semantics as the 'ascent' descriptor within an @font-face rule. The maximum
       
   218     // unaccented height of the font within the font coordinate system. If the attribute is not specified,
       
   219     // the effect is as if the attribute were set to the difference between the units-per-em value and the
       
   220     // vert-origin-y value for the corresponding font.
       
   221     const AtomicString& ascentValue = getAttribute(ascentAttr);
       
   222     if (!ascentValue.isEmpty())
       
   223         return static_cast<int>(ceilf(ascentValue.toFloat()));
       
   224 
       
   225     if (m_fontElement) {
       
   226         const AtomicString& vertOriginY = m_fontElement->getAttribute(vert_origin_yAttr);
       
   227         if (!vertOriginY.isEmpty())
       
   228             return static_cast<int>(unitsPerEm()) - static_cast<int>(ceilf(vertOriginY.toFloat()));
       
   229     }
       
   230 
       
   231     // Match Batiks default value
       
   232     return static_cast<int>(ceilf(unitsPerEm() * 0.8f));
       
   233 }
       
   234 
       
   235 int SVGFontFaceElement::descent() const
       
   236 {
       
   237     // Spec: Same syntax and semantics as the 'descent' descriptor within an @font-face rule. The maximum
       
   238     // unaccented depth of the font within the font coordinate system. If the attribute is not specified,
       
   239     // the effect is as if the attribute were set to the vert-origin-y value for the corresponding font.
       
   240     const AtomicString& descentValue = getAttribute(descentAttr);
       
   241     if (!descentValue.isEmpty()) {
       
   242         // 14 different W3C SVG 1.1 testcases use a negative descent value,
       
   243         // where a positive was meant to be used  Including:
       
   244         // animate-elem-24-t.svg, fonts-elem-01-t.svg, fonts-elem-02-t.svg (and 11 others)
       
   245         int descent = static_cast<int>(ceilf(descentValue.toFloat()));
       
   246         return descent < 0 ? -descent : descent;
       
   247     }
       
   248 
       
   249     if (m_fontElement) {
       
   250         const AtomicString& vertOriginY = m_fontElement->getAttribute(vert_origin_yAttr);
       
   251         if (!vertOriginY.isEmpty())
       
   252             return static_cast<int>(ceilf(vertOriginY.toFloat()));
       
   253     }
       
   254 
       
   255     // Match Batiks default value
       
   256     return static_cast<int>(ceilf(unitsPerEm() * 0.2f));
       
   257 }
       
   258 
       
   259 String SVGFontFaceElement::fontFamily() const
       
   260 {
       
   261     return m_styleDeclaration->getPropertyValue(CSSPropertyFontFamily);
       
   262 }
       
   263 
       
   264 void SVGFontFaceElement::rebuildFontFace()
       
   265 {
       
   266     ASSERT(inDocument());
       
   267 
       
   268     // we currently ignore all but the first src element, alternatively we could concat them
       
   269     SVGFontFaceSrcElement* srcElement = 0;
       
   270 
       
   271     for (Node* child = firstChild(); child && !srcElement; child = child->nextSibling()) {
       
   272         if (child->hasTagName(font_face_srcTag))
       
   273             srcElement = static_cast<SVGFontFaceSrcElement*>(child);
       
   274     }
       
   275 
       
   276     bool describesParentFont = parentNode()->hasTagName(SVGNames::fontTag);
       
   277     RefPtr<CSSValueList> list;
       
   278 
       
   279     if (describesParentFont) {
       
   280         m_fontElement = static_cast<SVGFontElement*>(parentNode());
       
   281 
       
   282         list = CSSValueList::createCommaSeparated();
       
   283         list->append(CSSFontFaceSrcValue::createLocal(fontFamily()));
       
   284     } else {
       
   285         m_fontElement = 0;
       
   286         if (srcElement)
       
   287             list = srcElement->srcValue();
       
   288     }
       
   289 
       
   290     if (!list)
       
   291         return;
       
   292 
       
   293     // Parse in-memory CSS rules
       
   294     CSSProperty srcProperty(CSSPropertySrc, list);
       
   295     const CSSProperty* srcPropertyRef = &srcProperty;
       
   296     m_styleDeclaration->addParsedProperties(&srcPropertyRef, 1);
       
   297 
       
   298     if (describesParentFont) {    
       
   299         // Traverse parsed CSS values and associate CSSFontFaceSrcValue elements with ourselves.
       
   300         RefPtr<CSSValue> src = m_styleDeclaration->getPropertyCSSValue(CSSPropertySrc);
       
   301         CSSValueList* srcList = static_cast<CSSValueList*>(src.get());
       
   302 
       
   303         unsigned srcLength = srcList ? srcList->length() : 0;
       
   304         for (unsigned i = 0; i < srcLength; i++) {
       
   305             if (CSSFontFaceSrcValue* item = static_cast<CSSFontFaceSrcValue*>(srcList->itemWithoutBoundsCheck(i)))
       
   306                 item->setSVGFontFaceElement(this);
       
   307         }
       
   308     }
       
   309 
       
   310     document()->updateStyleSelector();
       
   311 }
       
   312 
       
   313 void SVGFontFaceElement::insertedIntoDocument()
       
   314 {
       
   315     SVGElement::insertedIntoDocument();
       
   316     document()->mappedElementSheet()->append(m_fontFaceRule);
       
   317     rebuildFontFace();
       
   318 }
       
   319 
       
   320 void SVGFontFaceElement::removedFromDocument()
       
   321 {
       
   322     removeFromMappedElementSheet();
       
   323     SVGElement::removedFromDocument();
       
   324 }
       
   325 
       
   326 void SVGFontFaceElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
       
   327 {
       
   328     SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
       
   329     if (inDocument())
       
   330         rebuildFontFace();
       
   331 }
       
   332 
       
   333 void SVGFontFaceElement::removeFromMappedElementSheet()
       
   334 {
       
   335     CSSStyleSheet* mappedElementSheet = document()->mappedElementSheet();
       
   336     if (!mappedElementSheet)
       
   337         return;
       
   338 
       
   339     for (unsigned i = 0; i < mappedElementSheet->length(); ++i) {
       
   340         if (mappedElementSheet->item(i) == m_fontFaceRule) {
       
   341             mappedElementSheet->remove(i);
       
   342             break;
       
   343         }
       
   344     }
       
   345     document()->updateStyleSelector();
       
   346 }
       
   347 
       
   348 } // namespace WebCore
       
   349 
       
   350 #endif // ENABLE(SVG_FONTS)