LCOV - code coverage report
Current view: top level - dom/html - nsDOMStringMap.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 114 0.9 %
Date: 2017-07-14 16:53:18 Functions: 2 20 10.0 %
Legend: Lines: hit not hit

          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 "nsDOMStringMap.h"
       8             : 
       9             : #include "jsapi.h"
      10             : #include "nsError.h"
      11             : #include "nsGenericHTMLElement.h"
      12             : #include "nsContentUtils.h"
      13             : #include "mozilla/dom/DOMStringMapBinding.h"
      14             : #include "nsIDOMMutationEvent.h"
      15             : 
      16             : using namespace mozilla;
      17             : using namespace mozilla::dom;
      18             : 
      19             : NS_IMPL_CYCLE_COLLECTION_CLASS(nsDOMStringMap)
      20             : 
      21           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMStringMap)
      22           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement)
      23           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      24             : 
      25           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMStringMap)
      26           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
      27             :   // Check that mElement exists in case the unlink code is run more than once.
      28           0 :   if (tmp->mElement) {
      29             :     // Call back to element to null out weak reference to this object.
      30           0 :     tmp->mElement->ClearDataset();
      31           0 :     tmp->mElement->RemoveMutationObserver(tmp);
      32           0 :     tmp->mElement = nullptr;
      33             :   }
      34           0 :   tmp->mExpandoAndGeneration.OwnerUnlinked();
      35           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      36             : 
      37           0 : NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsDOMStringMap)
      38             : 
      39           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStringMap)
      40           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      41           0 :   NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
      42           0 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      43           0 : NS_INTERFACE_MAP_END
      44             : 
      45           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsDOMStringMap)
      46           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMStringMap)
      47             : 
      48           0 : nsDOMStringMap::nsDOMStringMap(Element* aElement)
      49             :   : mElement(aElement),
      50           0 :     mRemovingProp(false)
      51             : {
      52           0 :   mElement->AddMutationObserver(this);
      53           0 : }
      54             : 
      55           0 : nsDOMStringMap::~nsDOMStringMap()
      56             : {
      57             :   // Check if element still exists, may have been unlinked by cycle collector.
      58           0 :   if (mElement) {
      59             :     // Call back to element to null out weak reference to this object.
      60           0 :     mElement->ClearDataset();
      61           0 :     mElement->RemoveMutationObserver(this);
      62             :   }
      63           0 : }
      64             : 
      65             : /* virtual */
      66             : JSObject*
      67           0 : nsDOMStringMap::WrapObject(JSContext *cx, JS::Handle<JSObject*> aGivenProto)
      68             : {
      69           0 :   return DOMStringMapBinding::Wrap(cx, this, aGivenProto);
      70             : }
      71             : 
      72             : void
      73           0 : nsDOMStringMap::NamedGetter(const nsAString& aProp, bool& found,
      74             :                             DOMString& aResult) const
      75             : {
      76           0 :   nsAutoString attr;
      77             : 
      78           0 :   if (!DataPropToAttr(aProp, attr)) {
      79           0 :     found = false;
      80           0 :     return;
      81             :   }
      82             : 
      83           0 :   found = mElement->GetAttr(attr, aResult);
      84             : }
      85             : 
      86             : void
      87           0 : nsDOMStringMap::NamedSetter(const nsAString& aProp,
      88             :                             const nsAString& aValue,
      89             :                             ErrorResult& rv)
      90             : {
      91           0 :   nsAutoString attr;
      92           0 :   if (!DataPropToAttr(aProp, attr)) {
      93           0 :     rv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
      94           0 :     return;
      95             :   }
      96             : 
      97           0 :   nsresult res = nsContentUtils::CheckQName(attr, false);
      98           0 :   if (NS_FAILED(res)) {
      99           0 :     rv.Throw(res);
     100           0 :     return;
     101             :   }
     102             : 
     103           0 :   nsCOMPtr<nsIAtom> attrAtom = NS_Atomize(attr);
     104           0 :   MOZ_ASSERT(attrAtom, "Should be infallible");
     105             : 
     106           0 :   res = mElement->SetAttr(kNameSpaceID_None, attrAtom, aValue, true);
     107           0 :   if (NS_FAILED(res)) {
     108           0 :     rv.Throw(res);
     109             :   }
     110             : }
     111             : 
     112             : void
     113           0 : nsDOMStringMap::NamedDeleter(const nsAString& aProp, bool& found)
     114             : {
     115             :   // Currently removing property, attribute is already removed.
     116           0 :   if (mRemovingProp) {
     117           0 :     found = false;
     118           0 :     return;
     119             :   }
     120             : 
     121           0 :   nsAutoString attr;
     122           0 :   if (!DataPropToAttr(aProp, attr)) {
     123           0 :     found = false;
     124           0 :     return;
     125             :   }
     126             : 
     127           0 :   nsCOMPtr<nsIAtom> attrAtom = NS_Atomize(attr);
     128           0 :   MOZ_ASSERT(attrAtom, "Should be infallible");
     129             : 
     130           0 :   found = mElement->HasAttr(kNameSpaceID_None, attrAtom);
     131             : 
     132           0 :   if (found) {
     133           0 :     mRemovingProp = true;
     134           0 :     mElement->UnsetAttr(kNameSpaceID_None, attrAtom, true);
     135           0 :     mRemovingProp = false;
     136             :   }
     137             : }
     138             : 
     139             : void
     140           0 : nsDOMStringMap::GetSupportedNames(nsTArray<nsString>& aNames)
     141             : {
     142           0 :   uint32_t attrCount = mElement->GetAttrCount();
     143             : 
     144             :   // Iterate through all the attributes and add property
     145             :   // names corresponding to data attributes to return array.
     146           0 :   for (uint32_t i = 0; i < attrCount; ++i) {
     147           0 :     const nsAttrName* attrName = mElement->GetAttrNameAt(i);
     148             :     // Skip the ones that are not in the null namespace
     149           0 :     if (attrName->NamespaceID() != kNameSpaceID_None) {
     150           0 :       continue;
     151             :     }
     152             : 
     153           0 :     nsAutoString prop;
     154           0 :     if (!AttrToDataProp(nsDependentAtomString(attrName->LocalName()),
     155             :                         prop)) {
     156           0 :       continue;
     157             :     }
     158             : 
     159           0 :     aNames.AppendElement(prop);
     160             :   }
     161           0 : }
     162             : 
     163             : /**
     164             :  * Converts a dataset property name to the corresponding data attribute name.
     165             :  * (ex. aBigFish to data-a-big-fish).
     166             :  */
     167           0 : bool nsDOMStringMap::DataPropToAttr(const nsAString& aProp,
     168             :                                     nsAutoString& aResult)
     169             : {
     170             :   // aResult is an autostring, so don't worry about setting its capacity:
     171             :   // SetCapacity is slow even when it's a no-op and we already have enough
     172             :   // storage there for most cases, probably.
     173           0 :   aResult.AppendLiteral("data-");
     174             : 
     175             :   // Iterate property by character to form attribute name.
     176             :   // Return syntax error if there is a sequence of "-" followed by a character
     177             :   // in the range "a" to "z".
     178             :   // Replace capital characters with "-" followed by lower case character.
     179             :   // Otherwise, simply append character to attribute name.
     180           0 :   const char16_t* start = aProp.BeginReading();
     181           0 :   const char16_t* end = aProp.EndReading();
     182           0 :   const char16_t* cur = start;
     183           0 :   for (; cur < end; ++cur) {
     184           0 :     const char16_t* next = cur + 1;
     185           0 :     if (char16_t('-') == *cur && next < end &&
     186           0 :         char16_t('a') <= *next && *next <= char16_t('z')) {
     187             :       // Syntax error if character following "-" is in range "a" to "z".
     188           0 :       return false;
     189             :     }
     190             : 
     191           0 :     if (char16_t('A') <= *cur && *cur <= char16_t('Z')) {
     192             :       // Append the characters in the range [start, cur)
     193           0 :       aResult.Append(start, cur - start);
     194             :       // Uncamel-case characters in the range of "A" to "Z".
     195           0 :       aResult.Append(char16_t('-'));
     196           0 :       aResult.Append(*cur - 'A' + 'a');
     197           0 :       start = next; // We've already appended the thing at *cur
     198             :     }
     199             :   }
     200             : 
     201           0 :   aResult.Append(start, cur - start);
     202             : 
     203           0 :   return true;
     204             : }
     205             : 
     206             : /**
     207             :  * Converts a data attribute name to the corresponding dataset property name.
     208             :  * (ex. data-a-big-fish to aBigFish).
     209             :  */
     210           0 : bool nsDOMStringMap::AttrToDataProp(const nsAString& aAttr,
     211             :                                     nsAutoString& aResult)
     212             : {
     213             :   // If the attribute name does not begin with "data-" then it can not be
     214             :   // a data attribute.
     215           0 :   if (!StringBeginsWith(aAttr, NS_LITERAL_STRING("data-"))) {
     216           0 :     return false;
     217             :   }
     218             : 
     219             :   // Start reading attribute from first character after "data-".
     220           0 :   const char16_t* cur = aAttr.BeginReading() + 5;
     221           0 :   const char16_t* end = aAttr.EndReading();
     222             : 
     223             :   // Don't try to mess with aResult's capacity: the probably-no-op SetCapacity()
     224             :   // call is not that fast.
     225             : 
     226             :   // Iterate through attrName by character to form property name.
     227             :   // If there is a sequence of "-" followed by a character in the range "a" to
     228             :   // "z" then replace with upper case letter.
     229             :   // Otherwise append character to property name.
     230           0 :   for (; cur < end; ++cur) {
     231           0 :     const char16_t* next = cur + 1;
     232           0 :     if (char16_t('-') == *cur && next < end &&
     233           0 :         char16_t('a') <= *next && *next <= char16_t('z')) {
     234             :       // Upper case the lower case letters that follow a "-".
     235           0 :       aResult.Append(*next - 'a' + 'A');
     236             :       // Consume character to account for "-" character.
     237           0 :       ++cur;
     238             :     } else {
     239             :       // Simply append character if camel case is not necessary.
     240           0 :       aResult.Append(*cur);
     241             :     }
     242             :   }
     243             : 
     244           0 :   return true;
     245             : }
     246             : 
     247             : void
     248           0 : nsDOMStringMap::AttributeChanged(nsIDocument *aDocument, Element* aElement,
     249             :                                  int32_t aNameSpaceID, nsIAtom* aAttribute,
     250             :                                  int32_t aModType,
     251             :                                  const nsAttrValue* aOldValue)
     252             : {
     253           0 :   if ((aModType == nsIDOMMutationEvent::ADDITION ||
     254           0 :        aModType == nsIDOMMutationEvent::REMOVAL) &&
     255           0 :       aNameSpaceID == kNameSpaceID_None &&
     256           0 :       StringBeginsWith(nsDependentAtomString(aAttribute),
     257           0 :                        NS_LITERAL_STRING("data-"))) {
     258           0 :     ++mExpandoAndGeneration.generation;
     259             :   }
     260           9 : }

Generated by: LCOV version 1.13