tor-browser

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

SVGAnimatedNumberPair.cpp (7497B)


      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 "SVGAnimatedNumberPair.h"
      8 
      9 #include "SVGAttrTearoffTable.h"
     10 #include "SVGNumberPairSMILType.h"
     11 #include "mozilla/SMILValue.h"
     12 #include "mozilla/SVGContentUtils.h"
     13 #include "nsCharSeparatedTokenizer.h"
     14 #include "nsContentUtils.h"
     15 
     16 using namespace mozilla::dom;
     17 
     18 namespace mozilla {
     19 
     20 //----------------------------------------------------------------------
     21 // Helper class: AutoChangeNumberPairNotifier
     22 // Stack-based helper class to pair calls to WillChangeNumberPair and
     23 // DidChangeNumberPair.
     24 class MOZ_RAII AutoChangeNumberPairNotifier {
     25 public:
     26  AutoChangeNumberPairNotifier(SVGAnimatedNumberPair* aNumberPair,
     27                               SVGElement* aSVGElement, bool aDoSetAttr = true)
     28      : mNumberPair(aNumberPair),
     29        mSVGElement(aSVGElement),
     30        mDoSetAttr(aDoSetAttr) {
     31    MOZ_ASSERT(mNumberPair, "Expecting non-null numberPair");
     32    MOZ_ASSERT(mSVGElement, "Expecting non-null element");
     33 
     34    if (mDoSetAttr) {
     35      mSVGElement->WillChangeNumberPair(mNumberPair->mAttrEnum);
     36    }
     37  }
     38 
     39  ~AutoChangeNumberPairNotifier() {
     40    if (mDoSetAttr) {
     41      mSVGElement->DidChangeNumberPair(mNumberPair->mAttrEnum);
     42    }
     43    if (mNumberPair->mIsAnimated) {
     44      mSVGElement->AnimationNeedsResample();
     45    }
     46  }
     47 
     48 private:
     49  SVGAnimatedNumberPair* const mNumberPair;
     50  SVGElement* const mSVGElement;
     51  bool mDoSetAttr;
     52 };
     53 
     54 constinit static SVGAttrTearoffTable<SVGAnimatedNumberPair,
     55                                     SVGAnimatedNumberPair::DOMAnimatedNumber>
     56    sSVGFirstAnimatedNumberTearoffTable;
     57 constinit static SVGAttrTearoffTable<SVGAnimatedNumberPair,
     58                                     SVGAnimatedNumberPair::DOMAnimatedNumber>
     59    sSVGSecondAnimatedNumberTearoffTable;
     60 
     61 static nsresult ParseNumberOptionalNumber(const nsAString& aValue,
     62                                          float aValues[2]) {
     63  nsCharSeparatedTokenizerTemplate<nsContentUtils::IsHTMLWhitespace,
     64                                   nsTokenizerFlags::SeparatorOptional>
     65      tokenizer(aValue, ',');
     66  uint32_t i;
     67  for (i = 0; i < 2 && tokenizer.hasMoreTokens(); ++i) {
     68    if (!SVGContentUtils::ParseNumber(tokenizer.nextToken(), aValues[i])) {
     69      return NS_ERROR_DOM_SYNTAX_ERR;
     70    }
     71  }
     72  if (i == 1) {
     73    aValues[1] = aValues[0];
     74  }
     75 
     76  if (i == 0 ||                                  // Too few values.
     77      tokenizer.hasMoreTokens() ||               // Too many values.
     78      tokenizer.separatorAfterCurrentToken()) {  // Trailing comma.
     79    return NS_ERROR_DOM_SYNTAX_ERR;
     80  }
     81 
     82  return NS_OK;
     83 }
     84 
     85 nsresult SVGAnimatedNumberPair::SetBaseValueString(
     86    const nsAString& aValueAsString, SVGElement* aSVGElement) {
     87  float val[2];
     88 
     89  nsresult rv = ParseNumberOptionalNumber(aValueAsString, val);
     90  if (NS_FAILED(rv)) {
     91    return rv;
     92  }
     93 
     94  // We don't need to call Will/DidChange* here - we're only called by
     95  // SVGElement::ParseAttribute under Element::SetAttr,
     96  // which takes care of notifying.
     97  AutoChangeNumberPairNotifier notifier(this, aSVGElement, false);
     98 
     99  mBaseVal[0] = val[0];
    100  mBaseVal[1] = val[1];
    101  mIsBaseSet = true;
    102  if (!mIsAnimated) {
    103    mAnimVal[0] = mBaseVal[0];
    104    mAnimVal[1] = mBaseVal[1];
    105  }
    106 
    107  return NS_OK;
    108 }
    109 
    110 void SVGAnimatedNumberPair::GetBaseValueString(
    111    nsAString& aValueAsString) const {
    112  aValueAsString.Truncate();
    113  aValueAsString.AppendFloat(mBaseVal[0]);
    114  if (mBaseVal[0] != mBaseVal[1]) {
    115    aValueAsString.AppendLiteral(", ");
    116    aValueAsString.AppendFloat(mBaseVal[1]);
    117  }
    118 }
    119 
    120 void SVGAnimatedNumberPair::SetBaseValue(float aValue, PairIndex aPairIndex,
    121                                         SVGElement* aSVGElement) {
    122  uint32_t index = (aPairIndex == eFirst ? 0 : 1);
    123  if (mIsBaseSet && mBaseVal[index] == aValue) {
    124    return;
    125  }
    126 
    127  AutoChangeNumberPairNotifier notifier(this, aSVGElement);
    128 
    129  mBaseVal[index] = aValue;
    130  mIsBaseSet = true;
    131  if (!mIsAnimated) {
    132    mAnimVal[index] = aValue;
    133  }
    134 }
    135 
    136 void SVGAnimatedNumberPair::SetBaseValues(float aValue1, float aValue2,
    137                                          SVGElement* aSVGElement) {
    138  if (mIsBaseSet && mBaseVal[0] == aValue1 && mBaseVal[1] == aValue2) {
    139    return;
    140  }
    141 
    142  AutoChangeNumberPairNotifier notifier(this, aSVGElement);
    143 
    144  mBaseVal[0] = aValue1;
    145  mBaseVal[1] = aValue2;
    146  mIsBaseSet = true;
    147  if (!mIsAnimated) {
    148    mAnimVal[0] = aValue1;
    149    mAnimVal[1] = aValue2;
    150  }
    151 }
    152 
    153 void SVGAnimatedNumberPair::SetAnimValue(const float aValue[2],
    154                                         SVGElement* aSVGElement) {
    155  if (mIsAnimated && mAnimVal[0] == aValue[0] && mAnimVal[1] == aValue[1]) {
    156    return;
    157  }
    158  mAnimVal[0] = aValue[0];
    159  mAnimVal[1] = aValue[1];
    160  mIsAnimated = true;
    161  aSVGElement->DidAnimateNumberPair(mAttrEnum);
    162 }
    163 
    164 already_AddRefed<DOMSVGAnimatedNumber>
    165 SVGAnimatedNumberPair::ToDOMAnimatedNumber(PairIndex aIndex,
    166                                           SVGElement* aSVGElement) {
    167  RefPtr<DOMAnimatedNumber> domAnimatedNumber =
    168      aIndex == eFirst ? sSVGFirstAnimatedNumberTearoffTable.GetTearoff(this)
    169                       : sSVGSecondAnimatedNumberTearoffTable.GetTearoff(this);
    170  if (!domAnimatedNumber) {
    171    domAnimatedNumber = new DOMAnimatedNumber(this, aIndex, aSVGElement);
    172    if (aIndex == eFirst) {
    173      sSVGFirstAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
    174    } else {
    175      sSVGSecondAnimatedNumberTearoffTable.AddTearoff(this, domAnimatedNumber);
    176    }
    177  }
    178 
    179  return domAnimatedNumber.forget();
    180 }
    181 
    182 SVGAnimatedNumberPair::DOMAnimatedNumber::~DOMAnimatedNumber() {
    183  if (mIndex == eFirst) {
    184    sSVGFirstAnimatedNumberTearoffTable.RemoveTearoff(mVal);
    185  } else {
    186    sSVGSecondAnimatedNumberTearoffTable.RemoveTearoff(mVal);
    187  }
    188 }
    189 
    190 UniquePtr<SMILAttr> SVGAnimatedNumberPair::ToSMILAttr(SVGElement* aSVGElement) {
    191  return MakeUnique<SMILNumberPair>(this, aSVGElement);
    192 }
    193 
    194 nsresult SVGAnimatedNumberPair::SMILNumberPair::ValueFromString(
    195    const nsAString& aStr, const dom::SVGAnimationElement* /*aSrcElement*/,
    196    SMILValue& aValue, bool& aPreventCachingOfSandwich) const {
    197  float values[2];
    198 
    199  nsresult rv = ParseNumberOptionalNumber(aStr, values);
    200  if (NS_FAILED(rv)) {
    201    return rv;
    202  }
    203 
    204  SMILValue val(&SVGNumberPairSMILType::sSingleton);
    205  val.mU.mNumberPair[0] = values[0];
    206  val.mU.mNumberPair[1] = values[1];
    207  aValue = val;
    208 
    209  return NS_OK;
    210 }
    211 
    212 SMILValue SVGAnimatedNumberPair::SMILNumberPair::GetBaseValue() const {
    213  SMILValue val(&SVGNumberPairSMILType::sSingleton);
    214  val.mU.mNumberPair[0] = mVal->mBaseVal[0];
    215  val.mU.mNumberPair[1] = mVal->mBaseVal[1];
    216  return val;
    217 }
    218 
    219 void SVGAnimatedNumberPair::SMILNumberPair::ClearAnimValue() {
    220  if (mVal->mIsAnimated) {
    221    mVal->mIsAnimated = false;
    222    mVal->mAnimVal[0] = mVal->mBaseVal[0];
    223    mVal->mAnimVal[1] = mVal->mBaseVal[1];
    224    mSVGElement->DidAnimateNumberPair(mVal->mAttrEnum);
    225  }
    226 }
    227 
    228 nsresult SVGAnimatedNumberPair::SMILNumberPair::SetAnimValue(
    229    const SMILValue& aValue) {
    230  NS_ASSERTION(aValue.mType == &SVGNumberPairSMILType::sSingleton,
    231               "Unexpected type to assign animated value");
    232  if (aValue.mType == &SVGNumberPairSMILType::sSingleton) {
    233    mVal->SetAnimValue(aValue.mU.mNumberPair, mSVGElement);
    234  }
    235  return NS_OK;
    236 }
    237 
    238 }  // namespace mozilla