1/*
2 * Copyright (C) 2018-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "SVGAttributeAnimator.h"
28
29#include "CSSComputedStyleDeclaration.h"
30#include "CSSPropertyParser.h"
31#include "SVGElement.h"
32
33namespace WebCore {
34
35bool SVGAttributeAnimator::isAnimatedStylePropertyAniamtor(const SVGElement* targetElement) const
36{
37 return targetElement->isAnimatedStyleAttribute(m_attributeName);
38}
39
40void SVGAttributeAnimator::applyAnimatedStylePropertyChange(SVGElement* element, CSSPropertyID id, const String& value)
41{
42 ASSERT(element);
43 ASSERT(!element->m_deletionHasBegun);
44
45 if (!element->ensureAnimatedSMILStyleProperties().setProperty(id, value, false))
46 return;
47 element->invalidateStyle();
48}
49
50void SVGAttributeAnimator::applyAnimatedStylePropertyChange(SVGElement* targetElement, const String& value)
51{
52 ASSERT(targetElement);
53 ASSERT(m_attributeName != anyQName());
54
55 // FIXME: Do we really need to check both isConnected and !parentNode?
56 if (!targetElement->isConnected() || !targetElement->parentNode())
57 return;
58
59 CSSPropertyID id = cssPropertyID(m_attributeName.localName());
60
61 SVGElement::InstanceUpdateBlocker blocker(*targetElement);
62 applyAnimatedStylePropertyChange(targetElement, id, value);
63
64 // If the target element has instances, update them as well, w/o requiring the <use> tree to be rebuilt.
65 for (auto* instance : targetElement->instances())
66 applyAnimatedStylePropertyChange(instance, id, value);
67}
68
69void SVGAttributeAnimator::removeAnimatedStyleProperty(SVGElement* element, CSSPropertyID id)
70{
71 ASSERT(element);
72 ASSERT(!element->m_deletionHasBegun);
73
74 element->ensureAnimatedSMILStyleProperties().removeProperty(id);
75 element->invalidateStyle();
76}
77
78void SVGAttributeAnimator::removeAnimatedStyleProperty(SVGElement* targetElement)
79{
80 ASSERT(targetElement);
81 ASSERT(m_attributeName != anyQName());
82
83 // FIXME: Do we really need to check both isConnected and !parentNode?
84 if (!targetElement->isConnected() || !targetElement->parentNode())
85 return;
86
87 CSSPropertyID id = cssPropertyID(m_attributeName.localName());
88
89 SVGElement::InstanceUpdateBlocker blocker(*targetElement);
90 removeAnimatedStyleProperty(targetElement, id);
91
92 // If the target element has instances, update them as well, w/o requiring the <use> tree to be rebuilt.
93 for (auto* instance : targetElement->instances())
94 removeAnimatedStyleProperty(instance, id);
95}
96
97void SVGAttributeAnimator::applyAnimatedPropertyChange(SVGElement* element, const QualifiedName& attributeName)
98{
99 ASSERT(!element->m_deletionHasBegun);
100 element->svgAttributeChanged(attributeName);
101}
102
103void SVGAttributeAnimator::applyAnimatedPropertyChange(SVGElement* targetElement)
104{
105 ASSERT(targetElement);
106 ASSERT(m_attributeName != anyQName());
107
108 // FIXME: Do we really need to check both isConnected and !parentNode?
109 if (!targetElement->isConnected() || !targetElement->parentNode())
110 return;
111
112 SVGElement::InstanceUpdateBlocker blocker(*targetElement);
113 applyAnimatedPropertyChange(targetElement, m_attributeName);
114
115 // If the target element has instances, update them as well, w/o requiring the <use> tree to be rebuilt.
116 for (auto* instance : targetElement->instances())
117 applyAnimatedPropertyChange(instance, m_attributeName);
118}
119
120}
121