Coverage Report

Created: 2018-09-25 14:53

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