Bug 733744 - don't round short durations to zero r=birtles

Differential Revision: https://phabricator.services.mozilla.com/D195971
This commit is contained in:
Robert Longson 2023-12-11 13:39:53 +00:00
parent 58cb4c95a3
commit 2e1f916689
6 changed files with 53 additions and 26 deletions

View file

@ -9,7 +9,6 @@
#include "mozilla/SMILAttr.h"
#include "mozilla/SMILKeySpline.h"
#include "mozilla/SMILRepeatCount.h"
#include "mozilla/SMILTimeValue.h"
#include "mozilla/SMILTimeValueSpecParams.h"
#include "mozilla/SMILTypes.h"
#include "mozilla/SMILValue.h"
@ -128,6 +127,7 @@ inline bool ParseClockMetric(RangedPtr<const char16_t>& aIter,
*/
bool ParseClockValue(RangedPtr<const char16_t>& aIter,
const RangedPtr<const char16_t>& aEnd,
SMILTimeValue::Rounding aRounding,
SMILTimeValue* aResult) {
if (aIter == aEnd) {
return false;
@ -187,8 +187,9 @@ bool ParseClockValue(RangedPtr<const char16_t>& aIter,
return false;
}
aResult->SetMillis(SMILTime(hours) * MSEC_PER_HOUR +
minutes * MSEC_PER_MIN + seconds * MSEC_PER_SEC +
NS_round(fraction * MSEC_PER_SEC));
minutes * MSEC_PER_MIN +
(seconds + fraction) * MSEC_PER_SEC,
aRounding);
aIter = iter;
return true;
case TIMECOUNT_VALUE:
@ -203,8 +204,7 @@ bool ParseClockValue(RangedPtr<const char16_t>& aIter,
if (!ParseClockMetric(iter, aEnd, multiplier)) {
return false;
}
aResult->SetMillis(SMILTime(timecount) * multiplier +
NS_round(fraction * multiplier));
aResult->SetMillis((timecount + fraction) * multiplier, aRounding);
aIter = iter;
return true;
}
@ -219,7 +219,8 @@ bool ParseOffsetValue(RangedPtr<const char16_t>& aIter,
int32_t sign;
if (!SVGContentUtils::ParseOptionalSign(iter, aEnd, sign) ||
!SkipWhitespace(iter, aEnd) || !ParseClockValue(iter, aEnd, aResult)) {
!SkipWhitespace(iter, aEnd) ||
!ParseClockValue(iter, aEnd, SMILTimeValue::Rounding::Nearest, aResult)) {
return false;
}
if (sign == -1) {
@ -240,7 +241,7 @@ bool ParseOptionalOffset(RangedPtr<const char16_t>& aIter,
const RangedPtr<const char16_t>& aEnd,
SMILTimeValue* aResult) {
if (aIter == aEnd) {
aResult->SetMillis(0L);
*aResult = SMILTimeValue::Zero();
return true;
}
@ -597,11 +598,12 @@ bool SMILParserUtils::ParseTimeValueSpecParams(
}
bool SMILParserUtils::ParseClockValue(const nsAString& aSpec,
SMILTimeValue::Rounding aRounding,
SMILTimeValue* aResult) {
RangedPtr<const char16_t> iter(SVGContentUtils::GetStartRangedPtr(aSpec));
RangedPtr<const char16_t> end(SVGContentUtils::GetEndRangedPtr(aSpec));
return ::ParseClockValue(iter, end, aResult) && iter == end;
return ::ParseClockValue(iter, end, aRounding, aResult) && iter == end;
}
int32_t SMILParserUtils::CheckForNegativeNumber(const nsAString& aStr) {

View file

@ -9,13 +9,13 @@
#include "nsTArray.h"
#include "nsStringFwd.h"
#include "SMILTimeValue.h"
namespace mozilla {
class SMILAttr;
class SMILKeySpline;
class SMILRepeatCount;
class SMILTimeValue;
class SMILTimeValueSpecParams;
class SMILValue;
@ -72,7 +72,9 @@ class SMILParserUtils {
* @param aResult The parsed result. [OUT]
* @return true if parsing succeeded, otherwise false.
*/
static bool ParseClockValue(const nsAString& aSpec, SMILTimeValue* aResult);
static bool ParseClockValue(const nsAString& aSpec,
SMILTimeValue::Rounding aRounding,
SMILTimeValue* aResult);
/*
* This method checks whether the given string looks like a negative number.

View file

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SMILTimeValue.h"
#include "nsMathUtils.h"
namespace mozilla {
@ -39,4 +40,13 @@ int8_t SMILTimeValue::CompareTo(const SMILTimeValue& aOther) const {
return result;
}
void SMILTimeValue::SetMillis(double aMillis, Rounding aRounding) {
mState = STATE_DEFINITE;
mMilliseconds = NS_round(aMillis);
if (aRounding == Rounding::EnsureNonZero && !mMilliseconds && aMillis) {
// Ensure we don't round small values to zero.
mMilliseconds = std::copysign(1.0, aMillis);
}
}
} // namespace mozilla

View file

@ -68,6 +68,8 @@ class SMILTimeValue {
return value;
}
static SMILTimeValue Zero() { return SMILTimeValue(SMILTime(0L)); }
bool IsIndefinite() const { return mState == STATE_INDEFINITE; }
void SetIndefinite() {
mState = STATE_INDEFINITE;
@ -88,11 +90,23 @@ class SMILTimeValue {
return mState == STATE_DEFINITE ? mMilliseconds : kUnresolvedMillis;
}
bool IsZero() const {
return mState == STATE_DEFINITE ? mMilliseconds == 0 : false;
}
void SetMillis(SMILTime aMillis) {
mState = STATE_DEFINITE;
mMilliseconds = aMillis;
}
/*
* EnsureNonZero ensures values such as 0.0001s are not represented as 0
* for values where 0 is invalid.
*/
enum class Rounding : uint8_t { EnsureNonZero, Nearest };
void SetMillis(double aMillis, Rounding aRounding);
int8_t CompareTo(const SMILTimeValue& aOther) const;
bool operator==(const SMILTimeValue& aOther) const {

View file

@ -229,7 +229,7 @@ SMILTimedElement::SMILTimedElement()
mDeleteCount(0),
mUpdateIntervalRecursionDepth(0) {
mSimpleDur.SetIndefinite();
mMin.SetMillis(0L);
mMin = SMILTimeValue::Zero();
mMax.SetIndefinite();
}
@ -854,8 +854,9 @@ nsresult SMILTimedElement::SetSimpleDuration(const nsAString& aDurSpec) {
if (dur.EqualsLiteral("media") || dur.EqualsLiteral("indefinite")) {
duration.SetIndefinite();
} else {
if (!SMILParserUtils::ParseClockValue(dur, &duration) ||
duration.GetMillis() == 0L) {
if (!SMILParserUtils::ParseClockValue(
dur, SMILTimeValue::Rounding::EnsureNonZero, &duration) ||
duration.IsZero()) {
mSimpleDur.SetIndefinite();
return NS_ERROR_FAILURE;
}
@ -882,10 +883,11 @@ nsresult SMILTimedElement::SetMin(const nsAString& aMinSpec) {
const nsAString& min = SMILParserUtils::TrimWhitespace(aMinSpec);
if (min.EqualsLiteral("media")) {
duration.SetMillis(0L);
duration = SMILTimeValue::Zero();
} else {
if (!SMILParserUtils::ParseClockValue(min, &duration)) {
mMin.SetMillis(0L);
if (!SMILParserUtils::ParseClockValue(min, SMILTimeValue::Rounding::Nearest,
&duration)) {
mMin = SMILTimeValue::Zero();
return NS_ERROR_FAILURE;
}
}
@ -898,7 +900,7 @@ nsresult SMILTimedElement::SetMin(const nsAString& aMinSpec) {
}
void SMILTimedElement::UnsetMin() {
mMin.SetMillis(0L);
mMin = SMILTimeValue::Zero();
UpdateCurrentInterval();
}
@ -912,8 +914,9 @@ nsresult SMILTimedElement::SetMax(const nsAString& aMaxSpec) {
if (max.EqualsLiteral("media") || max.EqualsLiteral("indefinite")) {
duration.SetIndefinite();
} else {
if (!SMILParserUtils::ParseClockValue(max, &duration) ||
duration.GetMillis() == 0L) {
if (!SMILParserUtils::ParseClockValue(
max, SMILTimeValue::Rounding::EnsureNonZero, &duration) ||
duration.IsZero()) {
mMax.SetIndefinite();
return NS_ERROR_FAILURE;
}
@ -974,7 +977,8 @@ nsresult SMILTimedElement::SetRepeatDur(const nsAString& aRepeatDurSpec) {
if (repeatDur.EqualsLiteral("indefinite")) {
duration.SetIndefinite();
} else {
if (!SMILParserUtils::ParseClockValue(repeatDur, &duration)) {
if (!SMILParserUtils::ParseClockValue(
repeatDur, SMILTimeValue::Rounding::EnsureNonZero, &duration)) {
mRepeatDur.SetUnresolved();
return NS_ERROR_FAILURE;
}
@ -1749,7 +1753,7 @@ SMILTime SMILTimedElement::ActiveTimeToSimpleTime(SMILTime aActiveTime,
// Note that a negative aActiveTime will give us a negative value for
// aRepeatIteration, which is bad because aRepeatIteration is unsigned
if (mSimpleDur.IsIndefinite() || mSimpleDur.GetMillis() == 0L) {
if (mSimpleDur.IsIndefinite() || mSimpleDur.IsZero()) {
aRepeatIteration = 0;
result = aActiveTime;
} else {

View file

@ -1,5 +0,0 @@
[short-simple-duration-and-fractional-repeatcount.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Short simple duration and fractional repeatCount does not hang]
expected: FAIL