зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1734476 - Don't run on compositor when content may contain non-scaling-stroke r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D227400
This commit is contained in:
Родитель
d8a80fdff3
Коммит
15674fd75a
|
@ -41,6 +41,9 @@ bool AnimationPerformanceWarning::ToLocalizedString(
|
|||
|
||||
return NS_SUCCEEDED(ToLocalizedStringWithIntParams<2>(
|
||||
"CompositorAnimationWarningContentTooLargeArea", aLocalizedString));
|
||||
case Type::NonScalingStroke:
|
||||
key = "CompositorAnimationWarningNonScalingStroke";
|
||||
break;
|
||||
case Type::TransformSVG:
|
||||
key = "CompositorAnimationWarningTransformSVG";
|
||||
break;
|
||||
|
|
|
@ -21,6 +21,7 @@ struct AnimationPerformanceWarning {
|
|||
None,
|
||||
ContentTooLarge,
|
||||
ContentTooLargeArea,
|
||||
NonScalingStroke,
|
||||
TransformSVG,
|
||||
TransformFrameInactive,
|
||||
TransformIsBlockedByImportantRules,
|
||||
|
|
|
@ -1632,6 +1632,15 @@ bool KeyframeEffect::CanAnimateTransformOnCompositor(
|
|||
return false;
|
||||
}
|
||||
|
||||
// If there's any content that might have non-scaling stroke then we can't
|
||||
// run in the compositor.
|
||||
if (primaryFrame->IsSVGFrame() &&
|
||||
primaryFrame->HasAnyStateBits(
|
||||
NS_STATE_SVG_MAY_CONTAIN_NON_SCALING_STROKE)) {
|
||||
aPerformanceWarning = AnimationPerformanceWarning::Type::NonScalingStroke;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1377,6 +1377,27 @@ waitForAllPaints(async () => {
|
|||
await ensureElementRemoval(div);
|
||||
});
|
||||
|
||||
add_task_if_omta_enabled(async function svg_non_scaling_stroke_animation() {
|
||||
const div = addDiv(null, { style: 'overflow: scroll;' +
|
||||
'height: 100px; width: 100px;' });
|
||||
const svg = addSVGElement(div, 'svg', { viewBox: '0 0 250 250',
|
||||
width: '40px',
|
||||
height: '40px' });
|
||||
const rect = addSVGElement(svg, 'rect', { x: '0',
|
||||
y: '0',
|
||||
width: '250',
|
||||
height: '250',
|
||||
fill: 'red',
|
||||
style: 'vector-effect: non-scaling-stroke; animation: rotate 100s infinite;'});
|
||||
const animation = rect.getAnimations()[0];
|
||||
await waitForAnimationReadyToRestyle(animation);
|
||||
|
||||
ok(!SpecialPowers.wrap(animation).isRunningOnCompositor,
|
||||
'The animation of a non-scaling-stroke element is not running on the compositor');
|
||||
|
||||
await ensureElementRemoval(div);
|
||||
});
|
||||
|
||||
add_task(async function no_throttling_animations_in_transformed_parent() {
|
||||
const div = addDiv(null, { style: 'overflow: scroll;' +
|
||||
'transform: translateX(50px);' });
|
||||
|
|
|
@ -19,10 +19,12 @@ CompositorAnimationWarningContentTooLargeArea=Animation cannot be run on the com
|
|||
## (%3$S, %4$S) is a pair of integer values of a limit based on the viewport size
|
||||
## (%5$S, %6$S) is a pair of integer values of an absolute limit
|
||||
CompositorAnimationWarningContentTooLarge2=Animation cannot be run on the compositor because the frame size (%1$S, %2$S) is too large relative to the viewport (larger than (%3$S, %4$S)) or larger than the maximum allowed value (%5$S, %6$S)
|
||||
## LOCALIZATION NOTE(CompositorAnimationWarningTransformSVG,
|
||||
## LOCALIZATION NOTE(CompositorAnimationWarningNonScalingStroke,
|
||||
## CompositorAnimationWarningTransformSVG,
|
||||
## CompositorAnimationWarningTransformFrameInactive,
|
||||
## CompositorAnimationWarningOpacityFrameInactive):
|
||||
## 'transform' and 'opacity' mean CSS property names, don't translate it.
|
||||
CompositorAnimationWarningNonScalingStroke=Animations of ‘transform’ on content containing non-scaling-stroke elements cannot be run on the compositor
|
||||
CompositorAnimationWarningTransformSVG=Animations of ‘transform’ on elements with SVG transforms cannot be run on the compositor
|
||||
CompositorAnimationWarningTransformFrameInactive=Animation cannot be run on the compositor because the frame was not marked active for ‘transform’ animation
|
||||
CompositorAnimationWarningTransformIsBlockedByImportantRules=Transform animation cannot be run on the compositor because transform-related properties are overridden by !important rules
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "mozilla/ScrollContainerFrame.h"
|
||||
#include "mozilla/StaticPrefs_browser.h"
|
||||
#include "mozilla/StaticPrefs_layout.h"
|
||||
#include "mozilla/SVGUtils.h"
|
||||
#include "mozilla/ToString.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
|
@ -6681,6 +6682,14 @@ static bool EstablishesBFC(const nsBlockFrame* aFrame) {
|
|||
|
||||
void nsBlockFrame::DidSetComputedStyle(ComputedStyle* aOldStyle) {
|
||||
nsContainerFrame::DidSetComputedStyle(aOldStyle);
|
||||
if (IsInSVGTextSubtree() &&
|
||||
(StyleSVGReset()->HasNonScalingStroke() &&
|
||||
(!aOldStyle || !aOldStyle->StyleSVGReset()->HasNonScalingStroke()))) {
|
||||
nsIFrame* textFrame =
|
||||
nsLayoutUtils::GetClosestFrameOfType(this, LayoutFrameType::SVGText);
|
||||
MOZ_ASSERT(textFrame, "Expecting to find an SVG text frame");
|
||||
SVGUtils::UpdateNonScalingStrokeStateBit(textFrame);
|
||||
}
|
||||
if (!aOldStyle) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -437,6 +437,10 @@ FRAME_STATE_BIT(SVG, 23, NS_STATE_SVG_TEXT_IN_REFLOW)
|
|||
// to update the cached nsTextNode indexes that they correspond to.
|
||||
FRAME_STATE_BIT(SVG, 24, NS_STATE_SVG_TEXT_CORRESPONDENCE_DIRTY)
|
||||
|
||||
// Set on svg frames when they or their descendants may contain non-scaling
|
||||
// stroke contents.
|
||||
FRAME_STATE_BIT(SVG, 25, NS_STATE_SVG_MAY_CONTAIN_NON_SCALING_STROKE)
|
||||
|
||||
// == Frame state bits that apply to text frames ==============================
|
||||
|
||||
FRAME_STATE_GROUP(Text, nsTextFrame)
|
||||
|
|
|
@ -84,6 +84,11 @@ nsresult SVGGeometryFrame::AttributeChanged(int32_t aNameSpaceID,
|
|||
/* virtual */
|
||||
void SVGGeometryFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
|
||||
nsIFrame::DidSetComputedStyle(aOldComputedStyle);
|
||||
if (StyleSVGReset()->HasNonScalingStroke() &&
|
||||
(!aOldComputedStyle ||
|
||||
!aOldComputedStyle->StyleSVGReset()->HasNonScalingStroke())) {
|
||||
SVGUtils::UpdateNonScalingStrokeStateBit(this);
|
||||
}
|
||||
auto* element = static_cast<SVGGeometryElement*>(GetContent());
|
||||
if (!aOldComputedStyle) {
|
||||
element->ClearAnyCachedPath();
|
||||
|
|
|
@ -2787,6 +2787,15 @@ void SVGTextFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
|||
aLists.Content()->AppendNewToTop<DisplaySVGText>(aBuilder, this);
|
||||
}
|
||||
|
||||
void SVGTextFrame::DidSetComputedStyle(ComputedStyle* aOldComputedStyle) {
|
||||
SVGDisplayContainerFrame::DidSetComputedStyle(aOldComputedStyle);
|
||||
if (StyleSVGReset()->HasNonScalingStroke() &&
|
||||
(!aOldComputedStyle ||
|
||||
!aOldComputedStyle->StyleSVGReset()->HasNonScalingStroke())) {
|
||||
SVGUtils::UpdateNonScalingStrokeStateBit(this);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult SVGTextFrame::AttributeChanged(int32_t aNameSpaceID,
|
||||
nsAtom* aAttribute, int32_t aModType) {
|
||||
if (aNameSpaceID != kNameSpaceID_None) {
|
||||
|
|
|
@ -199,6 +199,8 @@ class SVGTextFrame final : public SVGDisplayContainerFrame {
|
|||
void Init(nsIContent* aContent, nsContainerFrame* aParent,
|
||||
nsIFrame* aPrevInFlow) override;
|
||||
|
||||
void DidSetComputedStyle(ComputedStyle* aOldComputedStyle) override;
|
||||
|
||||
nsresult AttributeChanged(int32_t aNamespaceID, nsAtom* aAttribute,
|
||||
int32_t aModType) override;
|
||||
|
||||
|
|
|
@ -1071,6 +1071,21 @@ bool SVGUtils::GetNonScalingStrokeTransform(const nsIFrame* aFrame,
|
|||
return aUserToOuterSVG->HasNonTranslation() && !aUserToOuterSVG->IsSingular();
|
||||
}
|
||||
|
||||
void SVGUtils::UpdateNonScalingStrokeStateBit(nsIFrame* aFrame) {
|
||||
MOZ_ASSERT(aFrame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT),
|
||||
"Called on invalid frame type");
|
||||
MOZ_ASSERT(aFrame->StyleSVGReset()->HasNonScalingStroke(),
|
||||
"Expecting initial frame to have non-scaling-stroke style");
|
||||
|
||||
do {
|
||||
MOZ_ASSERT(aFrame->IsSVGFrame(), "Unexpected frame type");
|
||||
aFrame->AddStateBits(NS_STATE_SVG_MAY_CONTAIN_NON_SCALING_STROKE);
|
||||
if (aFrame->IsSVGOuterSVGFrame()) {
|
||||
return;
|
||||
}
|
||||
} while (aFrame = aFrame->GetParent());
|
||||
}
|
||||
|
||||
// The logic here comes from _cairo_stroke_style_max_distance_from_path
|
||||
static gfxRect PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
|
||||
const nsIFrame* aFrame,
|
||||
|
|
|
@ -422,6 +422,12 @@ class SVGUtils final {
|
|||
static bool GetNonScalingStrokeTransform(const nsIFrame* aFrame,
|
||||
gfxMatrix* aUserToOuterSVG);
|
||||
|
||||
/**
|
||||
* We need to track whether content has non-scaling-stroke because we can't
|
||||
* asynchronously animate it with a scaling transform.
|
||||
*/
|
||||
static void UpdateNonScalingStrokeStateBit(nsIFrame* aFrame);
|
||||
|
||||
/**
|
||||
* Compute the maximum possible device space stroke extents of a path given
|
||||
* the path's device space path extents, its stroke style and its ctm.
|
||||
|
|
Загрузка…
Ссылка в новой задаче