tor-browser

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

HTMLOptionsCollection.cpp (6195B)


      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 "mozilla/dom/HTMLOptionsCollection.h"
      8 
      9 #include "mozilla/dom/HTMLOptionElement.h"
     10 #include "mozilla/dom/HTMLOptionsCollectionBinding.h"
     11 #include "mozilla/dom/HTMLSelectElement.h"
     12 
     13 namespace mozilla::dom {
     14 
     15 HTMLOptionsCollection::HTMLOptionsCollection(HTMLSelectElement* aSelect)
     16    : mSelect(aSelect) {}
     17 
     18 nsresult HTMLOptionsCollection::GetOptionIndex(Element* aOption,
     19                                               int32_t aStartIndex,
     20                                               bool aForward, int32_t* aIndex) {
     21  // NOTE: aIndex shouldn't be set if the returned value isn't NS_OK.
     22 
     23  int32_t index;
     24 
     25  // Make the common case fast
     26  if (aStartIndex == 0 && aForward) {
     27    index = mElements.IndexOf(aOption);
     28    if (index == -1) {
     29      return NS_ERROR_FAILURE;
     30    }
     31 
     32    *aIndex = index;
     33    return NS_OK;
     34  }
     35 
     36  int32_t high = mElements.Length();
     37  int32_t step = aForward ? 1 : -1;
     38 
     39  for (index = aStartIndex; index < high && index > -1; index += step) {
     40    if (mElements[index] == aOption) {
     41      *aIndex = index;
     42      return NS_OK;
     43    }
     44  }
     45 
     46  return NS_ERROR_FAILURE;
     47 }
     48 
     49 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLOptionsCollection, mElements, mSelect)
     50 
     51 // nsISupports
     52 
     53 // QueryInterface implementation for HTMLOptionsCollection
     54 NS_INTERFACE_TABLE_HEAD(HTMLOptionsCollection)
     55  NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
     56  NS_INTERFACE_TABLE(HTMLOptionsCollection, nsIHTMLCollection)
     57  NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(HTMLOptionsCollection)
     58 NS_INTERFACE_MAP_END
     59 
     60 NS_IMPL_CYCLE_COLLECTING_ADDREF(HTMLOptionsCollection)
     61 NS_IMPL_CYCLE_COLLECTING_RELEASE(HTMLOptionsCollection)
     62 
     63 JSObject* HTMLOptionsCollection::WrapObject(JSContext* aCx,
     64                                            JS::Handle<JSObject*> aGivenProto) {
     65  return HTMLOptionsCollection_Binding::Wrap(aCx, this, aGivenProto);
     66 }
     67 
     68 uint32_t HTMLOptionsCollection::Length() { return mElements.Length(); }
     69 
     70 void HTMLOptionsCollection::SetLength(uint32_t aLength, ErrorResult& aError) {
     71  mSelect->SetLength(aLength, aError);
     72 }
     73 
     74 void HTMLOptionsCollection::IndexedSetter(uint32_t aIndex,
     75                                          HTMLOptionElement* aOption,
     76                                          ErrorResult& aError) {
     77  // if the new option is null, just remove this option.  Note that it's safe
     78  // to pass a too-large aIndex in here.
     79  if (!aOption) {
     80    mSelect->Remove(aIndex);
     81 
     82    // We're done.
     83    return;
     84  }
     85 
     86  // Now we're going to be setting an option in our collection
     87  if (aIndex > mElements.Length()) {
     88    // Fill our array with blank options up to (but not including, since we're
     89    // about to change it) aIndex, for compat with other browsers.
     90    SetLength(aIndex, aError);
     91    if (NS_WARN_IF(aError.Failed())) {
     92      return;
     93    }
     94  }
     95 
     96  NS_ASSERTION(aIndex <= mElements.Length(), "SetLength lied");
     97 
     98  if (aIndex == mElements.Length()) {
     99    mSelect->AppendChild(*aOption, aError);
    100    return;
    101  }
    102 
    103  // Find the option they're talking about and replace it
    104  // hold a strong reference to follow COM rules.
    105  RefPtr<HTMLOptionElement> refChild = ItemAsOption(aIndex);
    106  if (!refChild) {
    107    aError.Throw(NS_ERROR_UNEXPECTED);
    108    return;
    109  }
    110 
    111  nsCOMPtr<nsINode> parent = refChild->GetParent();
    112  if (!parent) {
    113    return;
    114  }
    115 
    116  parent->ReplaceChild(*aOption, *refChild, aError);
    117 }
    118 
    119 int32_t HTMLOptionsCollection::SelectedIndex() {
    120  return mSelect->SelectedIndex();
    121 }
    122 
    123 void HTMLOptionsCollection::SetSelectedIndex(int32_t aSelectedIndex) {
    124  mSelect->SetSelectedIndex(aSelectedIndex);
    125 }
    126 
    127 Element* HTMLOptionsCollection::GetElementAt(uint32_t aIndex) {
    128  return ItemAsOption(aIndex);
    129 }
    130 
    131 HTMLOptionElement* HTMLOptionsCollection::NamedGetter(const nsAString& aName,
    132                                                      bool& aFound) {
    133  if (aName.IsEmpty()) {
    134    aFound = false;
    135    return nullptr;
    136  }
    137  uint32_t count = mElements.Length();
    138  for (uint32_t i = 0; i < count; i++) {
    139    HTMLOptionElement* content = mElements.ElementAt(i);
    140    if (content && (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
    141                                         aName, eCaseMatters) ||
    142                    content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id,
    143                                         aName, eCaseMatters))) {
    144      aFound = true;
    145      return content;
    146    }
    147  }
    148 
    149  aFound = false;
    150  return nullptr;
    151 }
    152 
    153 nsINode* HTMLOptionsCollection::GetParentObject() { return mSelect; }
    154 
    155 DocGroup* HTMLOptionsCollection::GetDocGroup() const {
    156  return mSelect ? mSelect->GetDocGroup() : nullptr;
    157 }
    158 
    159 void HTMLOptionsCollection::GetSupportedNames(nsTArray<nsString>& aNames) {
    160  AutoTArray<nsAtom*, 8> atoms;
    161  for (uint32_t i = 0; i < mElements.Length(); ++i) {
    162    HTMLOptionElement* content = mElements.ElementAt(i);
    163    if (content) {
    164      // Note: HasName means the names is exposed on the document,
    165      // which is false for options, so we don't check it here.
    166      const nsAttrValue* val = content->GetParsedAttr(nsGkAtoms::name);
    167      if (val && val->Type() == nsAttrValue::eAtom) {
    168        nsAtom* name = val->GetAtomValue();
    169        if (!atoms.Contains(name)) {
    170          atoms.AppendElement(name);
    171        }
    172      }
    173      if (content->HasID()) {
    174        nsAtom* id = content->GetID();
    175        if (!atoms.Contains(id)) {
    176          atoms.AppendElement(id);
    177        }
    178      }
    179    }
    180  }
    181 
    182  uint32_t atomsLen = atoms.Length();
    183  nsString* names = aNames.AppendElements(atomsLen);
    184  for (uint32_t i = 0; i < atomsLen; ++i) {
    185    atoms[i]->ToString(names[i]);
    186  }
    187 }
    188 
    189 void HTMLOptionsCollection::Add(const HTMLOptionOrOptGroupElement& aElement,
    190                                const Nullable<HTMLElementOrLong>& aBefore,
    191                                ErrorResult& aError) {
    192  mSelect->Add(aElement, aBefore, aError);
    193 }
    194 
    195 void HTMLOptionsCollection::Remove(int32_t aIndex) { mSelect->Remove(aIndex); }
    196 
    197 }  // namespace mozilla::dom