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#pragma once
27
28#include "SVGList.h"
29
30namespace WebCore {
31
32template<typename PropertyType>
33class SVGPropertyList : public SVGList<Ref<PropertyType>>, public SVGPropertyOwner {
34public:
35 using BaseList = SVGList<Ref<PropertyType>>;
36 using BaseList::isEmpty;
37 using BaseList::size;
38 using BaseList::append;
39
40 // Visual Studio doesn't seem to see these private constructors from subclasses.
41 // FIXME: See what it takes to remove this hack.
42#if !COMPILER(MSVC)
43protected:
44#endif
45 using SVGPropertyOwner::SVGPropertyOwner;
46 using BaseList::m_items;
47 using BaseList::m_access;
48 using BaseList::m_owner;
49
50 SVGPropertyList(SVGPropertyOwner* owner = nullptr, SVGPropertyAccess access = SVGPropertyAccess::ReadWrite)
51 : BaseList(owner, access)
52 {
53 }
54
55 ~SVGPropertyList()
56 {
57 // Detach the items from the list before it is deleted.
58 detachItems();
59 }
60
61 void detachItems() override
62 {
63 for (auto& item : m_items)
64 item->detach();
65 }
66
67 SVGPropertyOwner* owner() const override { return m_owner; }
68
69 void commitPropertyChange(SVGProperty*) override
70 {
71 if (owner())
72 owner()->commitPropertyChange(this);
73 }
74
75 Ref<PropertyType> at(unsigned index) const override
76 {
77 ASSERT(index < size());
78 return m_items.at(index).copyRef();
79 }
80
81 Ref<PropertyType> insert(unsigned index, Ref<PropertyType>&& newItem) override
82 {
83 ASSERT(index <= size());
84
85 // Spec: if newItem is not a detached object, then set newItem to be
86 // a clone object of newItem.
87 if (newItem->isAttached())
88 newItem = newItem->clone();
89
90 // Spec: Attach newItem to the list object.
91 newItem->attach(this, m_access);
92 m_items.insert(index, WTFMove(newItem));
93 return at(index);
94 }
95
96 Ref<PropertyType> replace(unsigned index, Ref<PropertyType>&& newItem) override
97 {
98 ASSERT(index < size());
99 Ref<PropertyType>& item = m_items[index];
100
101 // Spec: Detach item.
102 item->detach();
103
104 // Spec: if newItem is not a detached object, then set newItem to be
105 // a clone object of newItem.
106 if (newItem->isAttached())
107 item = newItem->clone();
108 else
109 item = WTFMove(newItem);
110
111 // Spec: Attach newItem to the list object.
112 item->attach(this, m_access);
113 return at(index);
114 }
115
116 Ref<PropertyType> remove(unsigned index) override
117 {
118 ASSERT(index < size());
119 Ref<PropertyType> item = at(index);
120
121 // Spec: Detach item.
122 item->detach();
123 m_items.remove(index);
124 return item;
125 }
126
127 Ref<PropertyType> append(Ref<PropertyType>&& newItem) override
128 {
129 // Spec: if newItem is not a detached object, then set newItem to be
130 // a clone object of newItem.
131 if (newItem->isAttached())
132 newItem = newItem->clone();
133
134 // Spec: Attach newItem to the list object.
135 newItem->attach(this, m_access);
136 m_items.append(WTFMove(newItem));
137 return at(size() - 1);
138 }
139};
140
141}
142