File indexing completed on 2024-04-28 11:39:14

0001 /*
0002    Copyright (C) 2007 Eric Seidel <eric@webkit.org>
0003    Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 #if ENABLE(SVG_FONTS)
0022 #include "SVGFontFaceElement.h"
0023 #include "CString.h"
0024 #include "CSSFontFaceRule.h"
0025 #include "CSSFontFaceSrcValue.h"
0026 #include "CSSParser.h"
0027 #include "CSSProperty.h"
0028 #include "CSSPropertyNames.h"
0029 #include "CSSStyleSelector.h"
0030 #include "CSSStyleSheet.h"
0031 #include "CSSValueKeywords.h"
0032 #include "CSSValueList.h"
0033 #include "FontCache.h"
0034 #include "SimpleFontData.h"
0035 #include "SVGDefinitionSrcElement.h"
0036 #include "SVGFontElement.h"
0037 #include "SVGFontFaceSrcElement.h"
0038 #include "SVGGlyphElement.h"
0039 #include "SVGNames.h"
0040 
0041 #include <math.h>
0042 
0043 namespace WebCore
0044 {
0045 
0046 using namespace SVGNames;
0047 
0048 SVGFontFaceElement::SVGFontFaceElement(const QualifiedName &tagName, Document *doc)
0049     : SVGElement(tagName, doc)
0050     , m_fontFaceRule(new CSSFontFaceRule(0))
0051     , m_styleDeclaration(new CSSMutableStyleDeclaration)
0052 {
0053     m_styleDeclaration->setParent(document()->mappedElementSheet());
0054     m_styleDeclaration->setStrictParsing(true);
0055     m_fontFaceRule->setDeclaration(m_styleDeclaration.get());
0056     document()->mappedElementSheet()->append(m_fontFaceRule);
0057 }
0058 
0059 SVGFontFaceElement::~SVGFontFaceElement()
0060 {
0061 }
0062 
0063 static void mapAttributeToCSSProperty(HashMap<AtomicStringImpl *, int> *propertyNameToIdMap, const QualifiedName &attrName)
0064 {
0065     int propertyId = cssPropertyID(attrName.localName());
0066     ASSERT(propertyId > 0);
0067     propertyNameToIdMap->set(attrName.localName().impl(), propertyId);
0068 }
0069 
0070 static int cssPropertyIdForSVGAttributeName(const QualifiedName &attrName)
0071 {
0072     if (!attrName.namespaceURI().isNull()) {
0073         return 0;
0074     }
0075 
0076     static HashMap<AtomicStringImpl *, int> *propertyNameToIdMap = 0;
0077     if (!propertyNameToIdMap) {
0078         propertyNameToIdMap = new HashMap<AtomicStringImpl *, int>;
0079         // This is a list of all @font-face CSS properties which are exposed as SVG XML attributes
0080         // Those commented out are not yet supported by WebCore's style system
0081         //mapAttributeToCSSProperty(propertyNameToIdMap, accent_heightAttr);
0082         //mapAttributeToCSSProperty(propertyNameToIdMap, alphabeticAttr);
0083         //mapAttributeToCSSProperty(propertyNameToIdMap, ascentAttr);
0084         //mapAttributeToCSSProperty(propertyNameToIdMap, bboxAttr);
0085         //mapAttributeToCSSProperty(propertyNameToIdMap, cap_heightAttr);
0086         //mapAttributeToCSSProperty(propertyNameToIdMap, descentAttr);
0087         mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
0088         mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
0089         mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
0090         mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
0091         mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
0092         mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
0093         //mapAttributeToCSSProperty(propertyNameToIdMap, hangingAttr);
0094         //mapAttributeToCSSProperty(propertyNameToIdMap, ideographicAttr);
0095         //mapAttributeToCSSProperty(propertyNameToIdMap, mathematicalAttr);
0096         //mapAttributeToCSSProperty(propertyNameToIdMap, overline_positionAttr);
0097         //mapAttributeToCSSProperty(propertyNameToIdMap, overline_thicknessAttr);
0098         //mapAttributeToCSSProperty(propertyNameToIdMap, panose_1Attr);
0099         //mapAttributeToCSSProperty(propertyNameToIdMap, slopeAttr);
0100         //mapAttributeToCSSProperty(propertyNameToIdMap, stemhAttr);
0101         //mapAttributeToCSSProperty(propertyNameToIdMap, stemvAttr);
0102         //mapAttributeToCSSProperty(propertyNameToIdMap, strikethrough_positionAttr);
0103         //mapAttributeToCSSProperty(propertyNameToIdMap, strikethrough_thicknessAttr);
0104         //mapAttributeToCSSProperty(propertyNameToIdMap, underline_positionAttr);
0105         //mapAttributeToCSSProperty(propertyNameToIdMap, underline_thicknessAttr);
0106         //mapAttributeToCSSProperty(propertyNameToIdMap, unicode_rangeAttr);
0107         //mapAttributeToCSSProperty(propertyNameToIdMap, units_per_emAttr);
0108         //mapAttributeToCSSProperty(propertyNameToIdMap, v_alphabeticAttr);
0109         //mapAttributeToCSSProperty(propertyNameToIdMap, v_hangingAttr);
0110         //mapAttributeToCSSProperty(propertyNameToIdMap, v_ideographicAttr);
0111         //mapAttributeToCSSProperty(propertyNameToIdMap, v_mathematicalAttr);
0112         //mapAttributeToCSSProperty(propertyNameToIdMap, widthsAttr);
0113         //mapAttributeToCSSProperty(propertyNameToIdMap, x_heightAttr);
0114     }
0115 
0116     return propertyNameToIdMap->get(attrName.localName().impl());
0117 }
0118 
0119 void SVGFontFaceElement::parseMappedAttribute(MappedAttribute *attr)
0120 {
0121     int propId = cssPropertyIdForSVGAttributeName(attr->name());
0122     if (propId > 0) {
0123         m_styleDeclaration->setProperty(propId, attr->value(), false);
0124         rebuildFontFace();
0125         return;
0126     }
0127 
0128     SVGElement::parseMappedAttribute(attr);
0129 }
0130 
0131 unsigned SVGFontFaceElement::unitsPerEm() const
0132 {
0133     AtomicString value(getAttribute(units_per_emAttr));
0134     if (value.isEmpty()) {
0135         return 1000;
0136     }
0137 
0138     return static_cast<unsigned>(ceilf(value.toFloat()));
0139 }
0140 
0141 int SVGFontFaceElement::xHeight() const
0142 {
0143     AtomicString value(getAttribute(x_heightAttr));
0144     if (value.isEmpty()) {
0145         return 0;
0146     }
0147 
0148     return static_cast<int>(ceilf(value.toFloat()));
0149 }
0150 
0151 float SVGFontFaceElement::horizontalOriginX() const
0152 {
0153     if (!m_fontElement) {
0154         return 0.0f;
0155     }
0156 
0157     // Spec: The X-coordinate in the font coordinate system of the origin of a glyph to be used when
0158     // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
0159     // If the attribute is not specified, the effect is as if a value of "0" were specified.
0160     AtomicString value(m_fontElement->getAttribute(horiz_origin_xAttr));
0161     if (value.isEmpty()) {
0162         return 0.0f;
0163     }
0164 
0165     return value.toFloat();
0166 }
0167 
0168 float SVGFontFaceElement::horizontalOriginY() const
0169 {
0170     if (!m_fontElement) {
0171         return 0.0f;
0172     }
0173 
0174     // Spec: The Y-coordinate in the font coordinate system of the origin of a glyph to be used when
0175     // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
0176     // If the attribute is not specified, the effect is as if a value of "0" were specified.
0177     AtomicString value(m_fontElement->getAttribute(horiz_origin_yAttr));
0178     if (value.isEmpty()) {
0179         return 0.0f;
0180     }
0181 
0182     return value.toFloat();
0183 }
0184 
0185 float SVGFontFaceElement::horizontalAdvanceX() const
0186 {
0187     if (!m_fontElement) {
0188         return 0.0f;
0189     }
0190 
0191     // Spec: The default horizontal advance after rendering a glyph in horizontal orientation. Glyph
0192     // widths are required to be non-negative, even if the glyph is typically rendered right-to-left,
0193     // as in Hebrew and Arabic scripts.
0194     AtomicString value(m_fontElement->getAttribute(horiz_adv_xAttr));
0195     if (value.isEmpty()) {
0196         return 0.0f;
0197     }
0198 
0199     return value.toFloat();
0200 }
0201 
0202 float SVGFontFaceElement::verticalOriginX() const
0203 {
0204     if (!m_fontElement) {
0205         return 0.0f;
0206     }
0207 
0208     // Spec: The default X-coordinate in the font coordinate system of the origin of a glyph to be used when
0209     // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
0210     // were set to half of the effective value of attribute horiz-adv-x.
0211     AtomicString value(m_fontElement->getAttribute(vert_origin_xAttr));
0212     if (value.isEmpty()) {
0213         return horizontalAdvanceX() / 2.0f;
0214     }
0215 
0216     return value.toFloat();
0217 }
0218 
0219 float SVGFontFaceElement::verticalOriginY() const
0220 {
0221     if (!m_fontElement) {
0222         return 0.0f;
0223     }
0224 
0225     // Spec: The default Y-coordinate in the font coordinate system of the origin of a glyph to be used when
0226     // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
0227     // were set to the position specified by the font's ascent attribute.
0228     AtomicString value(m_fontElement->getAttribute(vert_origin_yAttr));
0229     if (value.isEmpty()) {
0230         return ascent();
0231     }
0232 
0233     return value.toFloat();
0234 }
0235 
0236 float SVGFontFaceElement::verticalAdvanceY() const
0237 {
0238     if (!m_fontElement) {
0239         return 0.0f;
0240     }
0241 
0242     // Spec: The default vertical advance after rendering a glyph in vertical orientation. If the attribute is
0243     // not specified, the effect is as if a value equivalent of one em were specified (see units-per-em).
0244     AtomicString value(m_fontElement->getAttribute(vert_adv_yAttr));
0245     if (value.isEmpty()) {
0246         return 1.0f;
0247     }
0248 
0249     return value.toFloat();
0250 }
0251 
0252 int SVGFontFaceElement::ascent() const
0253 {
0254     if (!m_fontElement) {
0255         return 0.0f;
0256     }
0257 
0258     // Spec: Same syntax and semantics as the 'ascent' descriptor within an @font-face rule. The maximum
0259     // unaccented height of the font within the font coordinate system. If the attribute is not specified,
0260     // the effect is as if the attribute were set to the difference between the units-per-em value and the
0261     // vert-origin-y value for the corresponding font.
0262     AtomicString value(m_fontElement->getAttribute(ascentAttr));
0263     if (!value.isEmpty()) {
0264         return static_cast<int>(ceilf(value.toFloat()));
0265     }
0266 
0267     value = m_fontElement->getAttribute(vert_origin_yAttr);
0268     if (!value.isEmpty()) {
0269         return static_cast<int>(unitsPerEm()) - static_cast<int>(ceilf(value.toFloat()));
0270     }
0271 
0272     // Match Batiks default value
0273     return static_cast<int>(ceilf(unitsPerEm() * 0.8f));
0274 }
0275 
0276 int SVGFontFaceElement::descent() const
0277 {
0278     if (!m_fontElement) {
0279         return 0.0f;
0280     }
0281 
0282     // Spec: Same syntax and semantics as the 'descent' descriptor within an @font-face rule. The maximum
0283     // unaccented depth of the font within the font coordinate system. If the attribute is not specified,
0284     // the effect is as if the attribute were set to the vert-origin-y value for the corresponding font.
0285     AtomicString value(m_fontElement->getAttribute(descentAttr));
0286     if (!value.isEmpty()) {
0287         // Some testcases use a negative descent value, where a positive was meant to be used :(
0288         int descent = static_cast<int>(ceilf(value.toFloat()));
0289         return descent < 0 ? -descent : descent;
0290     }
0291 
0292     value = m_fontElement->getAttribute(vert_origin_yAttr);
0293     if (!value.isEmpty()) {
0294         return static_cast<int>(ceilf(value.toFloat()));
0295     }
0296 
0297     // Match Batiks default value
0298     return static_cast<int>(ceilf(unitsPerEm() * 0.2f));
0299 }
0300 
0301 String SVGFontFaceElement::fontFamily() const
0302 {
0303     return m_styleDeclaration->getPropertyValue(CSSPropertyFontFamily);
0304 }
0305 
0306 SVGFontElement *SVGFontFaceElement::associatedFontElement() const
0307 {
0308     return m_fontElement.get();
0309 }
0310 
0311 void SVGFontFaceElement::rebuildFontFace()
0312 {
0313     // Ignore changes until we live in the tree
0314     if (!parentNode()) {
0315         return;
0316     }
0317 
0318     // we currently ignore all but the first src element, alternatively we could concat them
0319     SVGFontFaceSrcElement *srcElement = 0;
0320     SVGDefinitionSrcElement *definitionSrc = 0;
0321 
0322     for (Node *child = firstChild(); child; child = child->nextSibling()) {
0323         if (child->hasTagName(font_face_srcTag) && !srcElement) {
0324             srcElement = static_cast<SVGFontFaceSrcElement *>(child);
0325         } else if (child->hasTagName(definition_srcTag) && !definitionSrc) {
0326             definitionSrc = static_cast<SVGDefinitionSrcElement *>(child);
0327         }
0328     }
0329 
0330 #if 0
0331     // @font-face (CSSFontFace) does not yet support definition-src, as soon as it does this code should do the trick!
0332     if (definitionSrc) {
0333         m_styleDeclaration->setProperty(CSSPropertyDefinitionSrc, definitionSrc->getAttribute(XLinkNames::hrefAttr), false);
0334     }
0335 #endif
0336 
0337     bool describesParentFont = parentNode()->hasTagName(fontTag);
0338     RefPtr<CSSValueList> list;
0339 
0340     if (describesParentFont) {
0341         m_fontElement = static_cast<SVGFontElement *>(parentNode());
0342 
0343         list = new CSSValueList; // ### CSSValueListImpl(CSSValueListImpl::Comma);
0344         list->append(new CSSFontFaceSrcValue(fontFamily(), true));
0345     } else if (srcElement) {
0346         list = srcElement->srcValue();
0347     }
0348 
0349     if (!list) {
0350         return;
0351     }
0352 
0353     // Parse in-memory CSS rules
0354     CSSProperty srcProperty(CSSPropertySrc, list);
0355     const CSSProperty *srcPropertyRef = &srcProperty;
0356     m_styleDeclaration->addParsedProperties(&srcPropertyRef, 1);
0357 
0358     if (describesParentFont) {
0359         // Traverse parsed CSS values and associate CSSFontFaceSrcValue elements with ourselves.
0360         RefPtr<CSSValue> src = m_styleDeclaration->getPropertyCSSValue(CSSPropertySrc);
0361         CSSValueList *srcList = static_cast<CSSValueList *>(src.get());
0362 
0363         unsigned srcLength = srcList ? srcList->length() : 0;
0364         for (unsigned i = 0; i < srcLength; i++) {
0365             if (CSSFontFaceSrcValue *item = static_cast<CSSFontFaceSrcValue *>(srcList->itemWithoutBoundsCheck(i))) {
0366                 item->setSVGFontFaceElement(this);
0367             }
0368         }
0369     }
0370 
0371     document()->updateStyleSelector();
0372 }
0373 
0374 void SVGFontFaceElement::insertedIntoDocument()
0375 {
0376     rebuildFontFace();
0377     SVGElement::insertedIntoDocument();
0378 }
0379 
0380 void SVGFontFaceElement::childrenChanged(bool changedByParser, Node *beforeChange, Node *afterChange, int childCountDelta)
0381 {
0382     SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
0383     rebuildFontFace();
0384 }
0385 
0386 }
0387 
0388 #endif // ENABLE(SVG_FONTS)