File indexing completed on 2024-04-28 15:24:33
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)