File indexing completed on 2024-04-28 15:24:41

0001 /*
0002     Copyright (C) 2004, 2005, 2006, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
0003                   2004, 2005, 2007 Rob Buis <buis@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 #include "wtf/Platform.h"
0022 
0023 #if ENABLE(SVG)
0024 #include "SVGStyledElement.h"
0025 
0026 /*#include "Attr.h"
0027 #include "CSSParser.h"
0028 #include "CSSStyleSelector.h"
0029 #include "CString.h"*/
0030 #include "cssstyleselector.h"
0031 #include "Document.h"
0032 /*#include "HTMLNames.h"*/
0033 #include "PlatformString.h"
0034 /*#include "SVGElementInstance.h"*/
0035 #include "SVGNames.h"
0036 #include "RenderObject.h"
0037 #include "SVGRenderStyle.h"
0038 /*#include "SVGResource.h"*/
0039 #include "SVGSVGElement.h"
0040 #include <wtf/Assertions.h>
0041 
0042 // khtml
0043 #include "css_base.h"
0044 
0045 namespace WebCore
0046 {
0047 
0048 using namespace SVGNames;
0049 using namespace DOM;
0050 
0051 static HashSet<const SVGStyledElement *> *gElementsWithInstanceUpdatesBlocked = nullptr;
0052 
0053 SVGStyledElement::SVGStyledElement(const QualifiedName &tagName, Document *doc)
0054     : SVGElement(tagName, doc)
0055 {
0056 }
0057 
0058 SVGStyledElement::~SVGStyledElement()
0059 {
0060 //    SVGResource::removeClient(this);
0061 }
0062 
0063 ANIMATED_PROPERTY_DEFINITIONS(SVGStyledElement, String, String, string, ClassName, className, HTMLNames::classAttr, m_className)
0064 
0065 bool SVGStyledElement::rendererIsNeeded(RenderStyle *style)
0066 {
0067     // https://www.w3.org/TR/SVG/extend.html#PrivateData
0068     // Prevent anything other than SVG renderers from appearing in our render tree
0069     // Spec: SVG allows inclusion of elements from foreign namespaces anywhere
0070     // with the SVG content. In general, the SVG user agent will include the unknown
0071     // elements in the DOM but will otherwise ignore unknown elements.
0072     if (!parentNode() || parentNode()->isSVGElement()) {
0073         return StyledElement::rendererIsNeeded(style);
0074     }
0075 
0076     return false;
0077 }
0078 
0079 static void mapAttributeToCSSProperty(HashMap<DOMStringImpl *, int> *propertyNameToIdMap, const QualifiedName &attrName)
0080 {
0081     /*int propertyId = cssPropertyID(attrName.localName());*/
0082     QString propName = attrName.localName().string();
0083     int propertyId = DOM::getPropertyID(propName.toLatin1(), propName.length());
0084     ASSERT(propertyId > 0);
0085     propertyNameToIdMap->set(attrName.localName().implementation(), propertyId);
0086 }
0087 
0088 int SVGStyledElement::cssPropertyIdForSVGAttributeName(const QualifiedName &attrName)
0089 {
0090     if (!attrName.namespaceURI().isEmpty()/*khtml fix, was isNull()*/) {
0091         return 0;
0092     }
0093 
0094     // ### I think this is better redone as a switch.
0095     static HashMap<DOMStringImpl *, int> *propertyNameToIdMap = nullptr;
0096     if (!propertyNameToIdMap) {
0097         propertyNameToIdMap = new HashMap<DOMStringImpl *, int>;
0098         // This is a list of all base CSS and SVG CSS properties which are exposed as SVG XML attributes
0099         mapAttributeToCSSProperty(propertyNameToIdMap, alignment_baselineAttr);
0100         mapAttributeToCSSProperty(propertyNameToIdMap, baseline_shiftAttr);
0101         mapAttributeToCSSProperty(propertyNameToIdMap, clipAttr);
0102         mapAttributeToCSSProperty(propertyNameToIdMap, clip_pathAttr);
0103         mapAttributeToCSSProperty(propertyNameToIdMap, clip_ruleAttr);
0104         mapAttributeToCSSProperty(propertyNameToIdMap, colorAttr);
0105         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolationAttr);
0106         mapAttributeToCSSProperty(propertyNameToIdMap, color_interpolation_filtersAttr);
0107         mapAttributeToCSSProperty(propertyNameToIdMap, color_profileAttr);
0108         mapAttributeToCSSProperty(propertyNameToIdMap, color_renderingAttr);
0109         mapAttributeToCSSProperty(propertyNameToIdMap, cursorAttr);
0110         mapAttributeToCSSProperty(propertyNameToIdMap, directionAttr);
0111         mapAttributeToCSSProperty(propertyNameToIdMap, displayAttr);
0112         mapAttributeToCSSProperty(propertyNameToIdMap, dominant_baselineAttr);
0113         mapAttributeToCSSProperty(propertyNameToIdMap, enable_backgroundAttr);
0114         mapAttributeToCSSProperty(propertyNameToIdMap, fillAttr);
0115         mapAttributeToCSSProperty(propertyNameToIdMap, fill_opacityAttr);
0116         mapAttributeToCSSProperty(propertyNameToIdMap, fill_ruleAttr);
0117         mapAttributeToCSSProperty(propertyNameToIdMap, filterAttr);
0118         mapAttributeToCSSProperty(propertyNameToIdMap, flood_colorAttr);
0119         mapAttributeToCSSProperty(propertyNameToIdMap, flood_opacityAttr);
0120         mapAttributeToCSSProperty(propertyNameToIdMap, font_familyAttr);
0121         mapAttributeToCSSProperty(propertyNameToIdMap, font_sizeAttr);
0122         mapAttributeToCSSProperty(propertyNameToIdMap, font_stretchAttr);
0123         mapAttributeToCSSProperty(propertyNameToIdMap, font_styleAttr);
0124         mapAttributeToCSSProperty(propertyNameToIdMap, font_variantAttr);
0125         mapAttributeToCSSProperty(propertyNameToIdMap, font_weightAttr);
0126         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_horizontalAttr);
0127         mapAttributeToCSSProperty(propertyNameToIdMap, glyph_orientation_verticalAttr);
0128         mapAttributeToCSSProperty(propertyNameToIdMap, image_renderingAttr);
0129         mapAttributeToCSSProperty(propertyNameToIdMap, kerningAttr);
0130         mapAttributeToCSSProperty(propertyNameToIdMap, letter_spacingAttr);
0131         mapAttributeToCSSProperty(propertyNameToIdMap, lighting_colorAttr);
0132         mapAttributeToCSSProperty(propertyNameToIdMap, marker_endAttr);
0133         mapAttributeToCSSProperty(propertyNameToIdMap, marker_midAttr);
0134         mapAttributeToCSSProperty(propertyNameToIdMap, marker_startAttr);
0135         mapAttributeToCSSProperty(propertyNameToIdMap, maskAttr);
0136         mapAttributeToCSSProperty(propertyNameToIdMap, opacityAttr);
0137         mapAttributeToCSSProperty(propertyNameToIdMap, overflowAttr);
0138         mapAttributeToCSSProperty(propertyNameToIdMap, pointer_eventsAttr);
0139         mapAttributeToCSSProperty(propertyNameToIdMap, shape_renderingAttr);
0140         mapAttributeToCSSProperty(propertyNameToIdMap, stop_colorAttr);
0141         mapAttributeToCSSProperty(propertyNameToIdMap, stop_opacityAttr);
0142         mapAttributeToCSSProperty(propertyNameToIdMap, strokeAttr);
0143         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dasharrayAttr);
0144         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_dashoffsetAttr);
0145         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linecapAttr);
0146         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_linejoinAttr);
0147         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_miterlimitAttr);
0148         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_opacityAttr);
0149         mapAttributeToCSSProperty(propertyNameToIdMap, stroke_widthAttr);
0150         mapAttributeToCSSProperty(propertyNameToIdMap, text_anchorAttr);
0151         mapAttributeToCSSProperty(propertyNameToIdMap, text_decorationAttr);
0152         mapAttributeToCSSProperty(propertyNameToIdMap, text_renderingAttr);
0153         mapAttributeToCSSProperty(propertyNameToIdMap, unicode_bidiAttr);
0154         mapAttributeToCSSProperty(propertyNameToIdMap, visibilityAttr);
0155         mapAttributeToCSSProperty(propertyNameToIdMap, word_spacingAttr);
0156         mapAttributeToCSSProperty(propertyNameToIdMap, writing_modeAttr);
0157     }
0158     return propertyNameToIdMap->get(attrName.localName().implementation());
0159 }
0160 
0161 /*bool SVGStyledElement::mapToEntry(const QualifiedName& attrName, MappedAttributeEntry& result) const
0162 {
0163     if (SVGStyledElement::cssPropertyIdForSVGAttributeName(attrName) > 0) {
0164         result = eSVG;
0165         return false;
0166     }
0167     return SVGElement::mapToEntry(attrName, result);
0168 }*/
0169 
0170 void SVGStyledElement::parseMappedAttribute(MappedAttribute *attr)
0171 {
0172     // NOTE: Any subclass which overrides parseMappedAttribute for a property handled by
0173     // cssPropertyIdForSVGAttributeName will also have to override mapToEntry to disable the default eSVG mapping
0174     int id = attr->id();
0175     if (id == ATTR_STYLE) {
0176         if (inlineStyleDecls()) {
0177             inlineStyleDecls()->clear();
0178         } else {
0179             createInlineDecl();
0180         }
0181         inlineStyleDecls()->setProperty(attr->value());
0182         setChanged();
0183         return;
0184     }
0185     int propId = SVGStyledElement::cssPropertyIdForSVGAttributeName(attr->name());
0186     if (propId > 0) {
0187         addCSSProperty(attr, propId, attr->value());
0188         setChanged();
0189         return;
0190     }
0191 
0192     // id and class are handled by StyledElement
0193     SVGElement::parseMappedAttribute(attr);
0194 }
0195 
0196 bool SVGStyledElement::isKnownAttribute(const QualifiedName &attrName)
0197 {
0198     // Recognize all style related SVG CSS properties
0199     int propId = SVGStyledElement::cssPropertyIdForSVGAttributeName(attrName);
0200     if (propId > 0) {
0201         return true;
0202     }
0203     return (attrName.id() == ATTR_ID || attrName.id() == ATTR_STYLE);
0204     /*return (attrName == HTMLNames::idAttr || attrName == HTMLNames::styleAttr); */
0205 }
0206 
0207 void SVGStyledElement::svgAttributeChanged(const QualifiedName &attrName)
0208 {
0209     SVGElement::svgAttributeChanged(attrName);
0210 
0211     // If we're the child of a resource element, be sure to invalidate it.
0212     invalidateResourcesInAncestorChain();
0213 
0214     SVGDocumentExtensions *extensions = document()->accessSVGExtensions();
0215     if (!extensions) {
0216         return;
0217     }
0218 
0219     // TODO: Fix bug https://bugs.webkit.org/show_bug.cgi?id=15430 (SVGElementInstances should rebuild themselves lazily)
0220 
0221     // In case we're referenced by a <use> element, we have element instances registered
0222     // to us in the SVGDocumentExtensions. If notifyAttributeChange() is called, we need
0223     // to recursively update all children including ourselves.
0224     updateElementInstance(extensions);
0225 }
0226 
0227 void SVGStyledElement::invalidateResourcesInAncestorChain() const
0228 {
0229     Node *node = parentNode();
0230     while (node) {
0231         if (!node->isSVGElement()) {
0232             break;
0233         }
0234 
0235         SVGElement *element = static_cast<SVGElement *>(node);
0236         if (SVGStyledElement *styledElement = static_cast<SVGStyledElement *>(element->isStyled() ? element : nullptr)) {
0237             /*if (SVGResource* resource = styledElement->canvasResource())
0238                 resource->invalidate();*/
0239         }
0240 
0241         node = node->parentNode();
0242     }
0243 }
0244 
0245 void SVGStyledElement::childrenChanged(bool changedByParser, Node *beforeChange, Node *afterChange, int childCountDelta)
0246 {
0247     Q_UNUSED(changedByParser);
0248     Q_UNUSED(beforeChange);
0249     Q_UNUSED(afterChange);
0250     Q_UNUSED(childCountDelta);
0251     SVGElement::childrenChanged();
0252     /*SVGElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
0253     if (document()->parsing())
0254         return;
0255 
0256     SVGDocumentExtensions* extensions = document()->accessSVGExtensions();
0257     if (!extensions)
0258         return;
0259 
0260     // TODO: Fix bug https://bugs.webkit.org/show_bug.cgi?id=15430 (SVGElementInstances should rebuild themselves lazily)
0261 
0262     // In case we're referenced by a <use> element, we have element instances registered
0263     // to us in the SVGDocumentExtensions. If childrenChanged() is called, we need
0264     // to recursively update all children including ourselves.
0265     updateElementInstance(extensions);*/
0266 }
0267 
0268 void SVGStyledElement::updateElementInstance(SVGDocumentExtensions *extensions) const
0269 {
0270     Q_UNUSED(extensions);
0271     /*if (gElementsWithInstanceUpdatesBlocked && gElementsWithInstanceUpdatesBlocked->contains(this))
0272         return;
0273 
0274     SVGStyledElement* nonConstThis = const_cast<SVGStyledElement*>(this);
0275     HashSet<SVGElementInstance*>* set = extensions->instancesForElement(nonConstThis);
0276     if (!set || set->isEmpty())
0277         return;
0278 
0279     // We need to be careful here, as the instancesForElement
0280     // hash set may be modified after we call updateInstance!
0281     HashSet<SVGElementInstance*> localCopy;
0282 
0283     // First create a local copy of the hashset
0284     HashSet<SVGElementInstance*>::const_iterator it1 = set->begin();
0285     const HashSet<SVGElementInstance*>::const_iterator end1 = set->end();
0286 
0287     for (; it1 != end1; ++it1)
0288         localCopy.add(*it1);
0289 
0290     // Actually nofify instances to update
0291     HashSet<SVGElementInstance*>::const_iterator it2 = localCopy.begin();
0292     const HashSet<SVGElementInstance*>::const_iterator end2 = localCopy.end();
0293 
0294     for (; it2 != end2; ++it2)
0295         (*it2)->updateInstance(nonConstThis);*/
0296 }
0297 
0298 RenderStyle *SVGStyledElement::resolveStyle(RenderStyle *parentStyle)
0299 {
0300     Q_UNUSED(parentStyle);
0301     if (renderer()) {
0302         RenderStyle *renderStyle = renderer()->style();
0303         renderStyle->ref();
0304         return renderStyle;
0305     }
0306 
0307     return document()->styleSelector()->styleForElement(this/*, parentStyle*/);
0308 }
0309 
0310 PassRefPtr<DOM::CSSValueImpl> SVGStyledElement::getPresentationAttribute(const String &name)
0311 {
0312     Q_UNUSED(name);
0313     /*MappedAttribute* cssSVGAttr = mappedAttributes()->getAttributeItem(name);
0314     if (!cssSVGAttr || !cssSVGAttr->style())
0315         return 0;
0316     return cssSVGAttr->style()->getPropertyCSSValue(name);*/
0317     Q_ASSERT(false);
0318     return new CSSPrimitiveValueImpl(0);
0319 }
0320 
0321 void SVGStyledElement::detach()
0322 {
0323     /*SVGResource::removeClient(this);*/
0324     SVGElement::detach();
0325 }
0326 
0327 void SVGStyledElement::setInstanceUpdatesBlocked(bool blockUpdates)
0328 {
0329     if (blockUpdates) {
0330         if (!gElementsWithInstanceUpdatesBlocked) {
0331             gElementsWithInstanceUpdatesBlocked = new HashSet<const SVGStyledElement *>;
0332         }
0333         gElementsWithInstanceUpdatesBlocked->add(this);
0334     } else {
0335         ASSERT(gElementsWithInstanceUpdatesBlocked);
0336         ASSERT(gElementsWithInstanceUpdatesBlocked->contains(this));
0337         gElementsWithInstanceUpdatesBlocked->remove(this);
0338     }
0339 }
0340 
0341 }
0342 
0343 #endif // ENABLE(SVG)