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/. */
7 #include "DOMSVGStringList.h"
9 #include "mozAutoDocUpdate.h"
10 #include "mozilla/dom/SVGStringListBinding.h"
11 #include "mozilla/dom/SVGTests.h"
14 #include "nsQueryObject.h"
15 #include "SVGAttrTearoffTable.h"
18 // See the architecture comment in this file's header.
20 namespace mozilla::dom
{
22 static inline SVGAttrTearoffTable
<SVGStringList
, DOMSVGStringList
>&
23 SVGStringListTearoffTable() {
24 static SVGAttrTearoffTable
<SVGStringList
, DOMSVGStringList
>
25 sSVGStringListTearoffTable
;
26 return sSVGStringListTearoffTable
;
29 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGStringList
)
31 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGStringList
)
32 // No unlinking of mElement, we'd need to null out the value pointer (the
33 // object it points to is held by the element) and null-check it everywhere.
34 tmp
->RemoveFromTearoffTable();
35 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
36 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
37 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGStringList
)
38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement
)
39 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
40 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGStringList
)
41 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
42 NS_IMPL_CYCLE_COLLECTION_TRACE_END
44 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGStringList
)
45 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGStringList
)
47 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGStringList
)
48 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
49 NS_INTERFACE_MAP_ENTRY(nsISupports
)
52 //----------------------------------------------------------------------
53 // Helper class: AutoChangeStringListNotifier
54 // Stack-based helper class to pair calls to WillChangeStringListList and
55 // DidChangeStringListList.
56 class MOZ_RAII AutoChangeStringListNotifier
: public mozAutoDocUpdate
{
58 explicit AutoChangeStringListNotifier(DOMSVGStringList
* aStringList
)
59 : mozAutoDocUpdate(aStringList
->mElement
->GetComposedDoc(), true),
60 mStringList(aStringList
) {
61 MOZ_ASSERT(mStringList
, "Expecting non-null stringList");
62 mEmptyOrOldValue
= mStringList
->mElement
->WillChangeStringList(
63 mStringList
->mIsConditionalProcessingAttribute
, mStringList
->mAttrEnum
,
67 ~AutoChangeStringListNotifier() {
68 mStringList
->mElement
->DidChangeStringList(
69 mStringList
->mIsConditionalProcessingAttribute
, mStringList
->mAttrEnum
,
70 mEmptyOrOldValue
, *this);
74 DOMSVGStringList
* const mStringList
;
75 nsAttrValue mEmptyOrOldValue
;
79 already_AddRefed
<DOMSVGStringList
> DOMSVGStringList::GetDOMWrapper(
80 SVGStringList
* aList
, SVGElement
* aElement
,
81 bool aIsConditionalProcessingAttribute
, uint8_t aAttrEnum
) {
82 RefPtr
<DOMSVGStringList
> wrapper
=
83 SVGStringListTearoffTable().GetTearoff(aList
);
85 wrapper
= new DOMSVGStringList(aElement
, aIsConditionalProcessingAttribute
,
87 SVGStringListTearoffTable().AddTearoff(aList
, wrapper
);
89 return wrapper
.forget();
92 void DOMSVGStringList::RemoveFromTearoffTable() {
93 // Script no longer has any references to us.
94 SVGStringListTearoffTable().RemoveTearoff(&InternalList());
97 DOMSVGStringList::~DOMSVGStringList() { RemoveFromTearoffTable(); }
100 JSObject
* DOMSVGStringList::WrapObject(JSContext
* aCx
,
101 JS::Handle
<JSObject
*> aGivenProto
) {
102 return SVGStringList_Binding::Wrap(aCx
, this, aGivenProto
);
105 // ----------------------------------------------------------------------------
106 // SVGStringList implementation:
108 uint32_t DOMSVGStringList::NumberOfItems() const {
109 return InternalList().Length();
112 uint32_t DOMSVGStringList::Length() const { return NumberOfItems(); }
114 void DOMSVGStringList::Clear() {
115 if (InternalList().IsExplicitlySet()) {
116 AutoChangeStringListNotifier
notifier(this);
117 InternalList().Clear();
121 void DOMSVGStringList::Initialize(const nsAString
& aNewItem
, nsAString
& aRetval
,
123 if (InternalList().IsExplicitlySet()) {
124 InternalList().Clear();
126 InsertItemBefore(aNewItem
, 0, aRetval
, aRv
);
129 void DOMSVGStringList::GetItem(uint32_t aIndex
, nsAString
& aRetval
,
132 IndexedGetter(aIndex
, found
, aRetval
);
134 aRv
.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR
);
138 void DOMSVGStringList::IndexedGetter(uint32_t aIndex
, bool& aFound
,
139 nsAString
& aRetval
) {
140 aFound
= aIndex
< InternalList().Length();
142 aRetval
= InternalList()[aIndex
];
146 void DOMSVGStringList::InsertItemBefore(const nsAString
& aNewItem
,
147 uint32_t aIndex
, nsAString
& aRetval
,
149 if (aNewItem
.IsEmpty()) {
150 aRv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
153 aIndex
= std::min(aIndex
, InternalList().Length());
155 // Ensure we have enough memory so we can avoid complex error handling below:
156 if (!InternalList().SetCapacity(InternalList().Length() + 1)) {
157 aRv
.Throw(NS_ERROR_OUT_OF_MEMORY
);
161 AutoChangeStringListNotifier
notifier(this);
162 InternalList().InsertItem(aIndex
, aNewItem
);
166 void DOMSVGStringList::ReplaceItem(const nsAString
& aNewItem
, uint32_t aIndex
,
167 nsAString
& aRetval
, ErrorResult
& aRv
) {
168 if (aNewItem
.IsEmpty()) {
169 aRv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
172 if (aIndex
>= InternalList().Length()) {
173 aRv
.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR
);
177 aRetval
= InternalList()[aIndex
];
178 AutoChangeStringListNotifier
notifier(this);
179 InternalList().ReplaceItem(aIndex
, aNewItem
);
182 void DOMSVGStringList::RemoveItem(uint32_t aIndex
, nsAString
& aRetval
,
184 if (aIndex
>= InternalList().Length()) {
185 aRv
.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR
);
189 AutoChangeStringListNotifier
notifier(this);
190 InternalList().RemoveItem(aIndex
);
193 void DOMSVGStringList::AppendItem(const nsAString
& aNewItem
, nsAString
& aRetval
,
195 InsertItemBefore(aNewItem
, InternalList().Length(), aRetval
, aRv
);
198 SVGStringList
& DOMSVGStringList::InternalList() const {
199 if (mIsConditionalProcessingAttribute
) {
200 nsCOMPtr
<dom::SVGTests
> tests
= do_QueryObject(mElement
);
201 return tests
->mStringListAttributes
[mAttrEnum
];
203 return mElement
->GetStringListInfo().mValues
[mAttrEnum
];
206 } // namespace mozilla::dom