1/*
2 * Copyright (C) 2006-2019 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org>
4 * Copyright (C) 2014 Adobe Systems Incorporated. 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#include "SVGForeignObjectElement.h"
24
25#include "CSSPropertyNames.h"
26#include "RenderSVGForeignObject.h"
27#include "RenderSVGResource.h"
28#include "SVGLengthValue.h"
29#include "SVGNames.h"
30#include <wtf/Assertions.h>
31#include <wtf/IsoMallocInlines.h>
32#include <wtf/NeverDestroyed.h>
33
34namespace WebCore {
35
36WTF_MAKE_ISO_ALLOCATED_IMPL(SVGForeignObjectElement);
37
38inline SVGForeignObjectElement::SVGForeignObjectElement(const QualifiedName& tagName, Document& document)
39 : SVGGraphicsElement(tagName, document)
40 , SVGExternalResourcesRequired(this)
41{
42 ASSERT(hasTagName(SVGNames::foreignObjectTag));
43 static std::once_flag onceFlag;
44 std::call_once(onceFlag, [] {
45 PropertyRegistry::registerProperty<SVGNames::xAttr, &SVGForeignObjectElement::m_x>();
46 PropertyRegistry::registerProperty<SVGNames::yAttr, &SVGForeignObjectElement::m_y>();
47 PropertyRegistry::registerProperty<SVGNames::widthAttr, &SVGForeignObjectElement::m_width>();
48 PropertyRegistry::registerProperty<SVGNames::heightAttr, &SVGForeignObjectElement::m_height>();
49 });
50}
51
52Ref<SVGForeignObjectElement> SVGForeignObjectElement::create(const QualifiedName& tagName, Document& document)
53{
54 return adoptRef(*new SVGForeignObjectElement(tagName, document));
55}
56
57void SVGForeignObjectElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
58{
59 SVGParsingError parseError = NoError;
60
61 if (name == SVGNames::xAttr)
62 m_x->setBaseValInternal(SVGLengthValue::construct(LengthModeWidth, value, parseError));
63 else if (name == SVGNames::yAttr)
64 m_y->setBaseValInternal(SVGLengthValue::construct(LengthModeHeight, value, parseError));
65 else if (name == SVGNames::widthAttr)
66 m_width->setBaseValInternal(SVGLengthValue::construct(LengthModeWidth, value, parseError));
67 else if (name == SVGNames::heightAttr)
68 m_height->setBaseValInternal(SVGLengthValue::construct(LengthModeHeight, value, parseError));
69
70 reportAttributeParsingError(parseError, name, value);
71
72 SVGGraphicsElement::parseAttribute(name, value);
73 SVGExternalResourcesRequired::parseAttribute(name, value);
74}
75
76void SVGForeignObjectElement::svgAttributeChanged(const QualifiedName& attrName)
77{
78 if (attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr) {
79 invalidateSVGPresentationAttributeStyle();
80 return;
81 }
82
83 if (attrName == SVGNames::xAttr || attrName == SVGNames::yAttr) {
84 updateRelativeLengthsInformation();
85 if (auto renderer = this->renderer())
86 RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer);
87 return;
88 }
89
90 SVGGraphicsElement::svgAttributeChanged(attrName);
91 SVGExternalResourcesRequired::svgAttributeChanged(attrName);
92}
93
94RenderPtr<RenderElement> SVGForeignObjectElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition&)
95{
96 return createRenderer<RenderSVGForeignObject>(*this, WTFMove(style));
97}
98
99bool SVGForeignObjectElement::childShouldCreateRenderer(const Node& child) const
100{
101 // Disallow arbitary SVG content. Only allow proper <svg xmlns="svgNS"> subdocuments.
102 if (child.isSVGElement())
103 return child.hasTagName(SVGNames::svgTag);
104
105 // Skip over SVG rules which disallow non-SVG kids
106 return StyledElement::childShouldCreateRenderer(child);
107}
108
109bool SVGForeignObjectElement::rendererIsNeeded(const RenderStyle& style)
110{
111 // Suppress foreignObject renderers in SVG hidden containers.
112 // (https://bugs.webkit.org/show_bug.cgi?id=87297)
113 // Note that we currently do not support foreignObject instantiation via <use>, hence it is safe
114 // to use parentElement() here. If that changes, this method should be updated to use
115 // parentOrShadowHostElement() instead.
116 auto ancestor = makeRefPtr(parentElement());
117 while (ancestor && ancestor->isSVGElement()) {
118 if (ancestor->renderer() && ancestor->renderer()->isSVGHiddenContainer())
119 return false;
120
121 ancestor = ancestor->parentElement();
122 }
123
124 return SVGGraphicsElement::rendererIsNeeded(style);
125}
126
127}
128