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 {
void clipPath(const SkPath& path, bool 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 SkPath& path) const = 0;
......
......@@ -14,6 +14,7 @@
#include "cc/paint/paint_record.h"
#include "third_party/skia/include/core/SkAnnotation.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkRegion.h"
namespace cc {
namespace {
......@@ -163,36 +164,37 @@ void RasterWithAlpha(const PaintOp* op,
} // namespace
#define TYPES(M) \
M(AnnotateOp) \
M(ClipPathOp) \
M(ClipRectOp) \
M(ClipRRectOp) \
M(ConcatOp) \
M(DrawArcOp) \
M(DrawCircleOp) \
M(DrawColorOp) \
M(DrawDRRectOp) \
M(DrawImageOp) \
M(DrawImageRectOp) \
M(DrawIRectOp) \
M(DrawLineOp) \
M(DrawOvalOp) \
M(DrawPathOp) \
M(DrawPosTextOp) \
M(DrawRecordOp) \
M(DrawRectOp) \
M(DrawRRectOp) \
M(DrawTextOp) \
M(DrawTextBlobOp) \
M(NoopOp) \
M(RestoreOp) \
M(RotateOp) \
M(SaveOp) \
M(SaveLayerOp) \
M(SaveLayerAlphaOp) \
M(ScaleOp) \
M(SetMatrixOp) \
#define TYPES(M) \
M(AnnotateOp) \
M(ClipDeviceRectOp) \
M(ClipPathOp) \
M(ClipRectOp) \
M(ClipRRectOp) \
M(ConcatOp) \
M(DrawArcOp) \
M(DrawCircleOp) \
M(DrawColorOp) \
M(DrawDRRectOp) \
M(DrawImageOp) \
M(DrawImageRectOp) \
M(DrawIRectOp) \
M(DrawLineOp) \
M(DrawOvalOp) \
M(DrawPathOp) \
M(DrawPosTextOp) \
M(DrawRecordOp) \
M(DrawRectOp) \
M(DrawRRectOp) \
M(DrawTextOp) \
M(DrawTextBlobOp) \
M(NoopOp) \
M(RestoreOp) \
M(RotateOp) \
M(SaveOp) \
M(SaveLayerOp) \
M(SaveLayerAlphaOp) \
M(ScaleOp) \
M(SetMatrixOp) \
M(TranslateOp)
static constexpr size_t kNumOpTypes =
......@@ -327,6 +329,8 @@ std::string PaintOpTypeToString(PaintOpType type) {
switch (type) {
case PaintOpType::Annotate:
return "Annotate";
case PaintOpType::ClipDeviceRect:
return "ClipDeviceRect";
case PaintOpType::ClipPath:
return "ClipPath";
case PaintOpType::ClipRect:
......@@ -413,6 +417,13 @@ size_t AnnotateOp::Serialize(const PaintOp* base_op,
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,
void* memory,
size_t size,
......@@ -748,6 +759,14 @@ PaintOp* AnnotateOp::Deserialize(const void* input,
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,
size_t input_size,
void* output,
......@@ -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,
SkCanvas* canvas,
const PlaybackParams& params) {
......
......@@ -57,6 +57,7 @@ class CC_PAINT_EXPORT ThreadsafePath : public SkPath {
enum class PaintOpType : uint8_t {
Annotate,
ClipDeviceRect,
ClipPath,
ClipRect,
ClipRRect,
......@@ -342,6 +343,23 @@ class CC_PAINT_EXPORT AnnotateOp final : public PaintOp {
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 {
public:
static constexpr PaintOpType kType = PaintOpType::ClipPath;
......
......@@ -1360,6 +1360,13 @@ void PushAnnotateOps(PaintOpBuffer* buffer) {
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) {
for (size_t i = 0; i < test_paths.size(); ++i) {
SkClipOp op = i % 3 ? SkClipOp::kDifference : SkClipOp::kIntersect;
......@@ -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) {
EXPECT_TRUE(original->path == written->path);
EXPECT_EQ(original->op, written->op);
......@@ -1813,6 +1827,9 @@ class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> {
case PaintOpType::Annotate:
PushAnnotateOps(&buffer_);
break;
case PaintOpType::ClipDeviceRect:
PushClipDeviceRectOps(&buffer_);
break;
case PaintOpType::ClipPath:
PushClipPathOps(&buffer_);
break;
......@@ -1914,6 +1931,10 @@ class PaintOpSerializationTest : public ::testing::TestWithParam<uint8_t> {
CompareAnnotateOp(static_cast<const AnnotateOp*>(original),
static_cast<const AnnotateOp*>(written));
break;
case PaintOpType::ClipDeviceRect:
CompareClipDeviceRectOp(static_cast<const ClipDeviceRectOp*>(original),
static_cast<const ClipDeviceRectOp*>(written));
break;
case PaintOpType::ClipPath:
CompareClipPathOp(static_cast<const ClipPathOp*>(original),
static_cast<const ClipPathOp*>(written));
......
......@@ -164,6 +164,12 @@ void RecordPaintCanvas::clipPath(const SkPath& path,
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 {
return GetCanvas()->quickReject(rect);
}
......
......@@ -50,6 +50,9 @@ class CC_PAINT_EXPORT RecordPaintCanvas final : public PaintCanvas {
void clipRect(const SkRect& rect, 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 clipDeviceRect(const SkIRect& device_rect,
const SkIRect& subtract_rect,
SkClipOp op) override;
bool quickReject(const SkRect& rect) const override;
bool quickReject(const SkPath& path) const override;
SkRect getLocalClipBounds() const override;
......
......@@ -10,6 +10,7 @@
#include "third_party/skia/include/core/SkAnnotation.h"
#include "third_party/skia/include/core/SkColorSpaceXformCanvas.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"
namespace cc {
......@@ -156,6 +157,16 @@ void SkiaPaintCanvas::clear(SkColor 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,
SkScalar y0,
SkScalar x1,
......
......@@ -58,6 +58,9 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
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 SkPath& path) const override;
SkRect getLocalClipBounds() const override;
......
......@@ -235,6 +235,20 @@ base::Optional<SkColor> SolidColorAnalyzer::DetermineIfSolidColor(
op->Raster(&canvas, params);
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.
case PaintOpType::Annotate:
......
......@@ -152,6 +152,48 @@ TEST_F(SolidColorAnalyzerTest, DrawRectClippedDifference) {
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) {
Initialize();
PaintFlags flags;
......
......@@ -33,6 +33,10 @@ class MockPaintCanvas : public PaintCanvas {
void(const SkRRect& rrect, SkClipOp op, bool do_anti_alias));
MOCK_METHOD3(clipPath,
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 SkPath& path));
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