summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMoonchild <moonchild@palemoon.org>2023-10-30 16:43:13 +0100
committerMoonchild <moonchild@palemoon.org>2023-11-01 10:32:04 +0100
commit9493e8c3dedbe92fed6391e74aa21627aee89d67 (patch)
tree588db08660544f9306b813384e8b94d3af3d3562
parent763129711224a8a46dfb0b7951c4ca5fcc23e1d1 (diff)
downloaduxp-9493e8c3dedbe92fed6391e74aa21627aee89d67.tar.gz
Issue #2364 - Limit the growth of scaling for animated nsDisplayTransform
in the fallback case. This ensures we don't scale the underlying size of the layer beyond what is close to the current display size. When box shadows get much larger than this, they start taking so much time to render that successive frames grow in scale too fast for any inter-frame reuse to be possible. With this, we avoid that and no longer get crushed by re-rendering gigantic box shadows every single frame. See BZ 1383825
-rw-r--r--gfx/thebes/gfxUtils.cpp13
-rw-r--r--gfx/thebes/gfxUtils.h5
-rw-r--r--layout/base/FrameLayerBuilder.cpp45
3 files changed, 42 insertions, 21 deletions
diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp
index 1ec73fbde0..3fc1f64639 100644
--- a/gfx/thebes/gfxUtils.cpp
+++ b/gfx/thebes/gfxUtils.cpp
@@ -692,7 +692,7 @@ gfxUtils::ClipToRegion(DrawTarget* aTarget, const nsIntRegion& aRegion)
}
/*static*/ gfxFloat
-gfxUtils::ClampToScaleFactor(gfxFloat aVal)
+gfxUtils::ClampToScaleFactor(gfxFloat aVal, bool aRoundDown)
{
// Arbitary scale factor limitation. We can increase this
// for better scaling performance at the cost of worse
@@ -713,14 +713,17 @@ gfxUtils::ClampToScaleFactor(gfxFloat aVal)
gfxFloat power = log(aVal)/log(kScaleResolution);
- // If power is within 1e-5 of an integer, round to nearest to
- // prevent floating point errors, otherwise round up to the
- // next integer value.
if (fabs(power - NS_round(power)) < 1e-5) {
+ // If power is within 1e-5 of an integer, round to nearest to
+ // prevent floating point errors.
power = NS_round(power);
- } else if (inverse) {
+ } else if (inverse != aRoundDown) {
+ // Use floor when we are either inverted or rounding down, but
+ // not both.
power = floor(power);
} else {
+ // Otherwise, ceil when we are not inverted and not rounding
+ // down, or we are inverted and rounding down.
power = ceil(power);
}
diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h
index 80094a762f..e2b5d476f5 100644
--- a/gfx/thebes/gfxUtils.h
+++ b/gfx/thebes/gfxUtils.h
@@ -128,9 +128,10 @@ public:
/**
* Return the smallest power of kScaleResolution (2) greater than or equal to
- * aVal.
+ * aVal. If aRoundDown is specified, the power of 2 will be less than
+ * or equal to aVal.
*/
- static gfxFloat ClampToScaleFactor(gfxFloat aVal);
+ static gfxFloat ClampToScaleFactor(gfxFloat aVal, bool aRoundDown = false);
/**
* Clears surface to aColor (which defaults to transparent black).
diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp
index d38b17adc4..d23ca436c9 100644
--- a/layout/base/FrameLayerBuilder.cpp
+++ b/layout/base/FrameLayerBuilder.cpp
@@ -5245,6 +5245,23 @@ static void RestrictScaleToMaxLayerSize(gfxSize& aScale,
aScale.height /= scale;
}
}
+
+static nsSize
+ComputeDesiredDisplaySizeForAnimation(nsIFrame* aContainerFrame)
+{
+ // Use the size of the nearest widget as the maximum size. This
+ // is important since it might be a popup that is bigger than the
+ // pres context's size.
+ nsPresContext* presContext = aContainerFrame->PresContext();
+ nsIWidget* widget = aContainerFrame->GetNearestWidget();
+ if (widget) {
+ return LayoutDevicePixel::ToAppUnits(widget->GetClientSize(),
+ presContext->AppUnitsPerDevPixel());
+ } else {
+ return presContext->GetVisibleArea().Size();
+ }
+}
+
static bool
ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
nsDisplayListBuilder* aDisplayListBuilder,
@@ -5309,20 +5326,7 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
aContainerItem->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
EffectCompositor::HasAnimationsForCompositor(
aContainerFrame, eCSSProperty_transform)) {
- // Use the size of the nearest widget as the maximum size. This
- // is important since it might be a popup that is bigger than the
- // pres context's size.
- nsPresContext* presContext = aContainerFrame->PresContext();
- nsIWidget* widget = aContainerFrame->GetNearestWidget();
- nsSize displaySize;
- if (widget) {
- LayoutDeviceIntSize widgetSize = widget->GetClientSize();
- int32_t p2a = presContext->AppUnitsPerDevPixel();
- displaySize.width = NSIntPixelsToAppUnits(widgetSize.width, p2a);
- displaySize.height = NSIntPixelsToAppUnits(widgetSize.height, p2a);
- } else {
- displaySize = presContext->GetVisibleArea().Size();
- }
+ nsSize displaySize = ComputeDesiredDisplaySizeForAnimation(aContainerFrame);
// compute scale using the animation on the container (ignoring
// its ancestors)
scale = nsLayoutUtils::ComputeSuitableScaleForAnimation(
@@ -5359,6 +5363,19 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
if (clamp) {
scale.width = gfxUtils::ClampToScaleFactor(scale.width);
scale.height = gfxUtils::ClampToScaleFactor(scale.height);
+
+ // Limit animated scale factors to not grow excessively beyond the display size.
+ nsSize maxScale(4, 4);
+ if (!aVisibleRect.IsEmpty()) {
+ nsSize displaySize = ComputeDesiredDisplaySizeForAnimation(aContainerFrame);
+ maxScale = Max(maxScale, displaySize / aVisibleRect.Size());
+ }
+ if (scale.width > maxScale.width) {
+ scale.width = gfxUtils::ClampToScaleFactor(maxScale.width, true);
+ }
+ if (scale.height > maxScale.height) {
+ scale.height = gfxUtils::ClampToScaleFactor(maxScale.height, true);
+ }
}
} else {
// XXX Do we need to move nearly-integer values to integers here?