Files
tubestation/dom/animation/KeyframeEffectParams.cpp
Brian Birtles 66b7edb9b6 Bug 1371518 - Make KeyframeUtils::IsAnimatable consult the Servo backend; r=hiro
When styling with the Servo backend, we should also use the Servo backend to
determine if a property is animatable or not. However, if we do this,
Servo_Property_IsAnimatable will start returning true for the 'display' property
once we mark that as animatable in Servo (for SMIL).

Even if we later fail to actually animate 'display' (due checks added to Servo
in the next patch) we still need to treat 'display' as un-animatable in
KeyframeUtils so that we don't *read* the 'display' property of Keyframe objects
passed to the Animations API, since that is observable.

This patch makes us consult Servo_Property_IsAnimatable when using the Servo
backend and also explicitly treat the 'display' property as not animatable.

MozReview-Commit-ID: 1JllbeJisAS
2017-06-14 15:23:45 +09:00

175 lines
4.9 KiB
C++

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/KeyframeEffectParams.h"
#include "mozilla/AnimationUtils.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/KeyframeUtils.h"
#include "mozilla/RangedPtr.h"
#include "nsReadableUtils.h"
namespace mozilla {
static inline bool
IsLetter(char16_t aCh)
{
return (0x41 <= aCh && aCh <= 0x5A) || (0x61 <= aCh && aCh <= 0x7A);
}
static inline bool
IsDigit(char16_t aCh)
{
return 0x30 <= aCh && aCh <= 0x39;
}
static inline bool
IsNameStartCode(char16_t aCh)
{
return IsLetter(aCh) || aCh >= 0x80 || aCh == '_';
}
static inline bool
IsNameCode(char16_t aCh)
{
return IsNameStartCode(aCh) || IsDigit(aCh) || aCh == '-';
}
static inline bool
IsNewLine(char16_t aCh)
{
// 0x0A (LF), 0x0C (FF), 0x0D (CR), or pairs of CR followed by LF are
// replaced by LF.
return aCh == 0x0A || aCh == 0x0C || aCh == 0x0D;
}
static inline bool
IsValidEscape(char16_t aFirst, char16_t aSecond)
{
return aFirst == '\\' && !IsNewLine(aSecond);
}
static bool
IsIdentStart(RangedPtr<const char16_t> aIter,
const char16_t* const aEnd)
{
if (aIter == aEnd) {
return false;
}
if (*aIter == '-') {
if (aIter + 1 == aEnd) {
return false;
}
char16_t second = *(aIter + 1);
return IsNameStartCode(second) ||
second == '-' ||
(aIter + 2 != aEnd && IsValidEscape(second, *(aIter + 2)));
}
return IsNameStartCode(*aIter) ||
(aIter + 1 != aEnd && IsValidEscape(*aIter, *(aIter + 1)));
}
static void
ConsumeIdentToken(RangedPtr<const char16_t>& aIter,
const char16_t* const aEnd,
nsAString& aResult)
{
aResult.Truncate();
// Check if it starts with an identifier.
if (!IsIdentStart(aIter, aEnd)) {
return;
}
// Start to consume.
while (aIter != aEnd) {
if (IsNameCode(*aIter)) {
aResult.Append(*aIter);
} else if (*aIter == '\\') {
const RangedPtr<const char16_t> secondChar = aIter + 1;
if (secondChar == aEnd || !IsValidEscape(*aIter, *secondChar)) {
break;
}
// Consume '\\' and append the character following this '\\'.
++aIter;
aResult.Append(*aIter);
} else {
break;
}
++aIter;
}
}
/* static */ void
KeyframeEffectParams::ParseSpacing(const nsAString& aSpacing,
SpacingMode& aSpacingMode,
nsCSSPropertyID& aPacedProperty,
nsAString& aInvalidPacedProperty,
dom::CallerType aCallerType,
ErrorResult& aRv)
{
aInvalidPacedProperty.Truncate();
// Ignore spacing if the core API is not enabled since it is not yet ready to
// ship.
if (!AnimationUtils::IsCoreAPIEnabledForCaller(aCallerType)) {
aSpacingMode = SpacingMode::distribute;
return;
}
// Parse spacing.
// distribute | paced({ident})
// https://w3c.github.io/web-animations/#dom-keyframeeffectreadonly-spacing
// 1. distribute spacing.
if (aSpacing.EqualsLiteral("distribute")) {
aSpacingMode = SpacingMode::distribute;
return;
}
// 2. paced spacing.
static const nsLiteralString kPacedPrefix = NS_LITERAL_STRING("paced(");
if (!StringBeginsWith(aSpacing, kPacedPrefix)) {
aRv.ThrowTypeError<dom::MSG_INVALID_SPACING_MODE_ERROR>(aSpacing);
return;
}
RangedPtr<const char16_t> iter(aSpacing.Data() + kPacedPrefix.Length(),
aSpacing.Data(), aSpacing.Length());
const char16_t* const end = aSpacing.EndReading();
nsAutoString identToken;
ConsumeIdentToken(iter, end, identToken);
if (identToken.IsEmpty()) {
aRv.ThrowTypeError<dom::MSG_INVALID_SPACING_MODE_ERROR>(aSpacing);
return;
}
aPacedProperty =
nsCSSProps::LookupProperty(identToken, CSSEnabledState::eForAllContent);
if (aPacedProperty == eCSSProperty_UNKNOWN ||
aPacedProperty == eCSSPropertyExtra_variable ||
// We just unconditionally pass Gecko as the backend type here since
// Servo doesn't support paced timing and this feature will soon be
// removed (bug 1339690).
!KeyframeUtils::IsAnimatableProperty(aPacedProperty,
StyleBackendType::Gecko)) {
aPacedProperty = eCSSProperty_UNKNOWN;
aInvalidPacedProperty = identToken;
}
if (end - iter.get() != 1 || *iter != ')') {
aRv.ThrowTypeError<dom::MSG_INVALID_SPACING_MODE_ERROR>(aSpacing);
return;
}
aSpacingMode = aPacedProperty == eCSSProperty_UNKNOWN
? SpacingMode::distribute
: SpacingMode::paced;
}
} // namespace mozilla