tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

DOMSVGStringList.cpp (6989B)


      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 <algorithm>
     10 
     11 #include "SVGAttrTearoffTable.h"
     12 #include "mozAutoDocUpdate.h"
     13 #include "mozilla/dom/SVGStringListBinding.h"
     14 #include "mozilla/dom/SVGTests.h"
     15 #include "nsCOMPtr.h"
     16 #include "nsError.h"
     17 #include "nsQueryObject.h"
     18 
     19 // See the architecture comment in this file's header.
     20 
     21 namespace mozilla::dom {
     22 
     23 static inline SVGAttrTearoffTable<SVGStringList, DOMSVGStringList>&
     24 SVGStringListTearoffTable() {
     25  static SVGAttrTearoffTable<SVGStringList, DOMSVGStringList>
     26      sSVGStringListTearoffTable;
     27  return sSVGStringListTearoffTable;
     28 }
     29 
     30 NS_IMPL_CYCLE_COLLECTION_CLASS(DOMSVGStringList)
     31 
     32 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMSVGStringList)
     33  // No unlinking of mElement, we'd need to null out the value pointer (the
     34  // object it points to is held by the element) and null-check it everywhere.
     35  tmp->RemoveFromTearoffTable();
     36  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
     37 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
     38 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMSVGStringList)
     39  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement)
     40 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
     41 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMSVGStringList)
     42  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
     43 NS_IMPL_CYCLE_COLLECTION_TRACE_END
     44 
     45 NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMSVGStringList)
     46 NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMSVGStringList)
     47 
     48 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMSVGStringList)
     49  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     50  NS_INTERFACE_MAP_ENTRY(nsISupports)
     51 NS_INTERFACE_MAP_END
     52 
     53 //----------------------------------------------------------------------
     54 // Helper class: AutoChangeStringListNotifier
     55 // Stack-based helper class to pair calls to WillChangeStringListList and
     56 // DidChangeStringListList.
     57 class MOZ_RAII AutoChangeStringListNotifier : public mozAutoDocUpdate {
     58 public:
     59  explicit AutoChangeStringListNotifier(DOMSVGStringList* aStringList)
     60      : mozAutoDocUpdate(aStringList->mElement->GetComposedDoc(), true),
     61        mStringList(aStringList) {
     62    MOZ_ASSERT(mStringList, "Expecting non-null stringList");
     63    mStringList->mElement->WillChangeStringList(
     64        mStringList->mIsConditionalProcessingAttribute, mStringList->mAttrEnum,
     65        *this);
     66  }
     67 
     68  ~AutoChangeStringListNotifier() {
     69    mStringList->mElement->DidChangeStringList(
     70        mStringList->mIsConditionalProcessingAttribute, mStringList->mAttrEnum,
     71        *this);
     72  }
     73 
     74 private:
     75  DOMSVGStringList* const mStringList;
     76 };
     77 
     78 /* static */
     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);
     84  if (!wrapper) {
     85    wrapper = new DOMSVGStringList(aElement, aIsConditionalProcessingAttribute,
     86                                   aAttrEnum);
     87    SVGStringListTearoffTable().AddTearoff(aList, wrapper);
     88  }
     89  return wrapper.forget();
     90 }
     91 
     92 void DOMSVGStringList::RemoveFromTearoffTable() {
     93  // Script no longer has any references to us.
     94  if (mIsInTearoffTable) {
     95    SVGStringListTearoffTable().RemoveTearoff(&InternalList());
     96    mIsInTearoffTable = false;
     97  }
     98 }
     99 
    100 DOMSVGStringList::~DOMSVGStringList() { RemoveFromTearoffTable(); }
    101 
    102 /* virtual */
    103 JSObject* DOMSVGStringList::WrapObject(JSContext* aCx,
    104                                       JS::Handle<JSObject*> aGivenProto) {
    105  return SVGStringList_Binding::Wrap(aCx, this, aGivenProto);
    106 }
    107 
    108 // ----------------------------------------------------------------------------
    109 // SVGStringList implementation:
    110 
    111 uint32_t DOMSVGStringList::NumberOfItems() const {
    112  return InternalList().Length();
    113 }
    114 
    115 uint32_t DOMSVGStringList::Length() const { return NumberOfItems(); }
    116 
    117 void DOMSVGStringList::Clear() {
    118  if (InternalList().IsExplicitlySet()) {
    119    AutoChangeStringListNotifier notifier(this);
    120    InternalList().Clear();
    121  }
    122 }
    123 
    124 void DOMSVGStringList::Initialize(const nsAString& aNewItem, nsAString& aRetval,
    125                                  ErrorResult& aRv) {
    126  if (InternalList().IsExplicitlySet()) {
    127    InternalList().Clear();
    128  }
    129  InsertItemBefore(aNewItem, 0, aRetval, aRv);
    130 }
    131 
    132 void DOMSVGStringList::GetItem(uint32_t aIndex, nsAString& aRetval,
    133                               ErrorResult& aRv) {
    134  bool found;
    135  IndexedGetter(aIndex, found, aRetval);
    136  if (!found) {
    137    aRv.ThrowIndexSizeError("Index out of range");
    138  }
    139 }
    140 
    141 void DOMSVGStringList::IndexedGetter(uint32_t aIndex, bool& aFound,
    142                                     nsAString& aRetval) {
    143  aFound = aIndex < InternalList().Length();
    144  if (aFound) {
    145    aRetval = InternalList()[aIndex];
    146  }
    147 }
    148 
    149 void DOMSVGStringList::InsertItemBefore(const nsAString& aNewItem,
    150                                        uint32_t aIndex, nsAString& aRetval,
    151                                        ErrorResult& aRv) {
    152  if (aNewItem.IsEmpty()) {
    153    aRv.ThrowSyntaxError("Cannot insert empty string");
    154    return;
    155  }
    156  aIndex = std::min(aIndex, InternalList().Length());
    157 
    158  // Ensure we have enough memory so we can avoid complex error handling below:
    159  if (!InternalList().SetCapacity(InternalList().Length() + 1)) {
    160    aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    161    return;
    162  }
    163 
    164  AutoChangeStringListNotifier notifier(this);
    165  InternalList().InsertItem(aIndex, aNewItem);
    166  aRetval = aNewItem;
    167 }
    168 
    169 void DOMSVGStringList::ReplaceItem(const nsAString& aNewItem, uint32_t aIndex,
    170                                   nsAString& aRetval, ErrorResult& aRv) {
    171  if (aNewItem.IsEmpty()) {
    172    aRv.ThrowSyntaxError("Cannot replace with empty string");
    173    return;
    174  }
    175  if (aIndex >= InternalList().Length()) {
    176    aRv.ThrowIndexSizeError("Index out of range");
    177    return;
    178  }
    179 
    180  aRetval = InternalList()[aIndex];
    181  AutoChangeStringListNotifier notifier(this);
    182  InternalList().ReplaceItem(aIndex, aNewItem);
    183 }
    184 
    185 void DOMSVGStringList::RemoveItem(uint32_t aIndex, nsAString& aRetval,
    186                                  ErrorResult& aRv) {
    187  if (aIndex >= InternalList().Length()) {
    188    aRv.ThrowIndexSizeError("Index out of range");
    189    return;
    190  }
    191 
    192  AutoChangeStringListNotifier notifier(this);
    193  InternalList().RemoveItem(aIndex);
    194 }
    195 
    196 void DOMSVGStringList::AppendItem(const nsAString& aNewItem, nsAString& aRetval,
    197                                  ErrorResult& aRv) {
    198  InsertItemBefore(aNewItem, InternalList().Length(), aRetval, aRv);
    199 }
    200 
    201 SVGStringList& DOMSVGStringList::InternalList() const {
    202  if (mIsConditionalProcessingAttribute) {
    203    nsCOMPtr<dom::SVGTests> tests = do_QueryObject(mElement);
    204    return tests->mStringListAttributes[mAttrEnum];
    205  }
    206  return mElement->GetStringListInfo().mValues[mAttrEnum];
    207 }
    208 
    209 }  // namespace mozilla::dom