tor-browser

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

SVGAnimatedPointList.cpp (6704B)


      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 "SVGAnimatedPointList.h"
      8 
      9 #include <utility>
     10 
     11 #include "DOMSVGPointList.h"
     12 #include "SVGPointListSMILType.h"
     13 #include "mozilla/SMILValue.h"
     14 #include "mozilla/dom/SVGElement.h"
     15 
     16 using namespace mozilla::dom;
     17 
     18 // See the comments in this file's header!
     19 
     20 namespace mozilla {
     21 
     22 nsresult SVGAnimatedPointList::SetBaseValueString(const nsAString& aValue) {
     23  SVGPointList newBaseValue;
     24 
     25  // The spec says that the point data is parsed and accepted up to the first
     26  // error encountered, so we don't return early if an error occurs. However,
     27  // we do want to throw any error code from setAttribute if there's a problem.
     28 
     29  nsresult rv = newBaseValue.SetValueFromString(aValue);
     30 
     31  // We must send these notifications *before* changing mBaseVal! Our baseVal's
     32  // DOM wrapper list may have to remove DOM items from itself, and any removed
     33  // DOM items need to copy their internal counterpart's values *before* we
     34  // change them. See the comments in
     35  // DOMSVGPointList::InternalListWillChangeTo().
     36 
     37  DOMSVGPointList* baseValWrapper =
     38      DOMSVGPointList::GetDOMWrapperIfExists(GetBaseValKey());
     39  if (baseValWrapper) {
     40    baseValWrapper->InternalListWillChangeTo(newBaseValue);
     41  }
     42 
     43  DOMSVGPointList* animValWrapper = nullptr;
     44  if (!IsAnimating()) {  // DOM anim val wraps our base val too!
     45    animValWrapper = DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
     46    if (animValWrapper) {
     47      animValWrapper->InternalListWillChangeTo(newBaseValue);
     48    }
     49  }
     50 
     51  // Only now may we modify mBaseVal!
     52 
     53  // We don't need to call DidChange* here - we're only called by
     54  // SVGElement::ParseAttribute under Element::SetAttr,
     55  // which takes care of notifying.
     56 
     57  mBaseVal.SwapWith(newBaseValue);
     58  return rv;
     59 }
     60 
     61 void SVGAnimatedPointList::ClearBaseValue() {
     62  // We must send these notifications *before* changing mBaseVal! (See above.)
     63 
     64  DOMSVGPointList* baseValWrapper =
     65      DOMSVGPointList::GetDOMWrapperIfExists(GetBaseValKey());
     66  if (baseValWrapper) {
     67    baseValWrapper->InternalListWillChangeTo(SVGPointList());
     68  }
     69 
     70  if (!IsAnimating()) {  // DOM anim val wraps our base val too!
     71    DOMSVGPointList* animValWrapper =
     72        DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
     73    if (animValWrapper) {
     74      animValWrapper->InternalListWillChangeTo(SVGPointList());
     75    }
     76  }
     77 
     78  mBaseVal.Clear();
     79  // Caller notifies
     80 }
     81 
     82 nsresult SVGAnimatedPointList::SetAnimValue(const SVGPointList& aNewAnimValue,
     83                                            SVGElement* aElement) {
     84  // Note that a new animation may totally change the number of items in the
     85  // animVal list, either replacing what was essentially a mirror of the
     86  // baseVal list, or else replacing and overriding an existing animation.
     87  // It is not possible for us to reliably distinguish between calls to this
     88  // method that are setting a new sample for an existing animation (in which
     89  // case our list length isn't changing and we wouldn't need to notify our DOM
     90  // wrapper to keep its length in sync), and calls to this method that are
     91  // setting the first sample of a new animation that will override the base
     92  // value/an existing animation (in which case our length may be changing and
     93  // our DOM wrapper may need to be notified). Happily though, it's cheap to
     94  // just blindly notify our animVal's DOM wrapper of our new value each time
     95  // this method is called, so that's what we do.
     96 
     97  // We must send this notification *before* changing mAnimVal! (See above.)
     98 
     99  DOMSVGPointList* domWrapper =
    100      DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
    101  if (domWrapper) {
    102    domWrapper->InternalListWillChangeTo(aNewAnimValue);
    103  }
    104  if (!mAnimVal) {
    105    mAnimVal = MakeUnique<SVGPointList>();
    106  }
    107  nsresult rv = mAnimVal->CopyFrom(aNewAnimValue);
    108  if (NS_FAILED(rv)) {
    109    // OOM. We clear the animation and, importantly, ClearAnimValue() ensures
    110    // that mAnimVal's DOM wrapper (if any) is kept in sync!
    111    ClearAnimValue(aElement);
    112    return rv;
    113  }
    114  aElement->DidAnimatePointList();
    115  return NS_OK;
    116 }
    117 
    118 void SVGAnimatedPointList::ClearAnimValue(SVGElement* aElement) {
    119  // We must send these notifications *before* changing mAnimVal! (See above.)
    120 
    121  DOMSVGPointList* domWrapper =
    122      DOMSVGPointList::GetDOMWrapperIfExists(GetAnimValKey());
    123  if (domWrapper) {
    124    // When all animation ends, animVal simply mirrors baseVal, which may have
    125    // a different number of items to the last active animated value.
    126    //
    127    domWrapper->InternalListWillChangeTo(mBaseVal);
    128  }
    129  mAnimVal = nullptr;
    130  aElement->DidAnimatePointList();
    131 }
    132 
    133 UniquePtr<SMILAttr> SVGAnimatedPointList::ToSMILAttr(SVGElement* aElement) {
    134  return MakeUnique<SMILAnimatedPointList>(this, aElement);
    135 }
    136 
    137 nsresult SVGAnimatedPointList::SMILAnimatedPointList::ValueFromString(
    138    const nsAString& aStr, const dom::SVGAnimationElement* /*aSrcElement*/,
    139    SMILValue& aValue, bool& aPreventCachingOfSandwich) const {
    140  SMILValue val(&SVGPointListSMILType::sSingleton);
    141  SVGPointListAndInfo* list = static_cast<SVGPointListAndInfo*>(val.mU.mPtr);
    142  nsresult rv = list->SetValueFromString(aStr);
    143  if (NS_SUCCEEDED(rv)) {
    144    list->SetInfo(mElement);
    145    aValue = std::move(val);
    146  }
    147  return rv;
    148 }
    149 
    150 SMILValue SVGAnimatedPointList::SMILAnimatedPointList::GetBaseValue() const {
    151  // To benefit from Return Value Optimization and avoid copy constructor calls
    152  // due to our use of return-by-value, we must return the exact same object
    153  // from ALL return points. This function must only return THIS variable:
    154  SMILValue val;
    155 
    156  SMILValue tmp(&SVGPointListSMILType::sSingleton);
    157  auto* list = static_cast<SVGPointListAndInfo*>(tmp.mU.mPtr);
    158  nsresult rv = list->CopyFrom(mVal->mBaseVal);
    159  if (NS_SUCCEEDED(rv)) {
    160    list->SetInfo(mElement);
    161    std::swap(val, tmp);
    162  }
    163  return val;
    164 }
    165 
    166 nsresult SVGAnimatedPointList::SMILAnimatedPointList::SetAnimValue(
    167    const SMILValue& aValue) {
    168  NS_ASSERTION(aValue.mType == &SVGPointListSMILType::sSingleton,
    169               "Unexpected type to assign animated value");
    170  if (aValue.mType == &SVGPointListSMILType::sSingleton) {
    171    mVal->SetAnimValue(*static_cast<SVGPointListAndInfo*>(aValue.mU.mPtr),
    172                       mElement);
    173  }
    174  return NS_OK;
    175 }
    176 
    177 void SVGAnimatedPointList::SMILAnimatedPointList::ClearAnimValue() {
    178  if (mVal->mAnimVal) {
    179    mVal->ClearAnimValue(mElement);
    180  }
    181 }
    182 
    183 }  // namespace mozilla