Changeset 116538 in webkit


Ignore:
Timestamp:
May 9, 2012 10:01:16 AM (12 years ago)
Author:
danakj@chromium.org
Message:

Early-out and avoid any copying when possible for Region operations
https://bugs.webkit.org/show_bug.cgi?id=85260

Reviewed by Anders Carlsson.

Source/WebCore:

For an empty region, any intersection or subtraction will not modify
the region, so we can simply return instead of creating a new Shape
and replacing the current empty Shape.

When a region is united with a region it contains, the orignal
containing region is the result. So, if A.unite(B) and A.contains(B)
then A does not need to change at all and we can return without making
a copy of A's shape. When A is a rect, we can do this test even more
simply.

We also remove redundant checks from trySimpleOperation() methods, where
the test is already done in the Region calling site.

This change improves the performance of the Region overlap testing for
composited layers, and allows us to avoid unnecessary copies of the
Region during unite. With a layout test (attached to bug #81087), that
creates a Region from the union of 225 composited layers, as well as
600 overlapping layers above them, this change decreases the running
time of the test by 3.2% by avoiding a copy of the entire Region for
each insertion that does not change the resulting Region.

Unit tests: RegionTest.unite

  • platform/graphics/Region.cpp:

(WebCore::Region::Shape::UnionOperation::trySimpleOperation):
(WebCore::Region::Shape::IntersectOperation::trySimpleOperation):
(WebCore::Region::Shape::SubtractOperation::trySimpleOperation):
(WebCore::Region::intersect):
(WebCore::Region::unite):
(WebCore::Region::subtract):

  • platform/graphics/Region.h:

(WebCore::Region::isRect):
(WebCore::Region::Shape::isRect):

Source/WebKit/chromium:

  • tests/RegionTest.cpp:

(WebCore::TEST):
(WebCore):

Location:
trunk/Source
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r116530 r116538  
     12012-05-09  Dana Jansens  <danakj@chromium.org>
     2
     3        Early-out and avoid any copying when possible for Region operations
     4        https://bugs.webkit.org/show_bug.cgi?id=85260
     5
     6        Reviewed by Anders Carlsson.
     7
     8        For an empty region, any intersection or subtraction will not modify
     9        the region, so we can simply return instead of creating a new Shape
     10        and replacing the current empty Shape.
     11
     12        When a region is united with a region it contains, the orignal
     13        containing region is the result. So, if A.unite(B) and A.contains(B)
     14        then A does not need to change at all and we can return without making
     15        a copy of A's shape. When A is a rect, we can do this test even more
     16        simply.
     17
     18        We also remove redundant checks from trySimpleOperation() methods, where
     19        the test is already done in the Region calling site.
     20
     21        This change improves the performance of the Region overlap testing for
     22        composited layers, and allows us to avoid unnecessary copies of the
     23        Region during unite. With a layout test (attached to bug #81087), that
     24        creates a Region from the union of 225 composited layers, as well as
     25        600 overlapping layers above them, this change decreases the running
     26        time of the test by 3.2% by avoiding a copy of the entire Region for
     27        each insertion that does not change the resulting Region.
     28
     29        Unit tests: RegionTest.unite
     30
     31        * platform/graphics/Region.cpp:
     32        (WebCore::Region::Shape::UnionOperation::trySimpleOperation):
     33        (WebCore::Region::Shape::IntersectOperation::trySimpleOperation):
     34        (WebCore::Region::Shape::SubtractOperation::trySimpleOperation):
     35        (WebCore::Region::intersect):
     36        (WebCore::Region::unite):
     37        (WebCore::Region::subtract):
     38        * platform/graphics/Region.h:
     39        (WebCore::Region::isRect):
     40        (WebCore::Region::Shape::isRect):
     41
    1422012-05-09  Tommy Widenflycht  <tommyw@google.com>
    243
  • trunk/Source/WebCore/platform/graphics/Region.cpp

    r116463 r116538  
    488488        }
    489489       
    490         if (shape2.isEmpty()) {
    491             result = shape1;
    492             return true;
    493         }
    494 
    495490        return false;
    496491    }
     
    510505
    511506struct Region::Shape::IntersectOperation {
    512     static bool trySimpleOperation(const Shape& shape1, const Shape& shape2, Shape& result)
     507    static bool trySimpleOperation(const Shape&, const Shape&, Shape&)
    513508    {
    514         if (shape1.isEmpty()) {
    515             result = Shape();
    516             return true;
    517         }
    518 
    519         if (shape2.isEmpty()) {
    520             result = shape1;
    521             return true;
    522         }
    523        
    524509        return false;
    525510    }
     
    539524
    540525struct Region::Shape::SubtractOperation {
    541     static bool trySimpleOperation(const Shape& shape1, const Shape& shape2, Region::Shape& result)
     526    static bool trySimpleOperation(const Shape&, const Shape&, Region::Shape&)
    542527    {
    543        
    544         if (shape1.isEmpty() || shape2.isEmpty()) {
    545             result = Shape();
    546             return true;
    547         }
    548        
    549528        return false;
    550529    }
     
    574553void Region::intersect(const Region& region)
    575554{
     555    if (m_bounds.isEmpty())
     556        return;
    576557    if (!m_bounds.intersects(region.m_bounds)) {
    577558        m_shape = Shape();
     
    590571    if (region.isEmpty())
    591572        return;
     573    if (isRect() && m_bounds.contains(region.m_bounds))
     574        return;
     575    if (region.isRect() && region.m_bounds.contains(m_bounds)) {
     576        m_shape = region.m_shape;
     577        m_bounds = region.m_bounds;
     578        return;
     579    }
     580    // FIXME: We may want another way to construct a Region without doing this test when we expect it to be false.
     581    if (!isRect() && contains(region))
     582        return;
    592583
    593584    Shape unitedShape = Shape::unionShapes(m_shape, region.m_shape);
     
    599590void Region::subtract(const Region& region)
    600591{
     592    if (m_bounds.isEmpty())
     593        return;
    601594    if (region.isEmpty())
    602595        return;
  • trunk/Source/WebCore/platform/graphics/Region.h

    r116377 r116538  
    3939    IntRect bounds() const { return m_bounds; }
    4040    bool isEmpty() const { return m_bounds.isEmpty(); }
     41    bool isRect() const { return m_shape.isRect(); }
    4142
    4243    Vector<IntRect> rects() const;
     
    8081        IntRect bounds() const;
    8182        bool isEmpty() const { return m_spans.isEmpty(); }
     83        bool isRect() const { return m_spans.size() <= 2 && m_segments.size() <= 2; }
    8284
    8385        typedef const Span* SpanIterator;
  • trunk/Source/WebKit/chromium/ChangeLog

    r116528 r116538  
     12012-05-09  Dana Jansens  <danakj@chromium.org>
     2
     3        Early-out and avoid any copying when possible for Region operations
     4        https://bugs.webkit.org/show_bug.cgi?id=85260
     5
     6        Reviewed by Anders Carlsson.
     7
     8        * tests/RegionTest.cpp:
     9        (WebCore::TEST):
     10        (WebCore):
     11
    1122012-05-09  Tommy Widenflycht  <tommyw@google.com>
    213
  • trunk/Source/WebKit/chromium/tests/RegionTest.cpp

    r116463 r116538  
    363363}
    364364
     365TEST(RegionTest, unite)
     366{
     367    Region r;
     368    Region r2;
     369
     370    // A rect uniting a contained rect does not change the region.
     371    r2 = r = IntRect(0, 0, 50, 50);
     372    r2.unite(IntRect(20, 20, 10, 10));
     373    EXPECT_EQ(r, r2);
     374
     375    // A rect uniting a containing rect gives back the containing rect.
     376    r = IntRect(0, 0, 50, 50);
     377    r.unite(IntRect(0, 0, 100, 100));
     378    EXPECT_EQ(Region(IntRect(0, 0, 100, 100)), r);
     379
     380    // A complex region uniting a contained rect does not change the region.
     381    r = IntRect(0, 0, 50, 50);
     382    r.unite(IntRect(100, 0, 50, 50));
     383    r2 = r;
     384    r2.unite(IntRect(20, 20, 10, 10));
     385    EXPECT_EQ(r, r2);
     386
     387    // A complex region uniting a containing rect gives back the containing rect.
     388    r = IntRect(0, 0, 50, 50);
     389    r.unite(IntRect(100, 0, 50, 50));
     390    r. unite(IntRect(0, 0, 500, 500));
     391    EXPECT_EQ(Region(IntRect(0, 0, 500, 500)), r);
     392}
     393
    365394} // namespace
Note: See TracChangeset for help on using the changeset viewer.