Commit 864fa557 authored by Adrienne Walker's avatar Adrienne Walker Committed by Commit Bot

cc: Add PaintCanvas::clipDeviceRect

Instead of having to serialize SkRegion (as clipRegion is the only call
that needs a region), instead add a top level "clip device rect" that
takes two parameters.  This is to support the use case that the
RasterSource canvas setup preamble uses to clear the canvas efficiently.

Bug: 737629
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel
Change-Id: Icfb41557c716d5c52ef44454b8791e29c36d5bda
Reviewed-on: https://chromium-review.googlesource.com/590950Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Reviewed-by: default avatarVladimir Levin <vmpstr@chromium.org>
Commit-Queue: enne <enne@chromium.org>
Cr-Commit-Position: refs/heads/master@{#491159}
parent 6951d59b
...@@ -85,6 +85,11 @@ class CC_PAINT_EXPORT PaintCanvas { ...@@ -85,6 +85,11 @@ class CC_PAINT_EXPORT PaintCanvas {
void clipPath(const SkPath& path, bool do_anti_alias) { void clipPath(const SkPath& path, bool do_anti_alias) {
clipPath(path, SkClipOp::kIntersect, do_anti_alias); clipPath(path, SkClipOp::kIntersect, do_anti_alias);
} }
// Clip a |device_rect| in canvas device space (subtracting out the
// |subtract_rect|, if non-empty, from that rect).
virtual void clipDeviceRect(const SkIRect& device_rect,
const SkIRect& subtract_rect,
SkClipOp op) = 0;
virtual bool quickReject(const SkRect& rect) const = 0; virtual bool quickReject(const SkRect& rect) const = 0;
virtual bool quickReject(const SkPath& path) const = 0; virtual bool quickReject(const SkPath& path) const = 0;
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "cc/paint/paint_record.h" #include "cc/paint/paint_record.h"
#include "third_party/skia/include/core/SkAnnotation.h" #include "third_party/skia/include/core/SkAnnotation.h"
#include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkRegion.h"
namespace cc { namespace cc {
namespace { namespace {
...@@ -165,6 +166,7 @@ void RasterWithAlpha(const PaintOp* op, ...@@ -165,6 +166,7 @@ void RasterWithAlpha(const PaintOp* op,
#define TYPES(M) \ #define TYPES(M) \
M(AnnotateOp) \ M(AnnotateOp) \
M(ClipDeviceRectOp) \
M(ClipPathOp) \ M(ClipPathOp) \
M(ClipRectOp) \ M(ClipRectOp) \
M(ClipRRectOp) \ M(ClipRRectOp) \
...@@ -327,6 +329,8 @@ std::string PaintOpTypeToString(PaintOpType type) { ...@@ -327,6 +329,8 @@ std::string PaintOpTypeToString(PaintOpType type) {
switch (type) { switch (type) {
case PaintOpType::Annotate: case PaintOpType::Annotate:
return "Annotate"; return "Annotate";
case PaintOpType::ClipDeviceRect:
return "ClipDeviceRect";
case PaintOpType::ClipPath: case PaintOpType::ClipPath:
return "ClipPath"; return "ClipPath";
case PaintOpType::ClipRect: case PaintOpType::ClipRect:
...@@ -413,6 +417,13 @@ size_t AnnotateOp::Serialize(const PaintOp* base_op, ...@@ -413,6 +417,13 @@ size_t AnnotateOp::Serialize(const PaintOp* base_op,
return helper.size(); return helper.size();
} }
size_t ClipDeviceRectOp::Serialize(const PaintOp* op,
void* memory,
size_t size,
const SerializeOptions& options) {
return SimpleSerialize<ClipDeviceRectOp>(op, memory, size);
}
size_t ClipPathOp::Serialize(const PaintOp* base_op, size_t ClipPathOp::Serialize(const PaintOp* base_op,
void* memory, void* memory,
size_t size, size_t size,
...@@ -748,6 +759,14 @@ PaintOp* AnnotateOp::Deserialize(const void* input, ...@@ -748,6 +759,14 @@ PaintOp* AnnotateOp::Deserialize(const void* input,
return op; return op;
} }
PaintOp* ClipDeviceRectOp::Deserialize(const void* input,
size_t input_size,
void* output,
size_t output_size) {
return SimpleDeserialize<ClipDeviceRectOp>(input, input_size, output,
output_size);
}
PaintOp* ClipPathOp::Deserialize(const void* input, PaintOp* ClipPathOp::Deserialize(const void* input,
size_t input_size, size_t input_size,
void* output, void* output,
...@@ -1195,6 +1214,16 @@ void AnnotateOp::Raster(const AnnotateOp* op, ...@@ -1195,6 +1214,16 @@ void AnnotateOp::Raster(const AnnotateOp* op,
} }
} }
void ClipDeviceRectOp::Raster(const ClipDeviceRectOp* op,
SkCanvas* canvas,
const PlaybackParams& params) {
SkRegion device_region;
device_region.setRect(op->device_rect);
if (!op->subtract_rect.isEmpty())
device_region.op(op->subtract_rect, SkRegion::kDifference_Op);
canvas->clipRegion(device_region, op->op);
}
void ClipPathOp::Raster(const ClipPathOp* op, void ClipPathOp::Raster(const ClipPathOp* op,
SkCanvas* canvas, SkCanvas* canvas,
const PlaybackParams& params) { const PlaybackParams& params) {
......
...@@ -57,6 +57,7 @@ class CC_PAINT_EXPORT ThreadsafePath : public SkPath { ...@@ -57,6 +57,7 @@ class CC_PAINT_EXPORT ThreadsafePath : public SkPath {
enum class PaintOpType : uint8_t { enum class PaintOpType : uint8_t {
Annotate, Annotate,
ClipDeviceRect,
ClipPath, ClipPath,
ClipRect, ClipRect,
ClipRRect, ClipRRect,
...@@ -342,6 +343,23 @@ class CC_PAINT_EXPORT AnnotateOp final : public PaintOp { ...@@ -342,6 +343,23 @@ class CC_PAINT_EXPORT AnnotateOp final : public PaintOp {
AnnotateOp(); AnnotateOp();
}; };
class CC_PAINT_EXPORT ClipDeviceRectOp final : public PaintOp {
public:
static constexpr PaintOpType kType = PaintOpType::ClipDeviceRect;
ClipDeviceRectOp(const SkIRect& device_rect,
const SkIRect& subtract_rect,
SkClipOp op)
: device_rect(device_rect), subtract_rect(subtract_rect), op(op) {}
static void Raster(const ClipDeviceRectOp* op,
SkCanvas* canvas,
const PlaybackParams& params);
HAS_SERIALIZATION_FUNCTIONS();
SkIRect device_rect;
SkIRect subtract_rect;
SkClipOp op;
};
class CC_PAINT_EXPORT ClipPathOp final : public PaintOp { class CC_PAINT_EXPORT ClipPathOp final : public PaintOp {
public: public:
static constexpr PaintOpType kType = PaintOpType::ClipPath; static constexpr PaintOpType kType = PaintOpType::ClipPath;
......
...@@ -1360,6 +1360,13 @@ void PushAnnotateOps(PaintOpBuffer* buffer) { ...@@ -1360,6 +1360,13 @@ void PushAnnotateOps(PaintOpBuffer* buffer) {
test_rects[2], SkData::MakeEmpty()); test_rects[2], SkData::MakeEmpty());
} }
void PushClipDeviceRectOps(PaintOpBuffer* buffer) {
for (size_t i = 1; i < test_irects.size(); i += 2) {
SkClipOp op = i % 3 ? SkClipOp::kDifference : SkClipOp::kIntersect;
buffer->push<ClipDeviceRectOp>(test_irects[i - 1], test_irects[0], op);
}
}
void PushClipPathOps(PaintOpBuffer* buffer) { void PushClipPathOps(PaintOpBuffer* buffer) {
for (size_t i = 0; i < test_paths.size(); ++i) { for (size_t i = 0; i < test_paths.size(); ++i) {
SkClipOp op = i % 3 ? SkClipOp::kDifference : SkClipOp::kIntersect; SkClipOp op = i % 3 ? SkClipOp::kDifference : SkClipOp::kIntersect;
...@@ -1601,6 +1608,13 @@ void CompareAnnotateOp(const AnnotateOp* original, const AnnotateOp* written) { ...@@ -1601,6 +1608,13 @@ void CompareAnnotateOp(const AnnotateOp* original, const AnnotateOp* written) {
} }
} }
void CompareClipDeviceRectOp(const ClipDeviceRectOp* original,
const ClipDeviceRectOp* written) {
EXPECT_EQ(original->device_rect, written->device_rect);
EXPECT_EQ(original->subtract_rect, written->subtract_rect);
EXPECT_EQ(original->op, written->op);
}
void CompareClipPathOp(const ClipPathOp* original, const ClipPathOp* written) { void CompareClipPathOp(const ClipPathOp* original, const ClipPathOp* written) {
EXPECT_TRUE(original->path == written->path); EXPECT_TRUE(original->path == written->path);
EXPECT_EQ(original->op, written->op); EXPECT_EQ(original->op, written->op);
...@@ -1813,6 +1827,9 @@ class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> { ...@@ -1813,6 +1827,9 @@ class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> {
case PaintOpType::Annotate: case PaintOpType::Annotate:
PushAnnotateOps(&buffer_); PushAnnotateOps(&buffer_);
break; break;
case PaintOpType::ClipDeviceRect:
PushClipDeviceRectOps(&buffer_);
break;
case PaintOpType::ClipPath: case PaintOpType::ClipPath:
PushClipPathOps(&buffer_); PushClipPathOps(&buffer_);
break; break;
...@@ -1914,6 +1931,10 @@ class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> { ...@@ -1914,6 +1931,10 @@ class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> {
CompareAnnotateOp(static_cast<const AnnotateOp*>(original), CompareAnnotateOp(static_cast<const AnnotateOp*>(original),
static_cast<const AnnotateOp*>(written)); static_cast<const AnnotateOp*>(written));
break; break;
case PaintOpType::ClipDeviceRect:
CompareClipDeviceRectOp(static_cast<const ClipDeviceRectOp*>(original),
static_cast<const ClipDeviceRectOp*>(written));
break;
case PaintOpType::ClipPath: case PaintOpType::ClipPath:
CompareClipPathOp(static_cast<const ClipPathOp*>(original), CompareClipPathOp(static_cast<const ClipPathOp*>(original),
static_cast<const ClipPathOp*>(written)); static_cast<const ClipPathOp*>(written));
......
...@@ -164,6 +164,12 @@ void RecordPaintCanvas::clipPath(const SkPath& path, ...@@ -164,6 +164,12 @@ void RecordPaintCanvas::clipPath(const SkPath& path,
return; return;
} }
void RecordPaintCanvas::clipDeviceRect(const SkIRect& device_rect,
const SkIRect& subtract_rect,
SkClipOp op) {
list_->push<ClipDeviceRectOp>(device_rect, subtract_rect, op);
}
bool RecordPaintCanvas::quickReject(const SkRect& rect) const { bool RecordPaintCanvas::quickReject(const SkRect& rect) const {
return GetCanvas()->quickReject(rect); return GetCanvas()->quickReject(rect);
} }
......
...@@ -50,6 +50,9 @@ class CC_PAINT_EXPORT RecordPaintCanvas final : public PaintCanvas { ...@@ -50,6 +50,9 @@ class CC_PAINT_EXPORT RecordPaintCanvas final : public PaintCanvas {
void clipRect(const SkRect& rect, SkClipOp op, bool antialias) override; void clipRect(const SkRect& rect, SkClipOp op, bool antialias) override;
void clipRRect(const SkRRect& rrect, SkClipOp op, bool antialias) override; void clipRRect(const SkRRect& rrect, SkClipOp op, bool antialias) override;
void clipPath(const SkPath& path, SkClipOp op, bool antialias) override; void clipPath(const SkPath& path, SkClipOp op, bool antialias) override;
void clipDeviceRect(const SkIRect& device_rect,
const SkIRect& subtract_rect,
SkClipOp op) override;
bool quickReject(const SkRect& rect) const override; bool quickReject(const SkRect& rect) const override;
bool quickReject(const SkPath& path) const override; bool quickReject(const SkPath& path) const override;
SkRect getLocalClipBounds() const override; SkRect getLocalClipBounds() const override;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "third_party/skia/include/core/SkAnnotation.h" #include "third_party/skia/include/core/SkAnnotation.h"
#include "third_party/skia/include/core/SkColorSpaceXformCanvas.h" #include "third_party/skia/include/core/SkColorSpaceXformCanvas.h"
#include "third_party/skia/include/core/SkMetaData.h" #include "third_party/skia/include/core/SkMetaData.h"
#include "third_party/skia/include/core/SkRegion.h"
#include "third_party/skia/include/utils/SkNWayCanvas.h" #include "third_party/skia/include/utils/SkNWayCanvas.h"
namespace cc { namespace cc {
...@@ -156,6 +157,16 @@ void SkiaPaintCanvas::clear(SkColor color) { ...@@ -156,6 +157,16 @@ void SkiaPaintCanvas::clear(SkColor color) {
canvas_->clear(color); canvas_->clear(color);
} }
void SkiaPaintCanvas::clipDeviceRect(const SkIRect& device_rect,
const SkIRect& subtract_rect,
SkClipOp op) {
SkRegion device_region;
device_region.setRect(device_rect);
if (!subtract_rect.isEmpty())
device_region.op(subtract_rect, SkRegion::kDifference_Op);
canvas_->clipRegion(device_region, op);
}
void SkiaPaintCanvas::drawLine(SkScalar x0, void SkiaPaintCanvas::drawLine(SkScalar x0,
SkScalar y0, SkScalar y0,
SkScalar x1, SkScalar x1,
......
...@@ -58,6 +58,9 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas { ...@@ -58,6 +58,9 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
SkClipOp op, SkClipOp op,
bool do_anti_alias) override; bool do_anti_alias) override;
void clipPath(const SkPath& path, SkClipOp op, bool do_anti_alias) override; void clipPath(const SkPath& path, SkClipOp op, bool do_anti_alias) override;
void clipDeviceRect(const SkIRect& device_rect,
const SkIRect& subtract_rect,
SkClipOp op) override;
bool quickReject(const SkRect& rect) const override; bool quickReject(const SkRect& rect) const override;
bool quickReject(const SkPath& path) const override; bool quickReject(const SkPath& path) const override;
SkRect getLocalClipBounds() const override; SkRect getLocalClipBounds() const override;
......
...@@ -235,6 +235,20 @@ base::Optional<SkColor> SolidColorAnalyzer::DetermineIfSolidColor( ...@@ -235,6 +235,20 @@ base::Optional<SkColor> SolidColorAnalyzer::DetermineIfSolidColor(
op->Raster(&canvas, params); op->Raster(&canvas, params);
break; break;
} }
case PaintOpType::ClipDeviceRect: {
// Similar to the ClipRect comment above, if clipDeviceRect uses
// a difference op or has an implicit subtraction (which would
// create a non-rect), then this creates a non-rect clip and
// we assume non-solid color.
const ClipDeviceRectOp* clip_op =
static_cast<const ClipDeviceRectOp*>(op);
if (clip_op->op == SkClipOp::kDifference)
return base::nullopt;
if (!clip_op->subtract_rect.isEmpty())
return base::nullopt;
op->Raster(&canvas, params);
break;
}
// The rest of the ops should only affect our state canvas. // The rest of the ops should only affect our state canvas.
case PaintOpType::Annotate: case PaintOpType::Annotate:
......
...@@ -152,6 +152,48 @@ TEST_F(SolidColorAnalyzerTest, DrawRectClippedDifference) { ...@@ -152,6 +152,48 @@ TEST_F(SolidColorAnalyzerTest, DrawRectClippedDifference) {
EXPECT_FALSE(IsSolidColor()); EXPECT_FALSE(IsSolidColor());
} }
TEST_F(SolidColorAnalyzerTest, DrawRectClipRegionUnclipped) {
Initialize();
PaintFlags flags;
SkColor color = SkColorSetARGB(255, 11, 22, 33);
flags.setColor(color);
static constexpr int kTranslate = 3000;
canvas()->translate(kTranslate, kTranslate);
SkRect rect = SkRect::MakeXYWH(-kTranslate, -kTranslate, 100, 100);
// Clip exactly the device bounds.
canvas()->clipDeviceRect(SkIRect::MakeWH(100, 100), SkIRect::MakeEmpty(),
SkClipOp::kIntersect);
canvas()->drawRect(rect, flags);
EXPECT_EQ(color, GetColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectClipRegionClipped) {
Initialize();
PaintFlags flags;
SkColor color = SkColorSetARGB(255, 11, 22, 33);
flags.setColor(color);
SkRect rect = SkRect::MakeWH(100, 100);
// Clip less than the device bounds.
canvas()->clipDeviceRect(SkIRect::MakeWH(50, 50), SkIRect::MakeEmpty(),
SkClipOp::kIntersect);
canvas()->drawRect(rect, flags);
EXPECT_FALSE(IsSolidColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectClipRegionClipped2) {
Initialize();
PaintFlags flags;
SkColor color = SkColorSetARGB(255, 11, 22, 33);
flags.setColor(color);
SkRect rect = SkRect::MakeWH(100, 100);
// Clip a reverse L shape (100x100 with a 50x50 corner bite out of it).
// This should not be solid.
canvas()->clipDeviceRect(SkIRect::MakeWH(100, 100), SkIRect::MakeWH(50, 50),
SkClipOp::kIntersect);
canvas()->drawRect(rect, flags);
EXPECT_FALSE(IsSolidColor());
}
TEST_F(SolidColorAnalyzerTest, DrawRectWithTranslateNotSolid) { TEST_F(SolidColorAnalyzerTest, DrawRectWithTranslateNotSolid) {
Initialize(); Initialize();
PaintFlags flags; PaintFlags flags;
......
...@@ -33,6 +33,10 @@ class MockPaintCanvas : public PaintCanvas { ...@@ -33,6 +33,10 @@ class MockPaintCanvas : public PaintCanvas {
void(const SkRRect& rrect, SkClipOp op, bool do_anti_alias)); void(const SkRRect& rrect, SkClipOp op, bool do_anti_alias));
MOCK_METHOD3(clipPath, MOCK_METHOD3(clipPath,
void(const SkPath& path, SkClipOp op, bool do_anti_alias)); void(const SkPath& path, SkClipOp op, bool do_anti_alias));
MOCK_METHOD3(clipDeviceRect,
void(const SkIRect& device_rect,
const SkIRect& subtract_rect,
SkClipOp op));
MOCK_CONST_METHOD1(quickReject, bool(const SkRect& rect)); MOCK_CONST_METHOD1(quickReject, bool(const SkRect& rect));
MOCK_CONST_METHOD1(quickReject, bool(const SkPath& path)); MOCK_CONST_METHOD1(quickReject, bool(const SkPath& path));
MOCK_CONST_METHOD0(getLocalClipBounds, SkRect()); MOCK_CONST_METHOD0(getLocalClipBounds, SkRect());
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment