• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KHTML

SVGFontFaceElement.cpp

Go to the documentation of this file.
00001 /*
00002    Copyright (C) 2007 Eric Seidel <eric@webkit.org>
00003    Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
00004     
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018    Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "config.h"
00022 
00023 #if ENABLE(SVG_FONTS)
00024 #include "SVGFontFaceElement.h"
00025 #include "CString.h"
00026 #include "CSSFontFaceRule.h"
00027 #include "CSSFontFaceSrcValue.h"
00028 #include "CSSParser.h"
00029 #include "CSSProperty.h"
00030 #include "CSSPropertyNames.h"
00031 #include "CSSStyleSelector.h"
00032 #include "CSSStyleSheet.h"
00033 #include "CSSValueKeywords.h"
00034 #include "CSSValueList.h"
00035 #include "FontCache.h"
00036 #include "SimpleFontData.h"
00037 #include "SVGDefinitionSrcElement.h"
00038 #include "SVGFontElement.h"
00039 #include "SVGFontFaceSrcElement.h"
00040 #include "SVGGlyphElement.h"
00041 #include "SVGNames.h"
00042 
00043 #include <math.h>
00044 
00045 namespace WebCore {
00046 
00047 using namespace SVGNames;
00048 
00049 SVGFontFaceElement::SVGFontFaceElement(const QualifiedName& tagName, Document* doc)
00050     : SVGElement(tagName, doc)
00051     , m_fontFaceRule(new CSSFontFaceRule(0))
00052     , m_styleDeclaration(new CSSMutableStyleDeclaration)
00053 {
00054     m_styleDeclaration->setParent(document()->mappedElementSheet());
00055     m_styleDeclaration->setStrictParsing(true);
00056     m_fontFaceRule->setDeclaration(m_styleDeclaration.get());
00057     document()->mappedElementSheet()->append(m_fontFaceRule);
00058 }
00059 
00060 SVGFontFaceElement::~SVGFontFaceElement()
00061 {
00062 }
00063 
00064 static void mapAttributeToCSSProperty(HashMap<AtomicStringImpl*, int>* propertyNameToIdMap, const QualifiedName& attrName)
00065 {
00066     int propertyId = cssPropertyID(attrName.localName());
00067     ASSERT(propertyId > 0);
00068     propertyNameToIdMap->set(attrName.localName().impl(), propertyId);
00069 }
00070 
00071 static int cssPropertyIdForSVGAttributeName(const QualifiedName& attrName)
00072 {
00073     if (!attrName.namespaceURI().isNull())
00074         return 0;
00075     
00076     static HashMap<AtomicStringImpl*, int>* propertyNameToIdMap = 0;
00077     if (!propertyNameToIdMap) {
00078         propertyNameToIdMap = new HashMap<AtomicStringImpl*, int>;
00079         // This is a list of all @font-face CSS properties which are exposed as SVG XML attributes
00080         // Those commented out are not yet supported by WebCore's style system
00081         //mapAttributeToCSSProperty(propertyNameToIdMap, accent_heightAttr);
00082         //mapAttributeToCSSProperty(propertyNameToIdMap, alphabeticAttr);
00083         //mapAttributeToCSSProperty(propertyNameToIdMap, ascentAttr);
00084         //mapAttributeToCSSProperty(propertyNameToIdMap, bboxAttr);
00085         //mapAttributeToCSSProperty(propertyNameToIdMap, cap_heightAttr);
00086         //mapAttributeToCSSProperty(propertyNameToIdMap, descentAttr);
00087         mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
00088         mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
00089         mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
00090         mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
00091         mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
00092         mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
00093         //mapAttributeToCSSProperty(propertyNameToIdMap, hangingAttr);
00094         //mapAttributeToCSSProperty(propertyNameToIdMap, ideographicAttr);
00095         //mapAttributeToCSSProperty(propertyNameToIdMap, mathematicalAttr);
00096         //mapAttributeToCSSProperty(propertyNameToIdMap, overline_positionAttr);
00097         //mapAttributeToCSSProperty(propertyNameToIdMap, overline_thicknessAttr);
00098         //mapAttributeToCSSProperty(propertyNameToIdMap, panose_1Attr);
00099         //mapAttributeToCSSProperty(propertyNameToIdMap, slopeAttr);
00100         //mapAttributeToCSSProperty(propertyNameToIdMap, stemhAttr);
00101         //mapAttributeToCSSProperty(propertyNameToIdMap, stemvAttr);
00102         //mapAttributeToCSSProperty(propertyNameToIdMap, strikethrough_positionAttr);
00103         //mapAttributeToCSSProperty(propertyNameToIdMap, strikethrough_thicknessAttr);
00104         //mapAttributeToCSSProperty(propertyNameToIdMap, underline_positionAttr);
00105         //mapAttributeToCSSProperty(propertyNameToIdMap, underline_thicknessAttr);
00106         //mapAttributeToCSSProperty(propertyNameToIdMap, unicode_rangeAttr);
00107         //mapAttributeToCSSProperty(propertyNameToIdMap, units_per_emAttr);
00108         //mapAttributeToCSSProperty(propertyNameToIdMap, v_alphabeticAttr);
00109         //mapAttributeToCSSProperty(propertyNameToIdMap, v_hangingAttr);
00110         //mapAttributeToCSSProperty(propertyNameToIdMap, v_ideographicAttr);
00111         //mapAttributeToCSSProperty(propertyNameToIdMap, v_mathematicalAttr);
00112         //mapAttributeToCSSProperty(propertyNameToIdMap, widthsAttr);
00113         //mapAttributeToCSSProperty(propertyNameToIdMap, x_heightAttr);
00114     }
00115     
00116     return propertyNameToIdMap->get(attrName.localName().impl());
00117 }
00118 
00119 void SVGFontFaceElement::parseMappedAttribute(MappedAttribute* attr)
00120 {    
00121     int propId = cssPropertyIdForSVGAttributeName(attr->name());
00122     if (propId > 0) {
00123         m_styleDeclaration->setProperty(propId, attr->value(), false);
00124         rebuildFontFace();
00125         return;
00126     }
00127     
00128     SVGElement::parseMappedAttribute(attr);
00129 }
00130 
00131 unsigned SVGFontFaceElement::unitsPerEm() const
00132 {
00133     AtomicString value(getAttribute(units_per_emAttr));
00134     if (value.isEmpty())
00135         return 1000;
00136 
00137     return static_cast<unsigned>(ceilf(value.toFloat()));
00138 }
00139 
00140 int SVGFontFaceElement::xHeight() const
00141 {
00142     AtomicString value(getAttribute(x_heightAttr));
00143     if (value.isEmpty())
00144         return 0;
00145 
00146     return static_cast<int>(ceilf(value.toFloat()));
00147 }
00148 
00149 float SVGFontFaceElement::horizontalOriginX() const
00150 {
00151     if (!m_fontElement)
00152         return 0.0f;
00153 
00154     // Spec: The X-coordinate in the font coordinate system of the origin of a glyph to be used when
00155     // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
00156     // If the attribute is not specified, the effect is as if a value of "0" were specified.
00157     AtomicString value(m_fontElement->getAttribute(horiz_origin_xAttr));
00158     if (value.isEmpty())
00159         return 0.0f;
00160 
00161     return value.toFloat();
00162 }
00163 
00164 float SVGFontFaceElement::horizontalOriginY() const
00165 {
00166     if (!m_fontElement)
00167         return 0.0f;
00168 
00169     // Spec: The Y-coordinate in the font coordinate system of the origin of a glyph to be used when
00170     // drawing horizontally oriented text. (Note that the origin applies to all glyphs in the font.)
00171     // If the attribute is not specified, the effect is as if a value of "0" were specified.
00172     AtomicString value(m_fontElement->getAttribute(horiz_origin_yAttr));
00173     if (value.isEmpty())
00174         return 0.0f;
00175 
00176     return value.toFloat();
00177 }
00178 
00179 float SVGFontFaceElement::horizontalAdvanceX() const
00180 {
00181     if (!m_fontElement)
00182         return 0.0f;
00183 
00184     // Spec: The default horizontal advance after rendering a glyph in horizontal orientation. Glyph
00185     // widths are required to be non-negative, even if the glyph is typically rendered right-to-left,
00186     // as in Hebrew and Arabic scripts.
00187     AtomicString value(m_fontElement->getAttribute(horiz_adv_xAttr));
00188     if (value.isEmpty())
00189         return 0.0f;
00190 
00191     return value.toFloat();
00192 }
00193 
00194 float SVGFontFaceElement::verticalOriginX() const
00195 {
00196     if (!m_fontElement)
00197         return 0.0f;
00198 
00199     // Spec: The default X-coordinate in the font coordinate system of the origin of a glyph to be used when
00200     // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
00201     // were set to half of the effective value of attribute horiz-adv-x.
00202     AtomicString value(m_fontElement->getAttribute(vert_origin_xAttr));
00203     if (value.isEmpty())
00204         return horizontalAdvanceX() / 2.0f;
00205 
00206     return value.toFloat();
00207 }
00208 
00209 float SVGFontFaceElement::verticalOriginY() const
00210 {
00211     if (!m_fontElement)
00212         return 0.0f;
00213 
00214     // Spec: The default Y-coordinate in the font coordinate system of the origin of a glyph to be used when
00215     // drawing vertically oriented text. If the attribute is not specified, the effect is as if the attribute
00216     // were set to the position specified by the font's ascent attribute.             
00217     AtomicString value(m_fontElement->getAttribute(vert_origin_yAttr));
00218     if (value.isEmpty())
00219         return ascent();
00220 
00221     return value.toFloat();
00222 }
00223 
00224 float SVGFontFaceElement::verticalAdvanceY() const
00225 {
00226     if (!m_fontElement)
00227         return 0.0f;
00228 
00229     // Spec: The default vertical advance after rendering a glyph in vertical orientation. If the attribute is
00230     // not specified, the effect is as if a value equivalent of one em were specified (see units-per-em).                    
00231     AtomicString value(m_fontElement->getAttribute(vert_adv_yAttr));
00232        if (value.isEmpty())
00233         return 1.0f;
00234 
00235     return value.toFloat();
00236 }
00237 
00238 int SVGFontFaceElement::ascent() const
00239 {
00240     if (!m_fontElement)
00241         return 0.0f;
00242 
00243     // Spec: Same syntax and semantics as the 'ascent' descriptor within an @font-face rule. The maximum
00244     // unaccented height of the font within the font coordinate system. If the attribute is not specified,
00245     // the effect is as if the attribute were set to the difference between the units-per-em value and the
00246     // vert-origin-y value for the corresponding font.
00247     AtomicString value(m_fontElement->getAttribute(ascentAttr));
00248     if (!value.isEmpty())
00249         return static_cast<int>(ceilf(value.toFloat()));
00250 
00251     value = m_fontElement->getAttribute(vert_origin_yAttr);
00252     if (!value.isEmpty())
00253         return static_cast<int>(unitsPerEm()) - static_cast<int>(ceilf(value.toFloat()));
00254 
00255     // Match Batiks default value
00256     return static_cast<int>(ceilf(unitsPerEm() * 0.8f));
00257 }
00258 
00259 int SVGFontFaceElement::descent() const
00260 {
00261     if (!m_fontElement)
00262         return 0.0f;
00263 
00264     // Spec: Same syntax and semantics as the 'descent' descriptor within an @font-face rule. The maximum
00265     // unaccented depth of the font within the font coordinate system. If the attribute is not specified,
00266     // the effect is as if the attribute were set to the vert-origin-y value for the corresponding font.
00267     AtomicString value(m_fontElement->getAttribute(descentAttr));
00268     if (!value.isEmpty()) {
00269         // Some testcases use a negative descent value, where a positive was meant to be used :(
00270         int descent = static_cast<int>(ceilf(value.toFloat()));
00271         return descent < 0 ? -descent : descent;
00272     }
00273 
00274     value = m_fontElement->getAttribute(vert_origin_yAttr);
00275     if (!value.isEmpty())
00276         return static_cast<int>(ceilf(value.toFloat()));
00277 
00278     // Match Batiks default value
00279     return static_cast<int>(ceilf(unitsPerEm() * 0.2f));
00280 }
00281 
00282 String SVGFontFaceElement::fontFamily() const
00283 {
00284     return m_styleDeclaration->getPropertyValue(CSSPropertyFontFamily);
00285 }
00286 
00287 SVGFontElement* SVGFontFaceElement::associatedFontElement() const
00288 {
00289     return m_fontElement.get();
00290 }
00291 
00292 void SVGFontFaceElement::rebuildFontFace()
00293 {
00294     // Ignore changes until we live in the tree
00295     if (!parentNode())
00296         return;
00297 
00298     // we currently ignore all but the first src element, alternatively we could concat them
00299     SVGFontFaceSrcElement* srcElement = 0;
00300     SVGDefinitionSrcElement* definitionSrc = 0;
00301 
00302     for (Node* child = firstChild(); child; child = child->nextSibling()) {
00303         if (child->hasTagName(font_face_srcTag) && !srcElement)
00304             srcElement = static_cast<SVGFontFaceSrcElement*>(child);
00305         else if (child->hasTagName(definition_srcTag) && !definitionSrc)
00306             definitionSrc = static_cast<SVGDefinitionSrcElement*>(child);
00307     }
00308 
00309 #if 0
00310     // @font-face (CSSFontFace) does not yet support definition-src, as soon as it does this code should do the trick!
00311     if (definitionSrc)
00312         m_styleDeclaration->setProperty(CSSPropertyDefinitionSrc, definitionSrc->getAttribute(XLinkNames::hrefAttr), false);
00313 #endif
00314 
00315     bool describesParentFont = parentNode()->hasTagName(fontTag);
00316     RefPtr<CSSValueList> list;
00317 
00318     if (describesParentFont) {
00319         m_fontElement = static_cast<SVGFontElement*>(parentNode());
00320 
00321         list = new CSSValueList;
00322         list->append(new CSSFontFaceSrcValue(fontFamily(), true));
00323     } else if (srcElement)
00324         list = srcElement->srcValue();
00325 
00326     if (!list)
00327         return;
00328 
00329     // Parse in-memory CSS rules
00330     CSSProperty srcProperty(CSSPropertySrc, list);
00331     const CSSProperty* srcPropertyRef = &srcProperty;
00332     m_styleDeclaration->addParsedProperties(&srcPropertyRef, 1);
00333 
00334     if (describesParentFont) {    
00335         // Traverse parsed CSS values and associate CSSFontFaceSrcValue elements with ourselves.
00336         RefPtr<CSSValue> src = m_styleDeclaration->getPropertyCSSValue(CSSPropertySrc);
00337         CSSValueList* srcList = static_cast<CSSValueList*>(src.get());
00338 
00339         unsigned srcLength = srcList ? srcList->length() : 0;
00340         for (unsigned i = 0; i < srcLength; i++) {
00341             if (CSSFontFaceSrcValue* item = static_cast<CSSFontFaceSrcValue*>(srcList->itemWithoutBoundsCheck(i)))
00342                 item->setSVGFontFaceElement(this);
00343         }
00344     }
00345 
00346     document()->updateStyleSelector();
00347 }
00348 
00349 void SVGFontFaceElement::insertedIntoDocument()
00350 {
00351     rebuildFontFace();
00352     SVGElement::insertedIntoDocument();
00353 }
00354 
00355 void SVGFontFaceElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
00356 {
00357     SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
00358     rebuildFontFace();
00359 }
00360 
00361 }
00362 
00363 #endif // ENABLE(SVG_FONTS)

KHTML

Skip menu "KHTML"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal