Line data Source code
1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 : /* This Source Code Form is subject to the terms of the Mozilla Public
4 : * License, v. 2.0. If a copy of the MPL was not distributed with this
5 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "DOMSVGStringList.h"
8 :
9 : #include "mozilla/dom/SVGStringListBinding.h"
10 : #include "mozilla/dom/SVGTests.h"
11 : #include "nsError.h"
12 : #include "nsCOMPtr.h"
13 : #include "nsSVGAttrTearoffTable.h"
14 : #include "nsQueryObject.h"
15 : #include <algorithm>
16 :
17 : // See the architecture comment in this file's header.
18 :
19 : namespace mozilla {
20 :
21 : using namespace dom;
22 :
23 : static inline
24 : nsSVGAttrTearoffTable<SVGStringList, DOMSVGStringList>&
25 0 : SVGStringListTearoffTable()
26 : {
27 : static nsSVGAttrTearoffTable<SVGStringList, DOMSVGStringList>
28 0 : sSVGStringListTearoffTable;
29 0 : return sSVGStringListTearoffTable;
30 : }
31 :
32 0 : NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(DOMSVGStringList, mElement)
33 :
34 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGStringList)
35 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGStringList)
36 :
37 0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGStringList)
38 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
39 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
40 0 : NS_INTERFACE_MAP_END
41 :
42 : //----------------------------------------------------------------------
43 : // Helper class: AutoChangeStringListNotifier
44 : // Stack-based helper class to pair calls to WillChangeStringListList and
45 : // DidChangeStringListList.
46 : class MOZ_RAII AutoChangeStringListNotifier
47 : {
48 : public:
49 0 : explicit AutoChangeStringListNotifier(DOMSVGStringList* aStringList MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
50 0 : : mStringList(aStringList)
51 : {
52 0 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
53 0 : MOZ_ASSERT(mStringList, "Expecting non-null stringList");
54 : mEmptyOrOldValue =
55 0 : mStringList->mElement->WillChangeStringList(mStringList->mIsConditionalProcessingAttribute,
56 0 : mStringList->mAttrEnum);
57 0 : }
58 :
59 0 : ~AutoChangeStringListNotifier()
60 0 : {
61 0 : mStringList->mElement->DidChangeStringList(mStringList->mIsConditionalProcessingAttribute,
62 0 : mStringList->mAttrEnum, mEmptyOrOldValue);
63 0 : }
64 :
65 : private:
66 : DOMSVGStringList* const mStringList;
67 : nsAttrValue mEmptyOrOldValue;
68 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
69 : };
70 :
71 : /* static */ already_AddRefed<DOMSVGStringList>
72 0 : DOMSVGStringList::GetDOMWrapper(SVGStringList *aList,
73 : nsSVGElement *aElement,
74 : bool aIsConditionalProcessingAttribute,
75 : uint8_t aAttrEnum)
76 : {
77 : RefPtr<DOMSVGStringList> wrapper =
78 0 : SVGStringListTearoffTable().GetTearoff(aList);
79 0 : if (!wrapper) {
80 : wrapper = new DOMSVGStringList(aElement,
81 : aIsConditionalProcessingAttribute,
82 0 : aAttrEnum);
83 0 : SVGStringListTearoffTable().AddTearoff(aList, wrapper);
84 : }
85 0 : return wrapper.forget();
86 : }
87 :
88 0 : DOMSVGStringList::~DOMSVGStringList()
89 : {
90 : // Script no longer has any references to us.
91 0 : SVGStringListTearoffTable().RemoveTearoff(&InternalList());
92 0 : }
93 :
94 : /* virtual */ JSObject*
95 0 : DOMSVGStringList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
96 : {
97 0 : return SVGStringListBinding::Wrap(aCx, this, aGivenProto);
98 : }
99 :
100 : // ----------------------------------------------------------------------------
101 : // SVGStringList implementation:
102 :
103 : uint32_t
104 0 : DOMSVGStringList::NumberOfItems() const
105 : {
106 0 : return InternalList().Length();
107 : }
108 :
109 : uint32_t
110 0 : DOMSVGStringList::Length() const
111 : {
112 0 : return NumberOfItems();
113 : }
114 :
115 : void
116 0 : DOMSVGStringList::Clear()
117 : {
118 0 : if (InternalList().IsExplicitlySet()) {
119 0 : AutoChangeStringListNotifier notifier(this);
120 0 : InternalList().Clear();
121 : }
122 0 : }
123 :
124 : void
125 0 : DOMSVGStringList::Initialize(const nsAString& aNewItem, nsAString& aRetval,
126 : ErrorResult& aRv)
127 : {
128 0 : if (InternalList().IsExplicitlySet()) {
129 0 : InternalList().Clear();
130 : }
131 0 : InsertItemBefore(aNewItem, 0, aRetval, aRv);
132 0 : }
133 :
134 : void
135 0 : DOMSVGStringList::GetItem(uint32_t aIndex, nsAString& aRetval, ErrorResult& aRv)
136 : {
137 : bool found;
138 0 : IndexedGetter(aIndex, found, aRetval);
139 0 : if (!found) {
140 0 : aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
141 : }
142 0 : }
143 :
144 : void
145 0 : DOMSVGStringList::IndexedGetter(uint32_t aIndex, bool& aFound,
146 : nsAString& aRetval)
147 : {
148 0 : aFound = aIndex < InternalList().Length();
149 0 : if (aFound) {
150 0 : aRetval = InternalList()[aIndex];
151 : }
152 0 : }
153 :
154 : void
155 0 : DOMSVGStringList::InsertItemBefore(const nsAString& aNewItem, uint32_t aIndex,
156 : nsAString& aRetval, ErrorResult& aRv)
157 : {
158 0 : if (aNewItem.IsEmpty()) {
159 0 : aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
160 0 : return;
161 : }
162 0 : aIndex = std::min(aIndex, InternalList().Length());
163 :
164 : // Ensure we have enough memory so we can avoid complex error handling below:
165 0 : if (!InternalList().SetCapacity(InternalList().Length() + 1)) {
166 0 : aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
167 0 : return;
168 : }
169 :
170 0 : AutoChangeStringListNotifier notifier(this);
171 0 : InternalList().InsertItem(aIndex, aNewItem);
172 0 : aRetval = aNewItem;
173 : }
174 :
175 : void
176 0 : DOMSVGStringList::ReplaceItem(const nsAString& aNewItem, uint32_t aIndex,
177 : nsAString& aRetval, ErrorResult& aRv)
178 : {
179 0 : if (aNewItem.IsEmpty()) {
180 0 : aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
181 0 : return;
182 : }
183 0 : if (aIndex >= InternalList().Length()) {
184 0 : aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
185 0 : return;
186 : }
187 :
188 0 : aRetval = InternalList()[aIndex];
189 0 : AutoChangeStringListNotifier notifier(this);
190 0 : InternalList().ReplaceItem(aIndex, aNewItem);
191 : }
192 :
193 : void
194 0 : DOMSVGStringList::RemoveItem(uint32_t aIndex, nsAString& aRetval,
195 : ErrorResult& aRv)
196 : {
197 0 : if (aIndex >= InternalList().Length()) {
198 0 : aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
199 0 : return;
200 : }
201 :
202 0 : AutoChangeStringListNotifier notifier(this);
203 0 : InternalList().RemoveItem(aIndex);
204 : }
205 :
206 : void
207 0 : DOMSVGStringList::AppendItem(const nsAString& aNewItem, nsAString& aRetval,
208 : ErrorResult& aRv)
209 : {
210 0 : InsertItemBefore(aNewItem, InternalList().Length(), aRetval, aRv);
211 0 : }
212 :
213 : SVGStringList &
214 0 : DOMSVGStringList::InternalList() const
215 : {
216 0 : if (mIsConditionalProcessingAttribute) {
217 0 : nsCOMPtr<dom::SVGTests> tests = do_QueryObject(mElement.get());
218 0 : return tests->mStringListAttributes[mAttrEnum];
219 : }
220 0 : return mElement->GetStringListInfo().mStringLists[mAttrEnum];
221 : }
222 :
223 : } // namespace mozilla
|