Bug 1196114 - Part 5: Store performce warning information as enum type. r=birtles

Each warning message is generated only when getPropertyState() is called.

MozReview-Commit-ID: C03ZSvPv9ff

--HG--
extra : rebase_source : 5932957f8f0b171c7b100b1c22e70513959c819e
This commit is contained in:
Hiroyuki Ikezoe 2016-03-04 17:54:25 +09:00
parent 53fd8ccffb
commit 9cacbd5b2d
8 changed files with 226 additions and 105 deletions

View File

@ -0,0 +1,72 @@
/* -*- 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 "AnimationPerformanceWarning.h"
#include "nsContentUtils.h"
namespace mozilla {
bool
AnimationPerformanceWarning::ToLocalizedString(
nsXPIDLString& aLocalizedString) const
{
const char* key = nullptr;
switch (mType) {
case Type::ContentTooLarge:
{
MOZ_ASSERT(mParams && mParams->Length() == 7,
"Parameter's length should be 7 for ContentTooLarge");
MOZ_ASSERT(mParams->Length() <= kMaxParamsForLocalization,
"Parameter's length should be less than "
"kMaxParamsForLocalization");
// We can pass an array of parameters whose length is greater than 7 to
// nsContentUtils::FormatLocalizedString because
// nsTextFormatter drops those extra parameters in the end.
nsAutoString strings[kMaxParamsForLocalization];
const char16_t* charParams[kMaxParamsForLocalization];
for (size_t i = 0, n = mParams->Length(); i < n; i++) {
strings[i].AppendInt((*mParams)[i]);
charParams[i] = strings[i].get();
}
nsresult rv = nsContentUtils::FormatLocalizedString(
nsContentUtils::eLAYOUT_PROPERTIES,
"AnimationWarningContentTooLarge",
charParams,
aLocalizedString);
return NS_SUCCEEDED(rv);
}
case Type::TransformBackfaceVisibilityHidden:
key = "AnimationWarningTransformBackfaceVisibilityHidden";
break;
case Type::TransformPreserve3D:
key = "AnimationWarningTransformPreserve3D";
break;
case Type::TransformSVG:
key = "AnimationWarningTransformSVG";
break;
case Type::TransformFrameInactive:
key = "AnimationWarningTransformFrameInactive";
break;
case Type::OpacityFrameInactive:
key = "AnimationWarningOpacityFrameInactive";
break;
case Type::WithGeometricProperties:
key = "AnimationWarningWithGeometricProperties";
break;
}
nsresult rv =
nsContentUtils::GetLocalizedString(nsContentUtils::eLAYOUT_PROPERTIES,
key, aLocalizedString);
return NS_SUCCEEDED(rv);
}
} // namespace mozilla

View File

@ -0,0 +1,74 @@
/* -*- 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/. */
#ifndef mozilla_dom_AnimationPerformanceWarning_h
#define mozilla_dom_AnimationPerformanceWarning_h
#include "mozilla/InitializerList.h"
class nsXPIDLString;
namespace mozilla {
// Represents the reason why we can't run the CSS property on the compositor.
struct AnimationPerformanceWarning
{
enum class Type : uint8_t {
ContentTooLarge,
TransformBackfaceVisibilityHidden,
TransformPreserve3D,
TransformSVG,
TransformFrameInactive,
OpacityFrameInactive,
WithGeometricProperties
};
explicit AnimationPerformanceWarning(Type aType)
: mType(aType) { }
AnimationPerformanceWarning(Type aType,
std::initializer_list<int32_t> aParams)
: mType(aType)
{
// FIXME: Once std::initializer_list::size() become a constexpr function,
// we should use static_assert here.
MOZ_ASSERT(aParams.size() <= kMaxParamsForLocalization,
"The length of parameters should be less than "
"kMaxParamsForLocalization");
mParams.emplace(aParams);
}
// Maximum number of parameters passed to
// nsContentUtils::FormatLocalizedString to localize warning messages.
//
// NOTE: This constexpr can't be forward declared, so if you want to use
// this variable, please include this header file directly.
// This value is the same as the limit of nsStringBundle::FormatString.
// See the implementation of nsStringBundle::FormatString.
static MOZ_CONSTEXPR_VAR uint8_t kMaxParamsForLocalization = 10;
// Indicates why this property could not be animated on the compositor.
Type mType;
// Optional parameters that may be used for localization.
Maybe<nsTArray<int32_t>> mParams;
bool ToLocalizedString(nsXPIDLString& aLocalizedString) const;
bool operator==(const AnimationPerformanceWarning& aOther) const
{
return mType == aOther.mType &&
mParams == aOther.mParams;
}
bool operator!=(const AnimationPerformanceWarning& aOther) const
{
return !(*this == aOther);
}
};
} // namespace mozilla
#endif // mozilla_dom_AnimationPerformanceWarning_h

View File

@ -10,6 +10,7 @@
#include "mozilla/dom/Element.h" #include "mozilla/dom/Element.h"
#include "mozilla/dom/KeyframeEffect.h" // For KeyframeEffectReadOnly #include "mozilla/dom/KeyframeEffect.h" // For KeyframeEffectReadOnly
#include "mozilla/AnimationUtils.h" #include "mozilla/AnimationUtils.h"
#include "mozilla/AnimationPerformanceWarning.h"
#include "mozilla/EffectSet.h" #include "mozilla/EffectSet.h"
#include "mozilla/InitializerList.h" #include "mozilla/InitializerList.h"
#include "mozilla/LayerAnimationInfo.h" #include "mozilla/LayerAnimationInfo.h"
@ -109,14 +110,14 @@ FindAnimationsForCompositor(const nsIFrame* aFrame,
continue; continue;
} }
nsAutoString performanceWarning; AnimationPerformanceWarning::Type warningType;
if (effect->ShouldBlockCompositorAnimations(aFrame, if (effect->ShouldBlockCompositorAnimations(aFrame,
performanceWarning)) { warningType)) {
if (aMatches) { if (aMatches) {
aMatches->Clear(); aMatches->Clear();
} }
effect->SetPerformanceWarning(aProperty, effect->SetPerformanceWarning(
performanceWarning); aProperty, AnimationPerformanceWarning(warningType));
return false; return false;
} }
@ -721,9 +722,10 @@ EffectCompositor::GetPresContext(Element* aElement)
} }
/* static */ void /* static */ void
EffectCompositor::SetPerformanceWarning(const nsIFrame *aFrame, EffectCompositor::SetPerformanceWarning(
nsCSSProperty aProperty, const nsIFrame *aFrame,
const nsAString& aMessage) nsCSSProperty aProperty,
const AnimationPerformanceWarning& aWarning)
{ {
EffectSet* effects = EffectSet::GetEffectSet(aFrame); EffectSet* effects = EffectSet::GetEffectSet(aFrame);
if (!effects) { if (!effects) {
@ -731,7 +733,7 @@ EffectCompositor::SetPerformanceWarning(const nsIFrame *aFrame,
} }
for (KeyframeEffectReadOnly* effect : *effects) { for (KeyframeEffectReadOnly* effect : *effects) {
effect->SetPerformanceWarning(aProperty, aMessage); effect->SetPerformanceWarning(aProperty, aWarning);
} }
} }

View File

@ -30,6 +30,7 @@ namespace mozilla {
class EffectSet; class EffectSet;
class RestyleTracker; class RestyleTracker;
enum class CSSPseudoElementType : uint8_t; enum class CSSPseudoElementType : uint8_t;
struct AnimationPerformanceWarning;
namespace dom { namespace dom {
class Animation; class Animation;
@ -187,11 +188,12 @@ public:
static Maybe<Pair<dom::Element*, CSSPseudoElementType>> static Maybe<Pair<dom::Element*, CSSPseudoElementType>>
GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame); GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame);
// Associates a warning message with effects on |aFrame| if the effect // Associates a performance warning with effects on |aFrame| that animates
// has |aProperty|. // |aProperty|.
static void SetPerformanceWarning(const nsIFrame* aFrame, static void SetPerformanceWarning(
nsCSSProperty aProperty, const nsIFrame* aFrame,
const nsAString& aMessage); nsCSSProperty aProperty,
const AnimationPerformanceWarning& aWarning);
private: private:
~EffectCompositor() = default; ~EffectCompositor() = default;

View File

@ -1893,8 +1893,10 @@ KeyframeEffectReadOnly::GetPropertyState(
NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(property.mProperty))); NS_ConvertASCIItoUTF16(nsCSSProps::GetStringValue(property.mProperty)));
state.mRunningOnCompositor.Construct(property.mIsRunningOnCompositor); state.mRunningOnCompositor.Construct(property.mIsRunningOnCompositor);
if (property.mPerformanceWarning.isSome()) { nsXPIDLString localizedString;
state.mWarning.Construct(property.mPerformanceWarning.value()); if (property.mPerformanceWarning &&
property.mPerformanceWarning->ToLocalizedString(localizedString)) {
state.mWarning.Construct(localizedString);
} }
aStates.AppendElement(state); aStates.AppendElement(state);
@ -2099,19 +2101,14 @@ KeyframeEffectReadOnly::IsGeometricProperty(
/* static */ bool /* static */ bool
KeyframeEffectReadOnly::CanAnimateTransformOnCompositor( KeyframeEffectReadOnly::CanAnimateTransformOnCompositor(
const nsIFrame* aFrame, const nsIFrame* aFrame,
nsAString& aPerformanceWarning) AnimationPerformanceWarning::Type& aPerformanceWarning)
{ {
// Disallow OMTA for preserve-3d transform. Note that we check the style property // Disallow OMTA for preserve-3d transform. Note that we check the style property
// rather than Extend3DContext() since that can recurse back into this function // rather than Extend3DContext() since that can recurse back into this function
// via HasOpacity(). See bug 779598. // via HasOpacity(). See bug 779598.
if (aFrame->Combines3DTransformWithAncestors() || if (aFrame->Combines3DTransformWithAncestors() ||
aFrame->StyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D) { aFrame->StyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D) {
nsXPIDLString localizedMessage; aPerformanceWarning = AnimationPerformanceWarning::Type::TransformPreserve3D;
nsContentUtils::GetLocalizedString(
nsContentUtils::eLAYOUT_PROPERTIES,
"AnimationWarningTransformPreserve3D",
localizedMessage);
aPerformanceWarning = localizedMessage;
return false; return false;
} }
// Note that testing BackfaceIsHidden() is not a sufficient test for // Note that testing BackfaceIsHidden() is not a sufficient test for
@ -2119,23 +2116,14 @@ KeyframeEffectReadOnly::CanAnimateTransformOnCompositor(
// remove the above test for Extend3DContext(); that would require // remove the above test for Extend3DContext(); that would require
// looking at backface-visibility on descendants as well. See bug 1186204. // looking at backface-visibility on descendants as well. See bug 1186204.
if (aFrame->StyleDisplay()->BackfaceIsHidden()) { if (aFrame->StyleDisplay()->BackfaceIsHidden()) {
nsXPIDLString localizedMessage; aPerformanceWarning =
nsContentUtils::GetLocalizedString( AnimationPerformanceWarning::Type::TransformBackfaceVisibilityHidden;
nsContentUtils::eLAYOUT_PROPERTIES,
"AnimationWarningTransformBackfaceVisibilityHidden",
localizedMessage);
aPerformanceWarning = localizedMessage;
return false; return false;
} }
// Async 'transform' animations of aFrames with SVG transforms is not // Async 'transform' animations of aFrames with SVG transforms is not
// supported. See bug 779599. // supported. See bug 779599.
if (aFrame->IsSVGTransformed()) { if (aFrame->IsSVGTransformed()) {
nsXPIDLString localizedMessage; aPerformanceWarning = AnimationPerformanceWarning::Type::TransformSVG;
nsContentUtils::GetLocalizedString(
nsContentUtils::eLAYOUT_PROPERTIES,
"AnimationWarningTransformSVG",
localizedMessage);
aPerformanceWarning = localizedMessage;
return false; return false;
} }
@ -2145,7 +2133,7 @@ KeyframeEffectReadOnly::CanAnimateTransformOnCompositor(
bool bool
KeyframeEffectReadOnly::ShouldBlockCompositorAnimations( KeyframeEffectReadOnly::ShouldBlockCompositorAnimations(
const nsIFrame* aFrame, const nsIFrame* aFrame,
nsAString& aPerformanceWarning) const AnimationPerformanceWarning::Type& aPerformanceWarning) const
{ {
// We currently only expect this method to be called when this effect // We currently only expect this method to be called when this effect
// is attached to a playing Animation. If that ever changes we'll need // is attached to a playing Animation. If that ever changes we'll need
@ -2162,12 +2150,8 @@ KeyframeEffectReadOnly::ShouldBlockCompositorAnimations(
} }
// Check for geometric properties // Check for geometric properties
if (IsGeometricProperty(property.mProperty)) { if (IsGeometricProperty(property.mProperty)) {
nsXPIDLString localizedMessage; aPerformanceWarning =
nsContentUtils::GetLocalizedString( AnimationPerformanceWarning::Type::WithGeometricProperties;
nsContentUtils::eLAYOUT_PROPERTIES,
"AnimationWarningWithGeometricProperties",
localizedMessage);
aPerformanceWarning = localizedMessage;
return true; return true;
} }
@ -2184,16 +2168,20 @@ KeyframeEffectReadOnly::ShouldBlockCompositorAnimations(
} }
void void
KeyframeEffectReadOnly::SetPerformanceWarning(nsCSSProperty aProperty, KeyframeEffectReadOnly::SetPerformanceWarning(
const nsAString &aMessage) nsCSSProperty aProperty,
const AnimationPerformanceWarning& aWarning)
{ {
for (AnimationProperty& property : mProperties) { for (AnimationProperty& property : mProperties) {
if (property.mProperty == aProperty) { if (property.mProperty == aProperty &&
property.mPerformanceWarning.reset(); (!property.mPerformanceWarning ||
property.mPerformanceWarning.emplace(aMessage); *property.mPerformanceWarning != aWarning)) {
property.mPerformanceWarning = Some(aWarning);
if (nsLayoutUtils::IsAnimationLoggingEnabled()) { nsXPIDLString localizedString;
nsAutoCString logMessage = NS_ConvertUTF16toUTF8(aMessage); if (nsLayoutUtils::IsAnimationLoggingEnabled() &&
property.mPerformanceWarning->ToLocalizedString(localizedString)) {
nsAutoCString logMessage = NS_ConvertUTF16toUTF8(localizedString);
AnimationUtils::LogAsyncAnimationFailure(logMessage, mTarget); AnimationUtils::LogAsyncAnimationFailure(logMessage, mTarget);
} }
return; return;

View File

@ -11,6 +11,7 @@
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
#include "nsIDocument.h" #include "nsIDocument.h"
#include "nsWrapperCache.h" #include "nsWrapperCache.h"
#include "mozilla/AnimationPerformanceWarning.h"
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/ComputedTimingFunction.h" // ComputedTimingFunction #include "mozilla/ComputedTimingFunction.h" // ComputedTimingFunction
#include "mozilla/LayerAnimationInfo.h" // LayerAnimations::kRecords #include "mozilla/LayerAnimationInfo.h" // LayerAnimations::kRecords
@ -146,9 +147,7 @@ struct AnimationProperty
// objects for equality. // objects for equality.
bool mIsRunningOnCompositor = false; bool mIsRunningOnCompositor = false;
// A warning string indicating why this property could not be animated Maybe<AnimationPerformanceWarning> mPerformanceWarning;
// on the compositor.
Maybe<nsString> mPerformanceWarning;
InfallibleTArray<AnimationPropertySegment> mSegments; InfallibleTArray<AnimationPropertySegment> mSegments;
@ -327,17 +326,20 @@ public:
// //
// When returning true, |aOutPerformanceWarning| stores the reason why // When returning true, |aOutPerformanceWarning| stores the reason why
// we shouldn't run the compositor animations. // we shouldn't run the compositor animations.
bool ShouldBlockCompositorAnimations(const nsIFrame* aFrame, bool ShouldBlockCompositorAnimations(
nsAString& aPerformanceWarning) const; const nsIFrame* aFrame,
AnimationPerformanceWarning::Type& aPerformanceWarning) const;
nsIDocument* GetRenderedDocument() const; nsIDocument* GetRenderedDocument() const;
nsPresContext* GetPresContext() const; nsPresContext* GetPresContext() const;
// Associates a warning string with the animated property on the specified // Associates a warning with the animated property on the specified frame
// frame indicating why, for example, the property could not be animated // indicating why, for example, the property could not be animated on the
// on the compositor. // compositor. |aParams| and |aParamsLength| are optional parameters which
void SetPerformanceWarning(nsCSSProperty aProperty, // will be used to generate a localized message for devtools.
const nsAString& aMessage); void SetPerformanceWarning(
nsCSSProperty aProperty,
const AnimationPerformanceWarning& aWarning);
protected: protected:
KeyframeEffectReadOnly(nsIDocument* aDocument, KeyframeEffectReadOnly(nsIDocument* aDocument,
@ -402,8 +404,9 @@ private:
// Returns true unless Gecko limitations prevent performing transform // Returns true unless Gecko limitations prevent performing transform
// animations for |aFrame|. When returning true, the reason for the // animations for |aFrame|. When returning true, the reason for the
// limitation is stored in |aOutPerformanceWarning|. // limitation is stored in |aOutPerformanceWarning|.
static bool CanAnimateTransformOnCompositor(const nsIFrame* aFrame, static bool CanAnimateTransformOnCompositor(
nsAString& aPerformanceWarning); const nsIFrame* aFrame,
AnimationPerformanceWarning::Type& aPerformanceWarning);
static bool IsGeometricProperty(const nsCSSProperty aProperty); static bool IsGeometricProperty(const nsCSSProperty aProperty);
static const TimeDuration OverflowRegionRefreshInterval(); static const TimeDuration OverflowRegionRefreshInterval();

View File

@ -20,6 +20,7 @@ EXPORTS.mozilla.dom += [
EXPORTS.mozilla += [ EXPORTS.mozilla += [
'AnimationComparator.h', 'AnimationComparator.h',
'AnimationPerformanceWarning.h',
'AnimationUtils.h', 'AnimationUtils.h',
'AnimValuesStyleRule.h', 'AnimValuesStyleRule.h',
'ComputedTimingFunction.h', 'ComputedTimingFunction.h',
@ -34,6 +35,7 @@ UNIFIED_SOURCES += [
'AnimationEffectReadOnly.cpp', 'AnimationEffectReadOnly.cpp',
'AnimationEffectTiming.cpp', 'AnimationEffectTiming.cpp',
'AnimationEffectTimingReadOnly.cpp', 'AnimationEffectTimingReadOnly.cpp',
'AnimationPerformanceWarning.cpp',
'AnimationTimeline.cpp', 'AnimationTimeline.cpp',
'AnimationUtils.cpp', 'AnimationUtils.cpp',
'AnimValuesStyleRule.cpp', 'AnimValuesStyleRule.cpp',

View File

@ -52,6 +52,7 @@
#include "ImageContainer.h" #include "ImageContainer.h"
#include "nsCanvasFrame.h" #include "nsCanvasFrame.h"
#include "StickyScrollContainer.h" #include "StickyScrollContainer.h"
#include "mozilla/AnimationPerformanceWarning.h"
#include "mozilla/AnimationUtils.h" #include "mozilla/AnimationUtils.h"
#include "mozilla/EffectCompositor.h" #include "mozilla/EffectCompositor.h"
#include "mozilla/EventStates.h" #include "mozilla/EventStates.h"
@ -5585,14 +5586,10 @@ nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
return true; return true;
} }
nsXPIDLString localizedMessage; EffectCompositor::SetPerformanceWarning(
nsContentUtils::GetLocalizedString( mFrame, eCSSProperty_transform,
nsContentUtils::eLAYOUT_PROPERTIES, AnimationPerformanceWarning(
"AnimationWarningOpacityFrameInactive", AnimationPerformanceWarning::Type::OpacityFrameInactive));
localizedMessage);
EffectCompositor::SetPerformanceWarning(mFrame,
eCSSProperty_opacity,
localizedMessage);
return false; return false;
} }
@ -5640,14 +5637,11 @@ nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBui
if (!ActiveLayerTracker::IsStyleMaybeAnimated(aFrame, eCSSProperty_transform) && if (!ActiveLayerTracker::IsStyleMaybeAnimated(aFrame, eCSSProperty_transform) &&
!EffectCompositor::HasAnimationsForCompositor(aFrame, !EffectCompositor::HasAnimationsForCompositor(aFrame,
eCSSProperty_transform)) { eCSSProperty_transform)) {
nsXPIDLString localizedMessage; EffectCompositor::SetPerformanceWarning(
nsContentUtils::GetLocalizedString( aFrame, eCSSProperty_transform,
nsContentUtils::eLAYOUT_PROPERTIES, AnimationPerformanceWarning(
"AnimationWarningTransformFrameInactive", AnimationPerformanceWarning::Type::TransformFrameInactive));
localizedMessage);
EffectCompositor::SetPerformanceWarning(aFrame,
eCSSProperty_transform,
localizedMessage);
return false; return false;
} }
@ -5668,36 +5662,20 @@ nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBui
nsRect visual = aFrame->GetVisualOverflowRect(); nsRect visual = aFrame->GetVisualOverflowRect();
nsAutoString frameWidth, frameHeight,
refWidth, refHeight,
visualWidth, visualHeight,
maxInAppUnitsString;
frameWidth.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameSize.width));
frameHeight.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(frameSize.height));
refWidth.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.width));
refHeight.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(refSize.height));
visualWidth.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(visual.width));
visualHeight.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(visual.height));
maxInAppUnitsString.AppendInt(nsPresContext::AppUnitsToIntCSSPixels(maxInAppUnits));
const char16_t* params[7] = { EffectCompositor::SetPerformanceWarning(
frameWidth.get(), aFrame, eCSSProperty_transform,
frameHeight.get(), AnimationPerformanceWarning(
refWidth.get(), AnimationPerformanceWarning::Type::ContentTooLarge,
refHeight.get(), {
visualWidth.get(), nsPresContext::AppUnitsToIntCSSPixels(frameSize.width),
visualHeight.get(), nsPresContext::AppUnitsToIntCSSPixels(frameSize.height),
maxInAppUnitsString.get() nsPresContext::AppUnitsToIntCSSPixels(refSize.width),
}; nsPresContext::AppUnitsToIntCSSPixels(refSize.height),
nsPresContext::AppUnitsToIntCSSPixels(visual.width),
nsXPIDLString message; nsPresContext::AppUnitsToIntCSSPixels(visual.height),
nsContentUtils::FormatLocalizedString(nsContentUtils::eLAYOUT_PROPERTIES, nsPresContext::AppUnitsToIntCSSPixels(maxInAppUnits)
"AnimationWarningContentTooLarge", }));
params,
message);
EffectCompositor::SetPerformanceWarning(aFrame,
eCSSProperty_transform,
message);
return false; return false;
} }