Changeset 236306 in webkit


Ignore:
Timestamp:
Sep 20, 2018 10:37:01 PM (6 years ago)
Author:
dino@apple.com
Message:

Restrict the total combined size of backdrop filters
https://bugs.webkit.org/show_bug.cgi?id=189812
<rdar://problem/44532782>

Reviewed by Simon Fraser.

Source/WebCore:

If the total area of all backdrop filters on the page gets
too large, the universe collapses in on itself and we enter
the Quantum Realm (i.e. crash horribly).

Put a hard limit on the total coverage, and ignore any backdrop
filters after the limit. This might break some content, but
such content is likely not doing things in the most optimal manner.
There isn't any reason to have a backdrop larger than the size of
the screen, because you'd be better off applying a foreground
filter to the main content and showing something above it.

Tests: css3/filters/backdrop/resource-use-add-more-layers.html

css3/filters/backdrop/resource-use-excessive.html
css3/filters/backdrop/resource-use-ok.html
css3/filters/backdrop/resource-use-remove-some-layers.html

  • platform/graphics/ca/GraphicsLayerCA.cpp: Pick a fairly small maximum size. We

can consider increasing this if necessary, and as devices with less RAM are
upgraded.
(WebCore::GraphicsLayerCA::recursiveCommitChanges): Gather the accumulated size
of backdrop filters into the commit state as we are recursing through the tree.
(WebCore::GraphicsLayerCA::commitLayerChangesBeforeSublayers): Force any layer
with backdrop filters, or any that is removing backdrop filters, into an update.
(WebCore::GraphicsLayerCA::updateBackdropFilters): Update the logic to first
check if this backdrop layer causes us to exceed the total allowed size, and if
it does, forbid it from getting the GraphicsLayer that composits the backdrop.

  • platform/graphics/ca/GraphicsLayerCA.h: Remove const from some parameters so

that we can use the CommitState to hold the accumulated size.

LayoutTests:

Tests that have an acceptable number of backdrops, an excessive
number of backdrops, and then some that add and remove backdrops
at various points in the tree to confirm we do recursive checks
correctly.

  • css3/filters/backdrop/layer-tree-as-text.js: Added.
  • css3/filters/backdrop/resource-use-add-more-layers-expected.txt: Added.
  • css3/filters/backdrop/resource-use-add-more-layers.html: Added.
  • css3/filters/backdrop/resource-use-excessive-expected.txt: Added.
  • css3/filters/backdrop/resource-use-excessive.html: Added.
  • css3/filters/backdrop/resource-use-ok-expected.txt: Added.
  • css3/filters/backdrop/resource-use-ok.html: Added.
  • css3/filters/backdrop/resource-use-remove-some-layers-expected.txt: Added.
  • css3/filters/backdrop/resource-use-remove-some-layers.html: Added.
  • css3/filters/backdrop/resource-use.css: Added.
Location:
trunk
Files:
10 added
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r236292 r236306  
     12018-09-20  Dean Jackson  <dino@apple.com>
     2
     3        Restrict the total combined size of backdrop filters
     4        https://bugs.webkit.org/show_bug.cgi?id=189812
     5        <rdar://problem/44532782>
     6
     7        Reviewed by Simon Fraser.
     8
     9        Tests that have an acceptable number of backdrops, an excessive
     10        number of backdrops, and then some that add and remove backdrops
     11        at various points in the tree to confirm we do recursive checks
     12        correctly.
     13
     14        * css3/filters/backdrop/layer-tree-as-text.js: Added.
     15        * css3/filters/backdrop/resource-use-add-more-layers-expected.txt: Added.
     16        * css3/filters/backdrop/resource-use-add-more-layers.html: Added.
     17        * css3/filters/backdrop/resource-use-excessive-expected.txt: Added.
     18        * css3/filters/backdrop/resource-use-excessive.html: Added.
     19        * css3/filters/backdrop/resource-use-ok-expected.txt: Added.
     20        * css3/filters/backdrop/resource-use-ok.html: Added.
     21        * css3/filters/backdrop/resource-use-remove-some-layers-expected.txt: Added.
     22        * css3/filters/backdrop/resource-use-remove-some-layers.html: Added.
     23        * css3/filters/backdrop/resource-use.css: Added.
     24
    1252018-09-20  Truitt Savell  <tsavell@apple.com>
    226
  • trunk/Source/WebCore/ChangeLog

    r236290 r236306  
     12018-09-20  Dean Jackson  <dino@apple.com>
     2
     3        Restrict the total combined size of backdrop filters
     4        https://bugs.webkit.org/show_bug.cgi?id=189812
     5        <rdar://problem/44532782>
     6
     7        Reviewed by Simon Fraser.
     8
     9        If the total area of all backdrop filters on the page gets
     10        too large, the universe collapses in on itself and we enter
     11        the Quantum Realm (i.e. crash horribly).
     12
     13        Put a hard limit on the total coverage, and ignore any backdrop
     14        filters after the limit. This might break some content, but
     15        such content is likely not doing things in the most optimal manner.
     16        There isn't any reason to have a backdrop larger than the size of
     17        the screen, because you'd be better off applying a foreground
     18        filter to the main content and showing something above it.
     19
     20        Tests: css3/filters/backdrop/resource-use-add-more-layers.html
     21               css3/filters/backdrop/resource-use-excessive.html
     22               css3/filters/backdrop/resource-use-ok.html
     23               css3/filters/backdrop/resource-use-remove-some-layers.html
     24
     25        * platform/graphics/ca/GraphicsLayerCA.cpp: Pick a fairly small maximum size. We
     26        can consider increasing this if necessary, and as devices with less RAM are
     27        upgraded.
     28        (WebCore::GraphicsLayerCA::recursiveCommitChanges): Gather the accumulated size
     29        of backdrop filters into the commit state as we are recursing through the tree.
     30        (WebCore::GraphicsLayerCA::commitLayerChangesBeforeSublayers): Force any layer
     31        with backdrop filters, or any that is removing backdrop filters, into an update.
     32        (WebCore::GraphicsLayerCA::updateBackdropFilters): Update the logic to first
     33        check if this backdrop layer causes us to exceed the total allowed size, and if
     34        it does, forbid it from getting the GraphicsLayer that composits the backdrop.
     35
     36        * platform/graphics/ca/GraphicsLayerCA.h: Remove const from some parameters so
     37        that we can use the CommitState to hold the accumulated size.
     38
    1392018-09-20  Benjamin Poulain  <benjamin@webkit.org>
    240
  • trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp

    r236247 r236306  
    4848#include <limits.h>
    4949#include <pal/spi/cf/CFUtilitiesSPI.h>
     50#include <wtf/CheckedArithmetic.h>
    5051#include <wtf/MathExtras.h>
    5152#include <wtf/NeverDestroyed.h>
     
    8990
    9091// Derived empirically: <rdar://problem/13401861>
    91 static const int cMaxLayerTreeDepth = 250;
     92static const unsigned cMaxLayerTreeDepth = 250;
     93
     94// About 10 screens of an iPhone 6 Plus. <rdar://problem/44532782>
     95static const unsigned cMaxTotalBackdropFilterArea = 1242 * 2208 * 10;
    9296
    9397// If we send a duration of 0 to CA, then it will use the default duration
     
    14881492// rootRelativeTransformForScaling is a transform from the root, but for layers with transform animations, it cherry-picked the state of the
    14891493// animation that contributes maximally to the scale (on every layer with animations down the hierarchy).
    1490 void GraphicsLayerCA::recursiveCommitChanges(const CommitState& commitState, const TransformState& state, float pageScaleFactor, const FloatPoint& positionRelativeToBase, bool affectedByPageScale)
     1494void GraphicsLayerCA::recursiveCommitChanges(CommitState& commitState, const TransformState& state, float pageScaleFactor, const FloatPoint& positionRelativeToBase, bool affectedByPageScale)
    14911495{
    14921496    if (!needsCommit(commitState))
     
    15851589    }
    15861590
     1591    commitState.totalBackdropFilterArea = childCommitState.totalBackdropFilterArea;
     1592
    15871593    if (GraphicsLayerCA* replicaLayer = downcast<GraphicsLayerCA>(m_replicaLayer.get()))
    15881594        replicaLayer->recursiveCommitChanges(childCommitState, localState, pageScaleFactor, baseRelativePosition, affectedByPageScale);
     
    17791785        updateFilters();
    17801786
    1781     if (m_uncommittedChanges & BackdropFiltersChanged)
    1782         updateBackdropFilters();
     1787    // If there are backdrop filters, we need to always check the resource usage
     1788    // because something up the tree may have changed its usage.
     1789    if (m_uncommittedChanges & BackdropFiltersChanged || needsBackdrop())
     1790        updateBackdropFilters(commitState);
    17831791
    17841792    if (m_uncommittedChanges & BackdropFiltersRectChanged)
     
    21272135}
    21282136
    2129 void GraphicsLayerCA::updateBackdropFilters()
    2130 {
    2131     if (m_backdropFilters.isEmpty()) {
     2137void GraphicsLayerCA::updateBackdropFilters(CommitState& commitState)
     2138{
     2139    bool canHaveBackdropFilters = needsBackdrop();
     2140
     2141    if (canHaveBackdropFilters) {
     2142        Checked<unsigned, RecordOverflow> backdropFilterArea = Checked<unsigned>(static_cast<int>(m_backdropFiltersRect.rect().width())) * Checked<unsigned>(static_cast<int>(m_backdropFiltersRect.rect().height()));
     2143        if (backdropFilterArea.hasOverflowed())
     2144            canHaveBackdropFilters = false;
     2145        else {
     2146            Checked<unsigned, RecordOverflow> newTotalBackdropFilterArea = Checked<unsigned, RecordOverflow>(commitState.totalBackdropFilterArea) + backdropFilterArea;
     2147            if (newTotalBackdropFilterArea.hasOverflowed() || newTotalBackdropFilterArea.unsafeGet() > cMaxTotalBackdropFilterArea)
     2148                canHaveBackdropFilters = false;
     2149            else
     2150                commitState.totalBackdropFilterArea = newTotalBackdropFilterArea.unsafeGet();
     2151        }
     2152    }
     2153
     2154    if (!canHaveBackdropFilters) {
    21322155        if (m_backdropLayer) {
    21332156            m_backdropLayer->removeFromSuperlayer();
     
    21372160        return;
    21382161    }
     2162
     2163    // If nothing actually changed, no need to touch the layer properties.
     2164    if (!(m_uncommittedChanges & BackdropFiltersChanged))
     2165        return;
    21392166
    21402167    bool madeLayer = !m_backdropLayer;
  • trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.h

    r236247 r236306  
    155155
    156156    struct CommitState {
    157         int treeDepth { 0 };
     157        unsigned treeDepth { 0 };
     158        unsigned totalBackdropFilterArea { 0 };
    158159        bool ancestorHadChanges { false };
    159160        bool ancestorHasTransformAnimation { false };
     
    163164    };
    164165    bool needsCommit(const CommitState&);
    165     void recursiveCommitChanges(const CommitState&, const TransformState&, float pageScaleFactor = 1, const FloatPoint& positionRelativeToBase = FloatPoint(), bool affectedByPageScale = false);
     166    void recursiveCommitChanges(CommitState&, const TransformState&, float pageScaleFactor = 1, const FloatPoint& positionRelativeToBase = FloatPoint(), bool affectedByPageScale = false);
    166167
    167168    WEBCORE_EXPORT void flushCompositingState(const FloatRect&) override;
     
    425426    void updateOpacityOnLayer();
    426427    void updateFilters();
    427     void updateBackdropFilters();
     428    void updateBackdropFilters(CommitState&);
    428429    void updateBackdropFiltersRect();
    429430
Note: See TracChangeset for help on using the changeset viewer.