Coverage Report

Created: 2018-09-25 14:53

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