Optimize Region for single rectangle case
authorantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 Mar 2019 15:43:20 +0000 (15:43 +0000)
committerantti@apple.com <antti@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 Mar 2019 15:43:20 +0000 (15:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=195743

Reviewed by Simon Fraser.

Source/WebCore:

Instrumentation shows vast majority of Region objects consist of a single rectangle. However it always allocates
the large Shape data structure. This makes it unsuitable to use as a member in any popular objects.

This patch optimizes the single rectangle case by using only the bounds rectangle to describe it.
Shape is allocated on demand. This makes it safe to use Region as a data member where a rectangle is the common case.

The patch also modernizes Region encoding/decoding support.

* platform/graphics/Region.cpp:
(WebCore::Region::Region):
(WebCore::Region::~Region):
(WebCore::Region::operator=):
(WebCore::Region::rects const):
(WebCore::Region::contains const):
(WebCore::Region::intersects const):
(WebCore::Region::Shape::Shape):
(WebCore::Region::Shape::appendSpan):
(WebCore::Region::dump const):
(WebCore::Region::intersect):
(WebCore::Region::unite):
(WebCore::Region::subtract):
(WebCore::Region::translate):
(WebCore::Region::setShape):
(WebCore::Region::Shape::isValid const): Deleted.
(WebCore::Region::Shape::swap): Deleted.
(WebCore::Region::updateBoundsFromShape): Deleted.

Remove some now unused function.

* platform/graphics/Region.h:
(WebCore::Region::isRect const):
(WebCore::Region::gridSize const):
(WebCore::Region::copyShape const):
(WebCore::operator==):
(WebCore::Region::Span::encode const):
(WebCore::Region::Span::decode):
(WebCore::Region::Shape::encode const):
(WebCore::Region::Shape::decode):
(WebCore::Region::encode const):
(WebCore::Region::decode):

This is now part of type.

(WebCore::Region::isValid const): Deleted.
(WebCore::Region::Span::Span): Deleted.
(WebCore::Region::shapeSegments const): Deleted.
(WebCore::Region::shapeSpans const): Deleted.
(WebCore::Region::setShapeSegments): Deleted.
(WebCore::Region::setShapeSpans): Deleted.
(WebCore::Region::Shape::segments const): Deleted.
(WebCore::Region::Shape::spans const): Deleted.
(WebCore::Region::Shape::setSegments): Deleted.
(WebCore::Region::Shape::setSpans): Deleted.

No need to expose these for encoding anymore.

Source/WebKit:

* Shared/RemoteLayerTree/RemoteLayerTreeTransaction.mm:
(WebKit::RemoteLayerTreeTransaction::LayerProperties::decode):
* Shared/WebCoreArgumentCoders.cpp:
(IPC::ArgumentCoder<EventTrackingRegions>::decode):
(IPC::ArgumentCoder<Region::Span>::encode): Deleted.
(IPC::ArgumentCoder<Region::Span>::decode): Deleted.
(IPC::ArgumentCoder<Region>::encode): Deleted.
(IPC::ArgumentCoder<Region>::decode): Deleted.
* Shared/WebCoreArgumentCoders.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@242995 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/platform/graphics/Region.cpp
Source/WebCore/platform/graphics/Region.h
Source/WebCore/platform/graphics/texmap/TextureMapperLayer.cpp
Source/WebKit/ChangeLog
Source/WebKit/Shared/RemoteLayerTree/RemoteLayerBackingStore.mm
Source/WebKit/Shared/RemoteLayerTree/RemoteLayerTreeTransaction.mm
Source/WebKit/Shared/WebCoreArgumentCoders.cpp
Source/WebKit/Shared/WebCoreArgumentCoders.h
Source/WebKit/UIProcess/win/WebView.cpp
Source/WebKit/WebProcess/WebPage/CoordinatedGraphics/DrawingAreaCoordinatedGraphics.cpp

index 9a33341..7837566 100644 (file)
@@ -1,3 +1,66 @@
+2019-03-15  Antti Koivisto  <antti@apple.com>
+
+        Optimize Region for single rectangle case
+        https://bugs.webkit.org/show_bug.cgi?id=195743
+
+        Reviewed by Simon Fraser.
+
+        Instrumentation shows vast majority of Region objects consist of a single rectangle. However it always allocates
+        the large Shape data structure. This makes it unsuitable to use as a member in any popular objects.
+
+        This patch optimizes the single rectangle case by using only the bounds rectangle to describe it.
+        Shape is allocated on demand. This makes it safe to use Region as a data member where a rectangle is the common case.
+
+        The patch also modernizes Region encoding/decoding support.
+
+        * platform/graphics/Region.cpp:
+        (WebCore::Region::Region):
+        (WebCore::Region::~Region):
+        (WebCore::Region::operator=):
+        (WebCore::Region::rects const):
+        (WebCore::Region::contains const):
+        (WebCore::Region::intersects const):
+        (WebCore::Region::Shape::Shape):
+        (WebCore::Region::Shape::appendSpan):
+        (WebCore::Region::dump const):
+        (WebCore::Region::intersect):
+        (WebCore::Region::unite):
+        (WebCore::Region::subtract):
+        (WebCore::Region::translate):
+        (WebCore::Region::setShape):
+        (WebCore::Region::Shape::isValid const): Deleted.
+        (WebCore::Region::Shape::swap): Deleted.
+        (WebCore::Region::updateBoundsFromShape): Deleted.
+
+        Remove some now unused function.
+
+        * platform/graphics/Region.h:
+        (WebCore::Region::isRect const):
+        (WebCore::Region::gridSize const):
+        (WebCore::Region::copyShape const):
+        (WebCore::operator==):
+        (WebCore::Region::Span::encode const):
+        (WebCore::Region::Span::decode):
+        (WebCore::Region::Shape::encode const):
+        (WebCore::Region::Shape::decode):
+        (WebCore::Region::encode const):
+        (WebCore::Region::decode):
+
+        This is now part of type.
+
+        (WebCore::Region::isValid const): Deleted.
+        (WebCore::Region::Span::Span): Deleted.
+        (WebCore::Region::shapeSegments const): Deleted.
+        (WebCore::Region::shapeSpans const): Deleted.
+        (WebCore::Region::setShapeSegments): Deleted.
+        (WebCore::Region::setShapeSpans): Deleted.
+        (WebCore::Region::Shape::segments const): Deleted.
+        (WebCore::Region::Shape::spans const): Deleted.
+        (WebCore::Region::Shape::setSegments): Deleted.
+        (WebCore::Region::Shape::setSpans): Deleted.
+
+        No need to expose these for encoding anymore.
+
 2019-03-15  Devin Rousso  <drousso@apple.com>
 
         Web Inspector: provide a way to capture a screenshot of a node from within the page
index ce555b7..e464b32 100644 (file)
@@ -42,19 +42,54 @@ Region::Region()
 
 Region::Region(const IntRect& rect)
     : m_bounds(rect)
-    , m_shape(rect)
 {
 }
 
-Vector<IntRect> Region::rects() const
+Region::Region(const Region& other)
+    : m_bounds(other.m_bounds)
+    , m_shape(other.copyShape())
 {
-    Vector<IntRect> rects;
+}
+
+Region::Region(Region&& other)
+    : m_bounds(WTFMove(other.m_bounds))
+    , m_shape(WTFMove(other.m_shape))
+{
+}
+
+Region::~Region()
+{
+}
+
+Region& Region::operator=(const Region& other)
+{
+    m_bounds = other.m_bounds;
+    m_shape = other.copyShape();
+    return *this;
+}
+
+Region& Region::operator=(Region&& other)
+{
+    m_bounds = WTFMove(other.m_bounds);
+    m_shape = WTFMove(other.m_shape);
+    return *this;
+}
+
+Vector<IntRect, 1> Region::rects() const
+{
+    Vector<IntRect, 1> rects;
 
-    for (Shape::SpanIterator span = m_shape.spans_begin(), end = m_shape.spans_end(); span != end && span + 1 != end; ++span) {
+    if (!m_shape) {
+        if (!m_bounds.isEmpty())
+            rects.uncheckedAppend(m_bounds);
+        return rects;
+    }
+
+    for (Shape::SpanIterator span = m_shape->spans_begin(), end = m_shape->spans_end(); span != end && span + 1 != end; ++span) {
         int y = span->y;
         int height = (span + 1)->y - y;
 
-        for (Shape::SegmentIterator segment = m_shape.segments_begin(span), end = m_shape.segments_end(span); segment != end && segment + 1 != end; segment += 2) {
+        for (Shape::SegmentIterator segment = m_shape->segments_begin(span), end = m_shape->segments_end(span); segment != end && segment + 1 != end; segment += 2) {
             int x = *segment;
             int width = *(segment + 1) - x;
 
@@ -70,7 +105,10 @@ bool Region::contains(const Region& region) const
     if (!m_bounds.contains(region.m_bounds))
         return false;
 
-    return Shape::compareShapes<Shape::CompareContainsOperation>(m_shape, region.m_shape);
+    if (!m_shape)
+        return true;
+
+    return Shape::compareShapes<Shape::CompareContainsOperation>(*m_shape, region.m_shape ? *region.m_shape : Shape(region.m_bounds));
 }
 
 bool Region::contains(const IntPoint& point) const
@@ -78,7 +116,10 @@ bool Region::contains(const IntPoint& point) const
     if (!m_bounds.contains(point))
         return false;
 
-    for (Shape::SpanIterator span = m_shape.spans_begin(), end = m_shape.spans_end(); span != end && span + 1 != end; ++span) {
+    if (!m_shape)
+        return true;
+
+    for (Shape::SpanIterator span = m_shape->spans_begin(), end = m_shape->spans_end(); span != end && span + 1 != end; ++span) {
         int y = span->y;
         int maxY = (span + 1)->y;
 
@@ -87,7 +128,7 @@ bool Region::contains(const IntPoint& point) const
         if (maxY <= point.y())
             continue;
 
-        for (Shape::SegmentIterator segment = m_shape.segments_begin(span), end = m_shape.segments_end(span); segment != end && segment + 1 != end; segment += 2) {
+        for (Shape::SegmentIterator segment = m_shape->segments_begin(span), end = m_shape->segments_end(span); segment != end && segment + 1 != end; segment += 2) {
             int x = *segment;
             int maxX = *(segment + 1);
 
@@ -106,19 +147,18 @@ bool Region::intersects(const Region& region) const
     if (!m_bounds.intersects(region.m_bounds))
         return false;
 
-    return Shape::compareShapes<Shape::CompareIntersectsOperation>(m_shape, region.m_shape);
+    if (!m_shape && !region.m_shape)
+        return true;
+
+    return Shape::compareShapes<Shape::CompareIntersectsOperation>(m_shape ? *m_shape : m_bounds, region.m_shape ? *region.m_shape : region.m_bounds);
 }
 
-unsigned Region::totalArea() const
+uint64_t Region::totalArea() const
 {
-    Vector<IntRect> rects = this->rects();
-    size_t size = rects.size();
-    unsigned totalArea = 0;
+    uint64_t totalArea = 0;
 
-    for (size_t i = 0; i < size; ++i) {
-        IntRect rect = rects[i];
+    for (auto& rect : rects())
         totalArea += (rect.width() * rect.height());
-    }
 
     return totalArea;
 }
@@ -221,21 +261,15 @@ struct Region::Shape::CompareIntersectsOperation {
     inline static bool aOverlapsB(bool& result) { result = true; return true; }
 };
 
-Region::Shape::Shape()
-{
-}
-
 Region::Shape::Shape(const IntRect& rect)
+    : m_segments({ rect.x(), rect.maxX() })
+    , m_spans({ { rect.y(), 0 }, { rect.maxY(), 2 } })
 {
-    appendSpan(rect.y());
-    appendSegment(rect.x());
-    appendSegment(rect.maxX());
-    appendSpan(rect.maxY());
 }
 
 void Region::Shape::appendSpan(int y)
 {
-    m_spans.append(Span(y, m_segments.size()));
+    m_spans.append({ y, m_segments.size() });
 }
 
 bool Region::Shape::canCoalesce(SegmentIterator begin, SegmentIterator end)
@@ -331,27 +365,6 @@ void Region::Shape::dump() const
 }
 #endif
 
-bool Region::Shape::isValid() const
-{
-    for (auto span = spans_begin(), end = spans_end(); span != end && span + 1 != end; ++span) {
-        int y = span->y;
-        int height = (span + 1)->y - y;
-        
-        if (height < 0)
-            return false;
-
-        for (auto segment = segments_begin(span), end = segments_end(span); segment != end && segment + 1 != end; segment += 2) {
-            int x = *segment;
-            int width = *(segment + 1) - x;
-            
-            if (width < 0)
-                return false;
-        }
-    }
-
-    return true;
-}
-
 IntRect Region::Shape::bounds() const
 {
     if (isEmpty())
@@ -397,12 +410,6 @@ void Region::Shape::translate(const IntSize& offset)
         m_spans[i].y += offset.height();
 }
 
-void Region::Shape::swap(Shape& other)
-{
-    m_segments.swap(other.m_segments);
-    m_spans.swap(other.m_spans);
-}
-
 enum {
     Shape1,
     Shape2,
@@ -567,71 +574,81 @@ void Region::dump() const
 {
     printf("Bounds: (%d, %d, %d, %d)\n",
            m_bounds.x(), m_bounds.y(), m_bounds.width(), m_bounds.height());
-    m_shape.dump();
+    if (m_shape)
+        m_shape->dump();
 }
 #endif
 
-void Region::updateBoundsFromShape()
-{
-    m_bounds = m_shape.bounds();
-}
-
 void Region::intersect(const Region& region)
 {
     if (m_bounds.isEmpty())
         return;
     if (!m_bounds.intersects(region.m_bounds)) {
-        m_shape = Shape();
+        m_shape = nullptr;
         m_bounds = IntRect();
         return;
     }
+    if (!m_shape && !region.m_shape) {
+        m_bounds = intersection(m_bounds, region.m_bounds);
+        return;
+    }
 
-    Shape intersectedShape = Shape::intersectShapes(m_shape, region.m_shape);
-
-    m_shape.swap(intersectedShape);
-    m_bounds = m_shape.bounds();
+    setShape(Shape::intersectShapes(m_shape ? *m_shape : m_bounds, region.m_shape ? *region.m_shape : region.m_bounds));
 }
 
 void Region::unite(const Region& region)
 {
     if (region.isEmpty())
         return;
-    if (isRect() && m_bounds.contains(region.m_bounds))
+    if (isEmpty()) {
+        m_bounds = region.m_bounds;
+        m_shape = region.copyShape();
         return;
+    }
     if (region.isRect() && region.m_bounds.contains(m_bounds)) {
-        m_shape = region.m_shape;
         m_bounds = region.m_bounds;
+        m_shape = nullptr;
         return;
     }
-    // FIXME: We may want another way to construct a Region without doing this test when we expect it to be false.
-    if (!isRect() && contains(region))
+    if (contains(region))
         return;
 
-    Shape unitedShape = Shape::unionShapes(m_shape, region.m_shape);
-
-    m_shape.swap(unitedShape);
-    m_bounds.unite(region.m_bounds);
+    setShape(Shape::unionShapes(m_shape ? *m_shape : m_bounds, region.m_shape ? *region.m_shape : region.m_bounds));
 }
 
 void Region::subtract(const Region& region)
 {
-    if (m_bounds.isEmpty())
+    if (isEmpty())
         return;
     if (region.isEmpty())
         return;
     if (!m_bounds.intersects(region.m_bounds))
         return;
 
-    Shape subtractedShape = Shape::subtractShapes(m_shape, region.m_shape);
-
-    m_shape.swap(subtractedShape);
-    m_bounds = m_shape.bounds();
+    setShape(Shape::subtractShapes(m_shape ? *m_shape : m_bounds, region.m_shape ? *region.m_shape : region.m_bounds));
 }
 
 void Region::translate(const IntSize& offset)
 {
     m_bounds.move(offset);
-    m_shape.translate(offset);
+    if (m_shape)
+        m_shape->translate(offset);
 }
 
+void Region::setShape(Shape&& shape)
+{
+    m_bounds = shape.bounds();
+
+    if (shape.isRect()) {
+        m_shape = nullptr;
+        return;
+    }
+
+    if (!m_shape)
+        m_shape = std::make_unique<Shape>(WTFMove(shape));
+    else
+        *m_shape = WTFMove(shape);
+}
+
+
 } // namespace WebCore
index b5b2db2..382a331 100644 (file)
@@ -27,6 +27,8 @@
 #define Region_h
 
 #include "IntRect.h"
+#include <wtf/Optional.h>
+#include <wtf/PointerComparison.h>
 #include <wtf/Vector.h>
 
 namespace WebCore {
@@ -38,11 +40,19 @@ public:
     WEBCORE_EXPORT Region();
     WEBCORE_EXPORT Region(const IntRect&);
 
+    WEBCORE_EXPORT Region(const Region&);
+    WEBCORE_EXPORT Region(Region&&);
+
+    WEBCORE_EXPORT ~Region();
+
+    WEBCORE_EXPORT Region& operator=(const Region&);
+    WEBCORE_EXPORT Region& operator=(Region&&);
+
     IntRect bounds() const { return m_bounds; }
     bool isEmpty() const { return m_bounds.isEmpty(); }
-    bool isRect() const { return m_shape.isRect(); }
+    bool isRect() const { return !m_shape; }
 
-    WEBCORE_EXPORT Vector<IntRect> rects() const;
+    WEBCORE_EXPORT Vector<IntRect, 1> rects() const;
 
     WEBCORE_EXPORT void unite(const Region&);
     WEBCORE_EXPORT void intersect(const Region&);
@@ -58,48 +68,31 @@ public:
     // Returns true if the query region intersects any part of this region.
     WEBCORE_EXPORT bool intersects(const Region&) const;
 
-    WEBCORE_EXPORT unsigned totalArea() const;
+    WEBCORE_EXPORT uint64_t totalArea() const;
 
-    unsigned gridSize() const { return m_shape.gridSize(); }
+    unsigned gridSize() const { return m_shape ? m_shape->gridSize() : 0; }
 
 #ifndef NDEBUG
     void dump() const;
 #endif
 
-    bool isValid() const { return m_shape.isValid(); }
+    template<class Encoder> void encode(Encoder&) const;
+    template<class Decoder> static Optional<Region> decode(Decoder&);
+    // FIXME: Remove legacy decode.
+    template<class Decoder> static bool decode(Decoder&, Region&);
 
-    // This is internal to Region, but exposed just for encoding.
-    // FIXME: figure out a better way to encode WebCore classes.
+private:
     struct Span {
-        Span()
-            : y(0)
-            , segmentIndex(0)
-        {
-        }
-
-        Span(int y, size_t segmentIndex)
-            : y(y)
-            , segmentIndex(segmentIndex)
-        {
-        }
-
-        int y;
-        size_t segmentIndex;
-    };
+        int y { 0 };
+        size_t segmentIndex { 0 };
 
-    // For encoding/decoding only.
-    const Vector<int, 32>& shapeSegments() const { return m_shape.segments(); }
-    const Vector<Span, 16>& shapeSpans() const { return m_shape.spans(); }
-
-    void setShapeSegments(const Vector<int>& segments) { m_shape.setSegments(segments); }
-    void setShapeSpans(const Vector<Span>& spans) { m_shape.setSpans(spans); }
-    WEBCORE_EXPORT void updateBoundsFromShape();
-
-private:
+        template<class Encoder> void encode(Encoder&) const;
+        template<class Decoder> static Optional<Span> decode(Decoder&);
+    };
 
     class Shape {
     public:
-        Shape();
+        Shape() = default;
         Shape(const IntRect&);
 
         IntRect bounds() const;
@@ -120,22 +113,15 @@ private:
         static Shape subtractShapes(const Shape& shape1, const Shape& shape2);
 
         WEBCORE_EXPORT void translate(const IntSize&);
-        void swap(Shape&);
 
         struct CompareContainsOperation;
         struct CompareIntersectsOperation;
 
         template<typename CompareOperation>
         static bool compareShapes(const Shape& shape1, const Shape& shape2);
-        
-        WEBCORE_EXPORT bool isValid() const;
 
-        // For encoding/decoding only.
-        const Vector<int, 32>& segments() const { return m_segments; }
-        const Vector<Span, 16>& spans() const { return m_spans; }
-
-        void setSegments(const Vector<int>& segments) { m_segments = segments; }
-        void setSpans(const Vector<Span>& spans) { m_spans = spans; }
+        template<class Encoder> void encode(Encoder&) const;
+        template<class Decoder> static Optional<Shape> decode(Decoder&);
 
 #ifndef NDEBUG
         void dump() const;
@@ -162,12 +148,16 @@ private:
         friend bool operator==(const Shape&, const Shape&);
     };
 
+    std::unique_ptr<Shape> copyShape() const { return m_shape ? std::make_unique<Shape>(*m_shape) : nullptr; }
+    void setShape(Shape&&);
+
     IntRect m_bounds;
-    Shape m_shape;
+    std::unique_ptr<Shape> m_shape;
 
     friend bool operator==(const Region&, const Region&);
     friend bool operator==(const Shape&, const Shape&);
     friend bool operator==(const Span&, const Span&);
+    friend bool operator!=(const Span&, const Span&);
 };
 
 static inline Region intersect(const Region& a, const Region& b)
@@ -177,7 +167,7 @@ static inline Region intersect(const Region& a, const Region& b)
 
     return result;
 }
-    
+
 static inline Region subtract(const Region& a, const Region& b)
 {
     Region result(a);
@@ -196,7 +186,7 @@ static inline Region translate(const Region& region, const IntSize& offset)
 
 inline bool operator==(const Region& a, const Region& b)
 {
-    return a.m_bounds == b.m_bounds && a.m_shape == b.m_shape;
+    return a.m_bounds == b.m_bounds && arePointingToEqualData(a.m_shape, b.m_shape);
 }
 inline bool operator!=(const Region& a, const Region& b)
 {
@@ -212,11 +202,108 @@ inline bool operator==(const Region::Span& a, const Region::Span& b)
 {
     return a.y == b.y && a.segmentIndex == b.segmentIndex;
 }
+
 inline bool operator!=(const Region::Span& a, const Region::Span& b)
 {
     return !(a == b);
 }
 
+template<class Encoder>
+void Region::Span::encode(Encoder& encoder) const
+{
+    encoder << y << static_cast<uint64_t>(segmentIndex);
+}
+
+template<class Decoder>
+Optional<Region::Span> Region::Span::decode(Decoder& decoder)
+{
+    Optional<int> y;
+    decoder >> y;
+    if (!y)
+        return { };
+
+    Optional<uint64_t> segmentIndex;
+    decoder >> segmentIndex;
+    if (!segmentIndex)
+        return { };
+
+    return { { *y, *segmentIndex } };
+}
+
+template<class Encoder>
+void Region::Shape::encode(Encoder& encoder) const
+{
+    encoder << m_segments;
+    encoder << m_spans;
+}
+
+template<class Decoder>
+Optional<Region::Shape> Region::Shape::decode(Decoder& decoder)
+{
+    Optional<Vector<int>> segments;
+    decoder >> segments;
+    if (!segments)
+        return WTF::nullopt;
+
+    Optional<Vector<Region::Span>> spans;
+    decoder >> spans;
+    if (!spans)
+        return WTF::nullopt;
+
+    Shape shape;
+    shape.m_segments = WTFMove(*segments);
+    shape.m_spans = WTFMove(*spans);
+
+    return { shape };
+}
+
+template<class Encoder>
+void Region::encode(Encoder& encoder) const
+{
+    encoder << m_bounds;
+    bool hasShape = !!m_shape;
+    encoder << hasShape;
+    if (hasShape)
+        encoder << *m_shape;
+}
+
+template<class Decoder>
+Optional<Region> Region::decode(Decoder& decoder)
+{
+    Optional<IntRect> bounds;
+    decoder >> bounds;
+    if (!bounds)
+        return WTF::nullopt;
+
+    Optional<bool> hasShape;
+    decoder >> hasShape;
+    if (!hasShape)
+        return WTF::nullopt;
+
+    Region region = { *bounds };
+
+    if (*hasShape) {
+        Optional<Shape> shape;
+        decoder >> shape;
+        if (!shape)
+            return WTF::nullopt;
+        region.m_shape = std::make_unique<Shape>(WTFMove(*shape));
+    }
+
+    return { region };
+}
+
+template<class Decoder>
+bool Region::decode(Decoder& decoder, Region& region)
+{
+    Optional<Region> decodedRegion;
+    decoder >> decodedRegion;
+    if (!decodedRegion)
+        return false;
+    region = WTFMove(*decodedRegion);
+    return true;
+}
+
 } // namespace WebCore
 
 #endif // Region_h
index f1b14d8..5e9c56b 100644 (file)
@@ -335,7 +335,7 @@ void TextureMapperLayer::paintUsingOverlapRegions(const TextureMapperPaintOption
     }
 
     nonOverlapRegion.translate(options.offset);
-    Vector<IntRect> rects = nonOverlapRegion.rects();
+    auto rects = nonOverlapRegion.rects();
 
     for (auto& rect : rects) {
         if (!rect.intersects(options.textureMapper.clipBounds()))
index 0300aca..f005fe1 100644 (file)
@@ -1,3 +1,20 @@
+2019-03-15  Antti Koivisto  <antti@apple.com>
+
+        Optimize Region for single rectangle case
+        https://bugs.webkit.org/show_bug.cgi?id=195743
+
+        Reviewed by Simon Fraser.
+
+        * Shared/RemoteLayerTree/RemoteLayerTreeTransaction.mm:
+        (WebKit::RemoteLayerTreeTransaction::LayerProperties::decode):
+        * Shared/WebCoreArgumentCoders.cpp:
+        (IPC::ArgumentCoder<EventTrackingRegions>::decode):
+        (IPC::ArgumentCoder<Region::Span>::encode): Deleted.
+        (IPC::ArgumentCoder<Region::Span>::decode): Deleted.
+        (IPC::ArgumentCoder<Region>::encode): Deleted.
+        (IPC::ArgumentCoder<Region>::decode): Deleted.
+        * Shared/WebCoreArgumentCoders.h:
+
 2019-03-14  Per Arne Vollan  <pvollan@apple.com>
 
         [iOS] WebKit crashes when opening pages documents
index 0eba0d0..b601547 100644 (file)
@@ -298,7 +298,7 @@ void RemoteLayerBackingStore::drawInContext(WebCore::GraphicsContext& context, C
     // Otherwise, repaint the entire bounding box of the dirty region.
     WebCore::IntRect dirtyBounds = m_dirtyRegion.bounds();
 
-    Vector<WebCore::IntRect> dirtyRects = m_dirtyRegion.rects();
+    auto dirtyRects = m_dirtyRegion.rects();
     if (dirtyRects.size() > WebCore::PlatformCALayer::webLayerMaxRectsToPaint || m_dirtyRegion.totalArea() > WebCore::PlatformCALayer::webLayerWastedSpaceThreshold * dirtyBounds.width() * dirtyBounds.height()) {
         dirtyRects.clear();
         dirtyRects.append(dirtyBounds);
index d99dddc..0e40244 100644 (file)
@@ -515,10 +515,11 @@ bool RemoteLayerTreeTransaction::LayerProperties::decode(IPC::Decoder& decoder,
         if (!decoder.decode(hasEventRegion))
             return false;
         if (hasEventRegion) {
-            auto eventRegion = std::make_unique<WebCore::Region>();
-            if (!decoder.decode(*eventRegion))
+            Optional<WebCore::Region> eventRegion;
+            decoder >> eventRegion;
+            if (!eventRegion)
                 return false;
-            result.eventRegion = WTFMove(eventRegion);
+            result.eventRegion = std::make_unique<Region>(WTFMove(*eventRegion));
         }
     }
 
index 23028dc..398d3ff 100644 (file)
@@ -367,8 +367,9 @@ void ArgumentCoder<EventTrackingRegions>::encode(Encoder& encoder, const EventTr
 
 bool ArgumentCoder<EventTrackingRegions>::decode(Decoder& decoder, EventTrackingRegions& eventTrackingRegions)
 {
-    Region asynchronousDispatchRegion;
-    if (!decoder.decode(asynchronousDispatchRegion))
+    Optional<Region> asynchronousDispatchRegion;
+    decoder >> asynchronousDispatchRegion;
+    if (!asynchronousDispatchRegion)
         return false;
     HashMap<String, Region> eventSpecificSynchronousDispatchRegions;
     if (!decoder.decode(eventSpecificSynchronousDispatchRegions))
@@ -378,7 +379,7 @@ bool ArgumentCoder<EventTrackingRegions>::decode(Decoder& decoder, EventTracking
     if (!decoder.decode(touchActionData))
         return false;
 #endif
-    eventTrackingRegions.asynchronousDispatchRegion = WTFMove(asynchronousDispatchRegion);
+    eventTrackingRegions.asynchronousDispatchRegion = WTFMove(*asynchronousDispatchRegion);
     eventTrackingRegions.eventSpecificSynchronousDispatchRegions = WTFMove(eventSpecificSynchronousDispatchRegions);
 #if ENABLE(POINTER_EVENTS)
     eventTrackingRegions.touchActionData = WTFMove(touchActionData);
@@ -902,66 +903,6 @@ Optional<RecentSearch> ArgumentCoder<RecentSearch>::decode(Decoder& decoder)
     return {{ WTFMove(*string), WTFMove(*time) }};
 }
 
-template<> struct ArgumentCoder<Region::Span> {
-    static void encode(Encoder&, const Region::Span&);
-    static Optional<Region::Span> decode(Decoder&);
-};
-
-void ArgumentCoder<Region::Span>::encode(Encoder& encoder, const Region::Span& span)
-{
-    encoder << span.y;
-    encoder << (uint64_t)span.segmentIndex;
-}
-
-Optional<Region::Span> ArgumentCoder<Region::Span>::decode(Decoder& decoder)
-{
-    Region::Span span;
-    if (!decoder.decode(span.y))
-        return WTF::nullopt;
-    
-    uint64_t segmentIndex;
-    if (!decoder.decode(segmentIndex))
-        return WTF::nullopt;
-    
-    span.segmentIndex = segmentIndex;
-    return WTFMove(span);
-}
-
-void ArgumentCoder<Region>::encode(Encoder& encoder, const Region& region)
-{
-    encoder.encode(region.shapeSegments());
-    encoder.encode(region.shapeSpans());
-}
-
-bool ArgumentCoder<Region>::decode(Decoder& decoder, Region& region)
-{
-    Vector<int> segments;
-    if (!decoder.decode(segments))
-        return false;
-
-    Vector<Region::Span> spans;
-    if (!decoder.decode(spans))
-        return false;
-    
-    region.setShapeSegments(segments);
-    region.setShapeSpans(spans);
-    region.updateBoundsFromShape();
-    
-    if (!region.isValid())
-        return false;
-
-    return true;
-}
-
-Optional<Region> ArgumentCoder<Region>::decode(Decoder& decoder)
-{
-    Region region;
-    if (!decode(decoder, region))
-        return WTF::nullopt;
-
-    return region;
-}
-
 void ArgumentCoder<Length>::encode(Encoder& encoder, const Length& length)
 {
     SimpleArgumentCoder<Length>::encode(encoder, length);
@@ -972,7 +913,6 @@ bool ArgumentCoder<Length>::decode(Decoder& decoder, Length& length)
     return SimpleArgumentCoder<Length>::decode(decoder, length);
 }
 
-
 void ArgumentCoder<ViewportAttributes>::encode(Encoder& encoder, const ViewportAttributes& viewportAttributes)
 {
     SimpleArgumentCoder<ViewportAttributes>::encode(encoder, viewportAttributes);
index 99fa2fe..0bdb9c7 100644 (file)
@@ -324,12 +324,6 @@ template<> struct ArgumentCoder<WebCore::Path> {
     static Optional<WebCore::Path> decode(Decoder&);
 };
 
-template<> struct ArgumentCoder<WebCore::Region> {
-    static void encode(Encoder&, const WebCore::Region&);
-    static bool decode(Decoder&, WebCore::Region&);
-    static Optional<WebCore::Region> decode(Decoder&);
-};
-
 template<> struct ArgumentCoder<WebCore::Length> {
     static void encode(Encoder&, const WebCore::Length&);
     static bool decode(Decoder&, WebCore::Length&);
index 450a06d..a88258b 100644 (file)
@@ -474,7 +474,7 @@ void WebView::paint(HDC hdc, const IntRect& dirtyRect)
         cairo_destroy(context);
         cairo_surface_destroy(surface);
 
-        Vector<IntRect> unpaintedRects = unpaintedRegion.rects();
+        auto unpaintedRects = unpaintedRegion.rects();
         for (auto& rect : unpaintedRects)
             drawPageBackground(hdc, m_page.get(), rect);
     } else
index c97e253..2e60e97 100644 (file)
@@ -676,7 +676,7 @@ void DrawingAreaCoordinatedGraphics::display()
     m_isWaitingForDidUpdate = true;
 }
 
-static bool shouldPaintBoundsRect(const IntRect& bounds, const Vector<IntRect>& rects)
+static bool shouldPaintBoundsRect(const IntRect& bounds, const Vector<IntRect, 1>& rects)
 {
     const size_t rectThreshold = 10;
     const double wastedSpaceThreshold = 0.75;
@@ -728,7 +728,7 @@ void DrawingAreaCoordinatedGraphics::display(UpdateInfo& updateInfo)
     if (!bitmap->createHandle(updateInfo.bitmapHandle))
         return;
 
-    Vector<IntRect> rects = m_dirtyRegion.rects();
+    auto rects = m_dirtyRegion.rects();
     if (shouldPaintBoundsRect(bounds, rects)) {
         rects.clear();
         rects.append(bounds);