| OLD | NEW |
| (Empty) |
| 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 "core/svg/SVGFontFaceElement.h" | |
| 26 | |
| 27 #include "core/CSSPropertyNames.h" | |
| 28 #include "core/CSSValueKeywords.h" | |
| 29 #include "core/css/CSSFontFaceSrcValue.h" | |
| 30 #include "core/css/CSSFontSelector.h" | |
| 31 #include "core/css/CSSStyleSheet.h" | |
| 32 #include "core/css/CSSValueList.h" | |
| 33 #include "core/css/StylePropertySet.h" | |
| 34 #include "core/css/StyleRule.h" | |
| 35 #include "core/css/parser/CSSParser.h" | |
| 36 #include "core/dom/Attribute.h" | |
| 37 #include "core/dom/Document.h" | |
| 38 #include "core/dom/StyleEngine.h" | |
| 39 #include "core/svg/SVGDocumentExtensions.h" | |
| 40 #include "core/svg/SVGFontElement.h" | |
| 41 #include "core/svg/SVGFontFaceSrcElement.h" | |
| 42 #include "core/svg/SVGGlyphElement.h" | |
| 43 #include "platform/fonts/Font.h" | |
| 44 #include <math.h> | |
| 45 | |
| 46 namespace blink { | |
| 47 | |
| 48 using namespace SVGNames; | |
| 49 | |
| 50 inline SVGFontFaceElement::SVGFontFaceElement(Document& document) | |
| 51 : SVGElement(font_faceTag, document) | |
| 52 , m_fontFaceRule(StyleRuleFontFace::create()) | |
| 53 , m_fontElement(nullptr) | |
| 54 , m_weakFactory(this) | |
| 55 { | |
| 56 RefPtrWillBeRawPtr<MutableStylePropertySet> styleDeclaration = MutableStyleP
ropertySet::create(HTMLStandardMode); | |
| 57 m_fontFaceRule->setProperties(styleDeclaration.release()); | |
| 58 } | |
| 59 | |
| 60 DEFINE_NODE_FACTORY(SVGFontFaceElement) | |
| 61 | |
| 62 static CSSPropertyID cssPropertyIdForFontFaceAttributeName(const QualifiedName&
attrName) | |
| 63 { | |
| 64 if (!attrName.namespaceURI().isNull()) | |
| 65 return CSSPropertyInvalid; | |
| 66 | |
| 67 static HashMap<StringImpl*, CSSPropertyID>* propertyNameToIdMap = 0; | |
| 68 if (!propertyNameToIdMap) { | |
| 69 propertyNameToIdMap = new HashMap<StringImpl*, CSSPropertyID>; | |
| 70 // This is a list of all @font-face CSS properties which are exposed as
SVG XML attributes | |
| 71 // Those commented out are not yet supported by WebCore's style system | |
| 72 const QualifiedName* const attrNames[] = { | |
| 73 // &accent_heightAttr, | |
| 74 // &alphabeticAttr, | |
| 75 // &ascentAttr, | |
| 76 // &bboxAttr, | |
| 77 // &cap_heightAttr, | |
| 78 // &descentAttr, | |
| 79 &font_familyAttr, | |
| 80 &font_sizeAttr, | |
| 81 &font_stretchAttr, | |
| 82 &font_styleAttr, | |
| 83 &font_variantAttr, | |
| 84 &font_weightAttr, | |
| 85 // &hangingAttr, | |
| 86 // &ideographicAttr, | |
| 87 // &mathematicalAttr, | |
| 88 // &overline_positionAttr, | |
| 89 // &overline_thicknessAttr, | |
| 90 // &panose_1Attr, | |
| 91 // &slopeAttr, | |
| 92 // &stemhAttr, | |
| 93 // &stemvAttr, | |
| 94 // &strikethrough_positionAttr, | |
| 95 // &strikethrough_thicknessAttr, | |
| 96 // &underline_positionAttr, | |
| 97 // &underline_thicknessAttr, | |
| 98 // &unicode_rangeAttr, | |
| 99 // &units_per_emAttr, | |
| 100 // &v_alphabeticAttr, | |
| 101 // &v_hangingAttr, | |
| 102 // &v_ideographicAttr, | |
| 103 // &v_mathematicalAttr, | |
| 104 // &widthsAttr, | |
| 105 // &x_heightAttr, | |
| 106 }; | |
| 107 for (size_t i = 0; i < WTF_ARRAY_LENGTH(attrNames); i++) { | |
| 108 CSSPropertyID propertyId = cssPropertyID(attrNames[i]->localName()); | |
| 109 ASSERT(propertyId > 0); | |
| 110 propertyNameToIdMap->set(attrNames[i]->localName().impl(), propertyI
d); | |
| 111 } | |
| 112 } | |
| 113 | |
| 114 return propertyNameToIdMap->get(attrName.localName().impl()); | |
| 115 } | |
| 116 | |
| 117 void SVGFontFaceElement::parseAttribute(const QualifiedName& name, const AtomicS
tring& value) | |
| 118 { | |
| 119 CSSPropertyID propId = cssPropertyIdForFontFaceAttributeName(name); | |
| 120 if (propId > 0) { | |
| 121 m_fontFaceRule->mutableProperties().setProperty(propId, value, false); | |
| 122 rebuildFontFace(); | |
| 123 return; | |
| 124 } | |
| 125 | |
| 126 SVGElement::parseAttribute(name, value); | |
| 127 } | |
| 128 | |
| 129 unsigned SVGFontFaceElement::unitsPerEm() const | |
| 130 { | |
| 131 const AtomicString& value = fastGetAttribute(units_per_emAttr); | |
| 132 if (value.isEmpty()) | |
| 133 return gDefaultUnitsPerEm; | |
| 134 | |
| 135 return static_cast<unsigned>(ceilf(value.toFloat())); | |
| 136 } | |
| 137 | |
| 138 int SVGFontFaceElement::xHeight() const | |
| 139 { | |
| 140 return static_cast<int>(ceilf(fastGetAttribute(x_heightAttr).toFloat())); | |
| 141 } | |
| 142 | |
| 143 float SVGFontFaceElement::horizontalOriginX() const | |
| 144 { | |
| 145 if (!m_fontElement) | |
| 146 return 0.0f; | |
| 147 | |
| 148 // Spec: The X-coordinate in the font coordinate system of the origin of a g
lyph to be used when | |
| 149 // drawing horizontally oriented text. (Note that the origin applies to all
glyphs in the font.) | |
| 150 // If the attribute is not specified, the effect is as if a value of "0" wer
e specified. | |
| 151 return m_fontElement->fastGetAttribute(horiz_origin_xAttr).toFloat(); | |
| 152 } | |
| 153 | |
| 154 float SVGFontFaceElement::horizontalOriginY() const | |
| 155 { | |
| 156 if (!m_fontElement) | |
| 157 return 0.0f; | |
| 158 | |
| 159 // Spec: The Y-coordinate in the font coordinate system of the origin of a g
lyph to be used when | |
| 160 // drawing horizontally oriented text. (Note that the origin applies to all
glyphs in the font.) | |
| 161 // If the attribute is not specified, the effect is as if a value of "0" wer
e specified. | |
| 162 return m_fontElement->fastGetAttribute(horiz_origin_yAttr).toFloat(); | |
| 163 } | |
| 164 | |
| 165 float SVGFontFaceElement::horizontalAdvanceX() const | |
| 166 { | |
| 167 if (!m_fontElement) | |
| 168 return 0.0f; | |
| 169 | |
| 170 // Spec: The default horizontal advance after rendering a glyph in horizonta
l orientation. Glyph | |
| 171 // widths are required to be non-negative, even if the glyph is typically re
ndered right-to-left, | |
| 172 // as in Hebrew and Arabic scripts. | |
| 173 return m_fontElement->fastGetAttribute(horiz_adv_xAttr).toFloat(); | |
| 174 } | |
| 175 | |
| 176 float SVGFontFaceElement::verticalOriginX() const | |
| 177 { | |
| 178 if (!m_fontElement) | |
| 179 return 0.0f; | |
| 180 | |
| 181 // Spec: The default X-coordinate in the font coordinate system of the origi
n of a glyph to be used when | |
| 182 // drawing vertically oriented text. If the attribute is not specified, the
effect is as if the attribute | |
| 183 // were set to half of the effective value of attribute horiz-adv-x. | |
| 184 const AtomicString& value = m_fontElement->fastGetAttribute(vert_origin_xAtt
r); | |
| 185 if (value.isEmpty()) | |
| 186 return horizontalAdvanceX() / 2.0f; | |
| 187 | |
| 188 return value.toFloat(); | |
| 189 } | |
| 190 | |
| 191 float SVGFontFaceElement::verticalOriginY() const | |
| 192 { | |
| 193 if (!m_fontElement) | |
| 194 return 0.0f; | |
| 195 | |
| 196 // Spec: The default Y-coordinate in the font coordinate system of the origi
n of a glyph to be used when | |
| 197 // drawing vertically oriented text. If the attribute is not specified, the
effect is as if the attribute | |
| 198 // were set to the position specified by the font's ascent attribute. | |
| 199 const AtomicString& value = m_fontElement->fastGetAttribute(vert_origin_yAtt
r); | |
| 200 if (value.isEmpty()) | |
| 201 return ascent(); | |
| 202 | |
| 203 return value.toFloat(); | |
| 204 } | |
| 205 | |
| 206 float SVGFontFaceElement::verticalAdvanceY() const | |
| 207 { | |
| 208 if (!m_fontElement) | |
| 209 return 0.0f; | |
| 210 | |
| 211 // Spec: The default vertical advance after rendering a glyph in vertical or
ientation. If the attribute is | |
| 212 // not specified, the effect is as if a value equivalent of one em were spec
ified (see units-per-em). | |
| 213 const AtomicString& value = m_fontElement->fastGetAttribute(vert_adv_yAttr); | |
| 214 if (value.isEmpty()) | |
| 215 return 1.0f; | |
| 216 | |
| 217 return value.toFloat(); | |
| 218 } | |
| 219 | |
| 220 int SVGFontFaceElement::ascent() const | |
| 221 { | |
| 222 // Spec: Same syntax and semantics as the 'ascent' descriptor within an @fon
t-face rule. The maximum | |
| 223 // unaccented height of the font within the font coordinate system. If the a
ttribute is not specified, | |
| 224 // the effect is as if the attribute were set to the difference between the
units-per-em value and the | |
| 225 // vert-origin-y value for the corresponding font. | |
| 226 const AtomicString& ascentValue = fastGetAttribute(ascentAttr); | |
| 227 if (!ascentValue.isEmpty()) | |
| 228 return static_cast<int>(ceilf(ascentValue.toFloat())); | |
| 229 | |
| 230 if (m_fontElement) { | |
| 231 const AtomicString& vertOriginY = m_fontElement->fastGetAttribute(vert_o
rigin_yAttr); | |
| 232 if (!vertOriginY.isEmpty()) | |
| 233 return static_cast<int>(unitsPerEm()) - static_cast<int>(ceilf(vertO
riginY.toFloat())); | |
| 234 } | |
| 235 | |
| 236 // Match Batiks default value | |
| 237 return static_cast<int>(ceilf(unitsPerEm() * 0.8f)); | |
| 238 } | |
| 239 | |
| 240 int SVGFontFaceElement::descent() const | |
| 241 { | |
| 242 // Spec: Same syntax and semantics as the 'descent' descriptor within an @fo
nt-face rule. The maximum | |
| 243 // unaccented depth of the font within the font coordinate system. If the at
tribute is not specified, | |
| 244 // the effect is as if the attribute were set to the vert-origin-y value for
the corresponding font. | |
| 245 const AtomicString& descentValue = fastGetAttribute(descentAttr); | |
| 246 if (!descentValue.isEmpty()) { | |
| 247 // 14 different W3C SVG 1.1 testcases use a negative descent value, | |
| 248 // where a positive was meant to be used Including: | |
| 249 // animate-elem-24-t.svg, fonts-elem-01-t.svg, fonts-elem-02-t.svg (and
11 others) | |
| 250 int descent = static_cast<int>(ceilf(descentValue.toFloat())); | |
| 251 return descent < 0 ? -descent : descent; | |
| 252 } | |
| 253 | |
| 254 if (m_fontElement) { | |
| 255 const AtomicString& vertOriginY = m_fontElement->fastGetAttribute(vert_o
rigin_yAttr); | |
| 256 if (!vertOriginY.isEmpty()) | |
| 257 return static_cast<int>(ceilf(vertOriginY.toFloat())); | |
| 258 } | |
| 259 | |
| 260 // Match Batiks default value | |
| 261 return static_cast<int>(ceilf(unitsPerEm() * 0.2f)); | |
| 262 } | |
| 263 | |
| 264 String SVGFontFaceElement::fontFamily() const | |
| 265 { | |
| 266 return m_fontFaceRule->properties().getPropertyValue(CSSPropertyFontFamily); | |
| 267 } | |
| 268 | |
| 269 SVGFontElement* SVGFontFaceElement::associatedFontElement() const | |
| 270 { | |
| 271 ASSERT(parentNode() == m_fontElement); | |
| 272 ASSERT(!parentNode() || isSVGFontElement(*parentNode())); | |
| 273 return m_fontElement; | |
| 274 } | |
| 275 | |
| 276 void SVGFontFaceElement::rebuildFontFace() | |
| 277 { | |
| 278 if (!inDocument()) { | |
| 279 ASSERT(!m_fontElement); | |
| 280 return; | |
| 281 } | |
| 282 | |
| 283 bool describesParentFont = isSVGFontElement(*parentNode()); | |
| 284 RefPtrWillBeRawPtr<CSSValueList> list = nullptr; | |
| 285 | |
| 286 if (describesParentFont) { | |
| 287 m_fontElement = toSVGFontElement(parentNode()); | |
| 288 | |
| 289 list = CSSValueList::createCommaSeparated(); | |
| 290 list->append(CSSFontFaceSrcValue::createLocal(fontFamily())); | |
| 291 } else { | |
| 292 m_fontElement = nullptr; | |
| 293 // we currently ignore all but the last src element, alternatively we co
uld concat them | |
| 294 if (SVGFontFaceSrcElement* element = Traversal<SVGFontFaceSrcElement>::l
astChild(*this)) | |
| 295 list = element->srcValue(); | |
| 296 } | |
| 297 | |
| 298 if (!list || !list->length()) | |
| 299 return; | |
| 300 | |
| 301 // Parse in-memory CSS rules | |
| 302 m_fontFaceRule->mutableProperties().addParsedProperty(CSSProperty(CSSPropert
ySrc, list)); | |
| 303 | |
| 304 if (describesParentFont) { | |
| 305 // Traverse parsed CSS values and associate CSSFontFaceSrcValue elements
with ourselves. | |
| 306 RefPtrWillBeRawPtr<CSSValue> src = m_fontFaceRule->properties().getPrope
rtyCSSValue(CSSPropertySrc); | |
| 307 CSSValueList* srcList = toCSSValueList(src.get()); | |
| 308 | |
| 309 unsigned srcLength = srcList ? srcList->length() : 0; | |
| 310 for (unsigned i = 0; i < srcLength; i++) { | |
| 311 if (CSSFontFaceSrcValue* item = toCSSFontFaceSrcValue(srcList->item(
i))) | |
| 312 item->setSVGFontFaceElement(this); | |
| 313 } | |
| 314 } | |
| 315 | |
| 316 document().styleResolverChanged(); | |
| 317 } | |
| 318 | |
| 319 Node::InsertionNotificationRequest SVGFontFaceElement::insertedInto(ContainerNod
e* rootParent) | |
| 320 { | |
| 321 SVGElement::insertedInto(rootParent); | |
| 322 if (!rootParent->inDocument()) { | |
| 323 ASSERT(!m_fontElement); | |
| 324 return InsertionDone; | |
| 325 } | |
| 326 document().accessSVGExtensions().registerSVGFontFaceElement(this); | |
| 327 | |
| 328 rebuildFontFace(); | |
| 329 return InsertionDone; | |
| 330 } | |
| 331 | |
| 332 void SVGFontFaceElement::removedFrom(ContainerNode* rootParent) | |
| 333 { | |
| 334 SVGElement::removedFrom(rootParent); | |
| 335 | |
| 336 if (rootParent->inDocument()) { | |
| 337 m_fontElement = nullptr; | |
| 338 document().accessSVGExtensions().unregisterSVGFontFaceElement(this); | |
| 339 | |
| 340 // FIXME: HTMLTemplateElement's document or imported document can be ac
tive? | |
| 341 // If so, we also need to check whether fontSelector() is nullptr or not
. | |
| 342 // Otherwise, we will use just document().isActive() here. | |
| 343 if (document().isActive() && document().styleEngine()->fontSelector()) { | |
| 344 document().styleEngine()->fontSelector()->fontFaceCache()->remove(m_
fontFaceRule.get()); | |
| 345 document().accessSVGExtensions().registerPendingSVGFontFaceElementsF
orRemoval(this); | |
| 346 } | |
| 347 m_fontFaceRule->mutableProperties().clear(); | |
| 348 document().styleResolverChanged(); | |
| 349 } else | |
| 350 ASSERT(!m_fontElement); | |
| 351 } | |
| 352 | |
| 353 void SVGFontFaceElement::childrenChanged(const ChildrenChange& change) | |
| 354 { | |
| 355 SVGElement::childrenChanged(change); | |
| 356 rebuildFontFace(); | |
| 357 } | |
| 358 | |
| 359 void SVGFontFaceElement::trace(Visitor* visitor) | |
| 360 { | |
| 361 visitor->trace(m_fontFaceRule); | |
| 362 visitor->trace(m_fontElement); | |
| 363 SVGElement::trace(visitor); | |
| 364 } | |
| 365 | |
| 366 } // namespace blink | |
| 367 | |
| 368 #endif // ENABLE(SVG_FONTS) | |
| OLD | NEW |