0

[cc] Stop caching paths in paint_op_buffer for 2d canvas use cases

The cache eviction logic for cached paths is a profiling hot spot
for 2d canvas path rendering, and the cache is not useful for 2d canvas
since there are no opportunities to recycle SkPath objects, except when
using the Path2D web interface.  Path2D object will continue to hit the
cache.

Furthermore, Skia-side caching is not useful for SkPath objects that are
rasterized only once, so this change also disables that cache for 2D
canvas use cases.

Bug: 1200458
Change-Id: I4d7837c9b4713710d5cb549e51e32e88b266bc73
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2860803
Commit-Queue: Justin Novosad <junov@chromium.org>
Reviewed-by: Jeremy Roman <jbroman@chromium.org>
Reviewed-by: Khushal <khushalsagar@chromium.org>
Reviewed-by: Philip Rogers <pdr@chromium.org>
Reviewed-by: Fernando Serboncini <fserb@chromium.org>
Reviewed-by: ccameron <ccameron@chromium.org>
Cr-Commit-Position: refs/heads/master@{#890784}
This commit is contained in:
Justin Novosad
2021-06-09 15:50:38 +00:00
committed by Chromium LUCI CQ
parent cd9f3c1f05
commit 2756a7d590
19 changed files with 192 additions and 64 deletions

@ -7,6 +7,8 @@
#include <map>
#include <set>
#include <utility>
#include <vector>
#include "base/containers/mru_cache.h"
#include "base/containers/stack_container.h"
@ -41,7 +43,8 @@ enum class PaintCacheEntryState : uint32_t {
kEmpty,
kCached,
kInlined,
kLast = kInlined
kInlinedDoNotCache,
kLast = kInlinedDoNotCache
};
constexpr size_t PaintCacheDataTypeCount =

@ -27,6 +27,8 @@ class SkottieWrapper;
class PaintFlags;
class PaintOpBuffer;
enum class UsePaintCache { kDisabled = 0, kEnabled };
using PaintRecord = PaintOpBuffer;
// PaintCanvas is the cc/paint wrapper of SkCanvas. It has a more restricted
@ -109,10 +111,17 @@ class CC_PAINT_EXPORT PaintCanvas {
virtual void clipPath(const SkPath& path,
SkClipOp op,
bool do_anti_alias) = 0;
void clipPath(const SkPath& path, SkClipOp op) { clipPath(path, op, false); }
bool do_anti_alias,
UsePaintCache) = 0;
void clipPath(const SkPath& path, SkClipOp op, bool do_anti_alias) {
clipPath(path, op, do_anti_alias, UsePaintCache::kEnabled);
}
void clipPath(const SkPath& path, SkClipOp op) {
clipPath(path, op, /*do_anti_alias=*/false, UsePaintCache::kEnabled);
}
void clipPath(const SkPath& path, bool do_anti_alias) {
clipPath(path, SkClipOp::kIntersect, do_anti_alias);
clipPath(path, SkClipOp::kIntersect, do_anti_alias,
UsePaintCache::kEnabled);
}
virtual SkRect getLocalClipBounds() const = 0;
@ -141,7 +150,12 @@ class CC_PAINT_EXPORT PaintCanvas {
SkScalar rx,
SkScalar ry,
const PaintFlags& flags) = 0;
virtual void drawPath(const SkPath& path, const PaintFlags& flags) = 0;
virtual void drawPath(const SkPath& path,
const PaintFlags& flags,
UsePaintCache) = 0;
void drawPath(const SkPath& path, const PaintFlags& flags) {
drawPath(path, flags, UsePaintCache::kEnabled);
}
virtual void drawImage(const PaintImage& image,
SkScalar left,
SkScalar top,

@ -4,6 +4,7 @@
#include "cc/paint/paint_op_buffer.h"
#include <algorithm>
#include <memory>
#include <utility>
#include <vector>
@ -413,7 +414,7 @@ size_t ClipPathOp::Serialize(const PaintOp* base_op,
const SkM44& original_ctm) {
auto* op = static_cast<const ClipPathOp*>(base_op);
PaintOpWriter helper(memory, size, options);
helper.Write(op->path);
helper.Write(op->path, op->use_cache);
helper.Write(op->op);
helper.Write(op->antialias);
return helper.size();
@ -629,7 +630,7 @@ size_t DrawPathOp::Serialize(const PaintOp* base_op,
if (!flags_to_serialize)
flags_to_serialize = &op->flags;
helper.Write(*flags_to_serialize, current_ctm);
helper.Write(op->path);
helper.Write(op->path, op->use_cache);
helper.Write(op->sk_path_fill_type);
return helper.size();
}
@ -2432,7 +2433,7 @@ gfx::Rect PaintOp::ComputePaintRect(const PaintOp* op,
} else {
const PaintFlags* flags =
op->IsPaintOpWithFlags()
? &static_cast<const PaintOpWithFlags*>(op)->flags
? &(static_cast<const PaintOpWithFlags*>(op)->flags)
: nullptr;
SkRect paint_rect = MapRect(ctm, op_rect);
if (flags) {

@ -389,8 +389,15 @@ class CC_PAINT_EXPORT AnnotateOp final : public PaintOp {
class CC_PAINT_EXPORT ClipPathOp final : public PaintOp {
public:
static constexpr PaintOpType kType = PaintOpType::ClipPath;
ClipPathOp(SkPath path, SkClipOp op, bool antialias)
: PaintOp(kType), path(path), op(op), antialias(antialias) {}
ClipPathOp(SkPath path,
SkClipOp op,
bool antialias,
UsePaintCache use_paint_cache = UsePaintCache::kEnabled)
: PaintOp(kType),
path(path),
op(op),
antialias(antialias),
use_cache(use_paint_cache) {}
static void Raster(const ClipPathOp* op,
SkCanvas* canvas,
const PlaybackParams& params);
@ -403,6 +410,7 @@ class CC_PAINT_EXPORT ClipPathOp final : public PaintOp {
ThreadsafePath path;
SkClipOp op;
bool antialias;
UsePaintCache use_cache;
private:
ClipPathOp() : PaintOp(kType) {}
@ -685,10 +693,13 @@ class CC_PAINT_EXPORT DrawPathOp final : public PaintOpWithFlags {
public:
static constexpr PaintOpType kType = PaintOpType::DrawPath;
static constexpr bool kIsDrawOp = true;
DrawPathOp(const SkPath& path, const PaintFlags& flags)
DrawPathOp(const SkPath& path,
const PaintFlags& flags,
UsePaintCache use_paint_cache = UsePaintCache::kEnabled)
: PaintOpWithFlags(kType, flags),
path(path),
sk_path_fill_type(static_cast<uint8_t>(path.getFillType())) {}
sk_path_fill_type(static_cast<uint8_t>(path.getFillType())),
use_cache(use_paint_cache) {}
static void RasterWithFlags(const DrawPathOp* op,
const PaintFlags* flags,
SkCanvas* canvas,
@ -705,6 +716,7 @@ class CC_PAINT_EXPORT DrawPathOp final : public PaintOpWithFlags {
// serialize/deserialize this value and set it on the SkPath before handing it
// to Skia.
uint8_t sk_path_fill_type;
UsePaintCache use_cache;
private:
DrawPathOp() : PaintOpWithFlags(kType) {}

@ -558,16 +558,19 @@ TEST(PaintOpBufferTest, SlowPaths) {
SkPath path;
path.addCircle(2, 2, 5);
EXPECT_TRUE(path.isConvex());
buffer->push<ClipPathOp>(path, SkClipOp::kIntersect, true);
buffer->push<ClipPathOp>(path, SkClipOp::kIntersect, /*antialias=*/true,
UsePaintCache::kDisabled);
EXPECT_EQ(buffer->numSlowPaths(), 1);
// Concave paths are slow only when antialiased.
SkPath concave = path;
concave.addCircle(3, 4, 2);
EXPECT_FALSE(concave.isConvex());
buffer->push<ClipPathOp>(concave, SkClipOp::kIntersect, true);
buffer->push<ClipPathOp>(concave, SkClipOp::kIntersect, /*antialias=*/true,
UsePaintCache::kDisabled);
EXPECT_EQ(buffer->numSlowPaths(), 2);
buffer->push<ClipPathOp>(concave, SkClipOp::kIntersect, false);
buffer->push<ClipPathOp>(concave, SkClipOp::kIntersect, /*antialias=*/false,
UsePaintCache::kDisabled);
EXPECT_EQ(buffer->numSlowPaths(), 2);
// Drawing a record with slow paths into another adds the same
@ -608,11 +611,13 @@ TEST(PaintOpBufferTest, NonAAPaint) {
path.addCircle(2, 2, 5);
// ClipPathOp with AA
buffer->push<ClipPathOp>(path, SkClipOp::kIntersect, true /* antialias */);
buffer->push<ClipPathOp>(path, SkClipOp::kIntersect, /*antialias=*/true,
UsePaintCache::kDisabled);
EXPECT_FALSE(buffer->HasNonAAPaint());
// ClipPathOp without AA
buffer->push<ClipPathOp>(path, SkClipOp::kIntersect, false /* antialias */);
buffer->push<ClipPathOp>(path, SkClipOp::kIntersect, /*antialias=*/false,
UsePaintCache::kDisabled);
EXPECT_TRUE(buffer->HasNonAAPaint());
}
@ -641,7 +646,7 @@ TEST(PaintOpBufferTest, NonAAPaint) {
SkPath path;
path.addCircle(2, 2, 5);
sub_buffer->push<ClipPathOp>(path, SkClipOp::kIntersect,
false /* antialias */);
/*antialias=*/false, UsePaintCache::kDisabled);
EXPECT_TRUE(sub_buffer->HasNonAAPaint());
buffer->push<DrawRecordOp>(sub_buffer);
@ -1415,7 +1420,8 @@ void PushAnnotateOps(PaintOpBuffer* buffer) {
void PushClipPathOps(PaintOpBuffer* buffer) {
for (size_t i = 0; i < test_paths.size(); ++i) {
SkClipOp op = i % 3 ? SkClipOp::kDifference : SkClipOp::kIntersect;
buffer->push<ClipPathOp>(test_paths[i], op, !!(i % 2));
buffer->push<ClipPathOp>(test_paths[i], op, /*antialias=*/!!(i % 2),
UsePaintCache::kDisabled);
}
ValidateOps<ClipPathOp>(buffer);
}
@ -1530,7 +1536,8 @@ void PushDrawOvalOps(PaintOpBuffer* buffer) {
void PushDrawPathOps(PaintOpBuffer* buffer) {
size_t len = std::min(test_paths.size(), test_flags.size());
for (size_t i = 0; i < len; ++i)
buffer->push<DrawPathOp>(test_paths[i], test_flags[i]);
buffer->push<DrawPathOp>(test_paths[i], test_flags[i],
UsePaintCache::kDisabled);
ValidateOps<DrawPathOp>(buffer);
}
@ -2458,13 +2465,15 @@ TEST(PaintOpBufferTest, ValidateSkClip) {
// Successful first op.
SkPath path;
buffer.push<ClipPathOp>(path, SkClipOp::kMax_EnumValue, true);
buffer.push<ClipPathOp>(path, SkClipOp::kMax_EnumValue, /*antialias=*/true,
UsePaintCache::kDisabled);
// Bad other ops.
SkClipOp bad_clip = static_cast<SkClipOp>(
static_cast<uint32_t>(SkClipOp::kMax_EnumValue) + 1);
buffer.push<ClipPathOp>(path, bad_clip, true);
buffer.push<ClipPathOp>(path, bad_clip, /*antialias=*/true,
UsePaintCache::kDisabled);
buffer.push<ClipRectOp>(test_rects[0], bad_clip, true);
buffer.push<ClipRRectOp>(test_rrects[0], bad_clip, false);
@ -3985,4 +3994,41 @@ TEST(PaintOpBufferTest, SetMatrixOpWithNonIdentityPlaybackParams) {
}
}
TEST(PaintOpBufferTest, PathCaching) {
SkPath path;
PaintFlags flags;
// Grow path large enough to trigger caching
path.moveTo(0, 0);
for (int x = 1; x < 100; ++x)
path.lineTo(x, x % 1);
TestOptionsProvider options_provider;
std::unique_ptr<char, base::AlignedFreeDeleter> memory(
static_cast<char*>(base::AlignedAlloc(PaintOpBuffer::kInitialBufferSize,
PaintOpBuffer::PaintOpAlign)));
auto buffer = sk_make_sp<PaintOpBuffer>();
buffer->push<DrawPathOp>(path, flags, UsePaintCache::kEnabled);
SimpleBufferSerializer serializer(memory.get(),
PaintOpBuffer::kInitialBufferSize,
options_provider.serialize_options());
serializer.Serialize(buffer.get());
EXPECT_TRUE(options_provider.client_paint_cache()->Get(
PaintCacheDataType::kPath, path.getGenerationID()));
auto deserialized_buffer =
PaintOpBuffer::MakeFromMemory(memory.get(), serializer.written(),
options_provider.deserialize_options());
ASSERT_TRUE(deserialized_buffer);
ASSERT_EQ(deserialized_buffer->size(), 1u);
ASSERT_EQ(deserialized_buffer->GetFirstOp()->GetType(),
PaintOpType::DrawPath);
SkPath cached_path;
EXPECT_TRUE(options_provider.service_paint_cache()->GetPath(
path.getGenerationID(), &cached_path));
}
} // namespace cc

@ -19,9 +19,12 @@ TEST(PaintOpHelper, AnnotateToString) {
}
TEST(PaintOpHelper, ClipPathToString) {
ClipPathOp op(SkPath(), SkClipOp::kDifference, true);
ClipPathOp op(SkPath(), SkClipOp::kDifference, true,
UsePaintCache::kDisabled);
std::string str = PaintOpHelper::ToString(&op);
EXPECT_EQ(str, "ClipPathOp(path=<SkPath>, op=kDifference, antialias=true)");
EXPECT_EQ(str,
"ClipPathOp(path=<SkPath>, op=kDifference, antialias=true, "
"use_cache=false)");
}
TEST(PaintOpHelper, ClipRectToString) {
@ -156,7 +159,7 @@ TEST(PaintOpHelper, DrawOvalToString) {
TEST(PaintOpHelper, DrawPathToString) {
SkPath path;
DrawPathOp op(path, PaintFlags());
DrawPathOp op(path, PaintFlags(), UsePaintCache::kDisabled);
std::string str = PaintOpHelper::ToString(&op);
EXPECT_EQ(str,
"DrawPathOp(path=<SkPath>, flags=[color=rgba(0, 0, 0, 255), "
@ -167,7 +170,7 @@ TEST(PaintOpHelper, DrawPathToString) {
"shader=(nil), hasShader=false, shaderIsOpaque=false, "
"pathEffect=(nil), imageFilter=(nil), drawLooper=(nil), "
"isSimpleOpacity=true, supportsFoldingAlpha=true, isValid=true, "
"hasDiscardableImages=false])");
"hasDiscardableImages=false], use_cache=false)");
}
TEST(PaintOpHelper, DrawRecordToString) {

@ -227,7 +227,8 @@ void PaintOpReader::Read(SkPath* path) {
if (!options_.paint_cache->GetPath(path_id, path))
SetInvalid();
return;
case PaintCacheEntryState::kInlined: {
case PaintCacheEntryState::kInlined:
case PaintCacheEntryState::kInlinedDoNotCache: {
size_t path_bytes = 0u;
ReadSize(&path_bytes);
if (path_bytes > remaining_bytes_)
@ -243,7 +244,9 @@ void PaintOpReader::Read(SkPath* path) {
SetInvalid();
return;
}
options_.paint_cache->PutPath(path_id, *path);
if (entry_state == PaintCacheEntryState::kInlined) {
options_.paint_cache->PutPath(path_id, *path);
}
memory_ += path_bytes;
remaining_bytes_ -= path_bytes;
return;

@ -173,12 +173,15 @@ void PaintOpWriter::Write(const SkRRect& rect) {
WriteSimple(rect);
}
void PaintOpWriter::Write(const SkPath& path) {
void PaintOpWriter::Write(const SkPath& path, UsePaintCache use_paint_cache) {
auto id = path.getGenerationID();
if (!options_.for_identifiability_study)
Write(id);
if (options_.paint_cache->Get(PaintCacheDataType::kPath, id)) {
DCHECK(use_paint_cache == UsePaintCache::kEnabled ||
!options_.paint_cache->Get(PaintCacheDataType::kPath, id));
if (use_paint_cache == UsePaintCache::kEnabled &&
options_.paint_cache->Get(PaintCacheDataType::kPath, id)) {
Write(static_cast<uint32_t>(PaintCacheEntryState::kCached));
return;
}
@ -190,7 +193,11 @@ void PaintOpWriter::Write(const SkPath& path) {
return;
}
Write(static_cast<uint32_t>(PaintCacheEntryState::kInlined));
if (use_paint_cache == UsePaintCache::kEnabled) {
Write(static_cast<uint32_t>(PaintCacheEntryState::kInlined));
} else {
Write(static_cast<uint32_t>(PaintCacheEntryState::kInlinedDoNotCache));
}
uint64_t* bytes_to_skip = WriteSize(0u);
if (!valid_)
return;
@ -201,7 +208,9 @@ void PaintOpWriter::Write(const SkPath& path) {
}
size_t bytes_written = path.writeToMemory(memory_);
DCHECK_EQ(bytes_written, bytes_required);
options_.paint_cache->Put(PaintCacheDataType::kPath, id, bytes_written);
if (use_paint_cache == UsePaintCache::kEnabled) {
options_.paint_cache->Put(PaintCacheDataType::kPath, id, bytes_written);
}
*bytes_to_skip = bytes_written;
memory_ += bytes_written;
remaining_bytes_ -= bytes_written;

@ -59,8 +59,7 @@ class CC_PAINT_EXPORT PaintOpWriter {
void Write(const SkRect& rect);
void Write(const SkIRect& rect);
void Write(const SkRRect& rect);
void Write(const SkPath& path);
void Write(const SkPath& path, UsePaintCache);
void Write(const sk_sp<SkData>& data);
void Write(const SkColorSpace* data);
void Write(const SkSamplingOptions&);

@ -150,7 +150,8 @@ void RecordPaintCanvas::clipRRect(const SkRRect& rrect,
void RecordPaintCanvas::clipPath(const SkPath& path,
SkClipOp op,
bool antialias) {
bool antialias,
UsePaintCache use_paint_cache) {
if (!path.isInverseFillType() &&
GetCanvas()->getTotalMatrix().rectStaysRect()) {
// TODO(enne): do these cases happen? should the caller know that this isn't
@ -172,7 +173,7 @@ void RecordPaintCanvas::clipPath(const SkPath& path,
}
}
list_->push<ClipPathOp>(path, op, antialias);
list_->push<ClipPathOp>(path, op, antialias, use_paint_cache);
GetCanvas()->clipPath(path, op, antialias);
return;
}
@ -257,8 +258,10 @@ void RecordPaintCanvas::drawRoundRect(const SkRect& rect,
}
}
void RecordPaintCanvas::drawPath(const SkPath& path, const PaintFlags& flags) {
list_->push<DrawPathOp>(path, flags);
void RecordPaintCanvas::drawPath(const SkPath& path,
const PaintFlags& flags,
UsePaintCache use_paint_cache) {
list_->push<DrawPathOp>(path, flags, use_paint_cache);
}
void RecordPaintCanvas::drawImage(const PaintImage& image,

@ -53,7 +53,10 @@ class CC_PAINT_EXPORT RecordPaintCanvas : 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 clipPath(const SkPath& path,
SkClipOp op,
bool antialias,
UsePaintCache use_paint_cache) override;
SkRect getLocalClipBounds() const override;
bool getLocalClipBounds(SkRect* bounds) const override;
SkIRect getDeviceClipBounds() const override;
@ -77,7 +80,9 @@ class CC_PAINT_EXPORT RecordPaintCanvas : public PaintCanvas {
SkScalar rx,
SkScalar ry,
const PaintFlags& flags) override;
void drawPath(const SkPath& path, const PaintFlags& flags) override;
void drawPath(const SkPath& path,
const PaintFlags& flags,
UsePaintCache use_paint_cache) override;
void drawImage(const PaintImage& image,
SkScalar left,
SkScalar top,

@ -125,7 +125,8 @@ void SkiaPaintCanvas::clipRRect(const SkRRect& rrect,
void SkiaPaintCanvas::clipPath(const SkPath& path,
SkClipOp op,
bool do_anti_alias) {
bool do_anti_alias,
UsePaintCache) {
canvas_->clipPath(path, op, do_anti_alias);
}
@ -250,7 +251,9 @@ void SkiaPaintCanvas::drawRoundRect(const SkRect& rect,
FlushAfterDrawIfNeeded();
}
void SkiaPaintCanvas::drawPath(const SkPath& path, const PaintFlags& flags) {
void SkiaPaintCanvas::drawPath(const SkPath& path,
const PaintFlags& flags,
UsePaintCache) {
ScopedRasterFlags raster_flags(&flags, image_provider_,
canvas_->getTotalMatrix(), max_texture_size(),
255u);

@ -77,7 +77,10 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
void clipRRect(const SkRRect& rrect,
SkClipOp op,
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,
UsePaintCache) override;
SkRect getLocalClipBounds() const override;
bool getLocalClipBounds(SkRect* bounds) const override;
SkIRect getDeviceClipBounds() const override;
@ -101,7 +104,9 @@ class CC_PAINT_EXPORT SkiaPaintCanvas final : public PaintCanvas {
SkScalar rx,
SkScalar ry,
const PaintFlags& flags) override;
void drawPath(const SkPath& path, const PaintFlags& flags) override;
void drawPath(const SkPath& path,
const PaintFlags& flags,
UsePaintCache) override;
void drawImage(const PaintImage& image,
SkScalar left,
SkScalar top,

@ -37,7 +37,9 @@ class PaintOpHelper {
const auto* op = static_cast<const ClipPathOp*>(base_op);
str << "ClipPathOp(path=" << PaintOpHelper::SkiaTypeToString(op->path)
<< ", op=" << PaintOpHelper::SkiaTypeToString(op->op)
<< ", antialias=" << op->antialias << ")";
<< ", antialias=" << op->antialias
<< ", use_cache=" << (op->use_cache == UsePaintCache::kEnabled)
<< ")";
break;
}
case PaintOpType::ClipRect: {
@ -124,7 +126,9 @@ class PaintOpHelper {
case PaintOpType::DrawPath: {
const auto* op = static_cast<const DrawPathOp*>(base_op);
str << "DrawPathOp(path=" << PaintOpHelper::SkiaTypeToString(op->path)
<< ", flags=" << PaintOpHelper::FlagsToString(op->flags) << ")";
<< ", flags=" << PaintOpHelper::FlagsToString(op->flags)
<< ", use_cache=" << (op->use_cache == UsePaintCache::kEnabled)
<< ")";
break;
}
case PaintOpType::DrawRecord: {

@ -56,7 +56,8 @@ sk_sp<PaintRecord> RecordMarker(Color blink_color) {
PaintRecorder recorder;
recorder.beginRecording(kMarkerWidth, kMarkerHeight);
recorder.getRecordingCanvas()->drawPath(path.detach(), flags);
recorder.getRecordingCanvas()->cc::PaintCanvas::drawPath(path.detach(),
flags);
return recorder.finishRecordingAsPicture();
}

@ -976,7 +976,8 @@ bool BaseRenderingContext2D::IsFullCanvasCompositeMode(SkBlendMode op) {
void BaseRenderingContext2D::DrawPathInternal(
const Path& path,
CanvasRenderingContext2DState::PaintType paint_type,
SkPathFillType fill_type) {
SkPathFillType fill_type,
UsePaintCache use_paint_cache) {
if (path.IsEmpty())
return;
@ -993,8 +994,9 @@ void BaseRenderingContext2D::DrawPathInternal(
if (!GetOrCreatePaintCanvas())
return;
Draw([sk_path](cc::PaintCanvas* c, const PaintFlags* flags) // draw lambda
{ c->drawPath(sk_path, *flags); },
Draw([sk_path, use_paint_cache](cc::PaintCanvas* c,
const PaintFlags* flags) // draw lambda
{ c->drawPath(sk_path, *flags, use_paint_cache); },
[](const SkIRect& rect) // overdraw test lambda
{ return false; },
bounds, paint_type,
@ -1015,23 +1017,25 @@ static SkPathFillType ParseWinding(const String& winding_rule_string) {
void BaseRenderingContext2D::fill(const String& winding_rule_string) {
DrawPathInternal(path_, CanvasRenderingContext2DState::kFillPaintType,
ParseWinding(winding_rule_string));
ParseWinding(winding_rule_string), UsePaintCache::kDisabled);
}
void BaseRenderingContext2D::fill(Path2D* dom_path,
const String& winding_rule_string) {
DrawPathInternal(dom_path->GetPath(),
CanvasRenderingContext2DState::kFillPaintType,
ParseWinding(winding_rule_string));
ParseWinding(winding_rule_string), UsePaintCache::kEnabled);
}
void BaseRenderingContext2D::stroke() {
DrawPathInternal(path_, CanvasRenderingContext2DState::kStrokePaintType);
DrawPathInternal(path_, CanvasRenderingContext2DState::kStrokePaintType,
SkPathFillType::kWinding, UsePaintCache::kDisabled);
}
void BaseRenderingContext2D::stroke(Path2D* dom_path) {
DrawPathInternal(dom_path->GetPath(),
CanvasRenderingContext2DState::kStrokePaintType);
CanvasRenderingContext2DState::kStrokePaintType,
SkPathFillType::kWinding, UsePaintCache::kEnabled);
}
void BaseRenderingContext2D::fillRect(double x,
@ -1130,7 +1134,8 @@ void BaseRenderingContext2D::strokeRect(double x,
}
void BaseRenderingContext2D::ClipInternal(const Path& path,
const String& winding_rule_string) {
const String& winding_rule_string,
UsePaintCache use_paint_cache) {
cc::PaintCanvas* c = GetOrCreatePaintCanvas();
if (!c) {
return;
@ -1142,17 +1147,18 @@ void BaseRenderingContext2D::ClipInternal(const Path& path,
SkPath sk_path = path.GetSkPath();
sk_path.setFillType(ParseWinding(winding_rule_string));
GetState().ClipPath(sk_path, clip_antialiasing_);
c->clipPath(sk_path, SkClipOp::kIntersect,
clip_antialiasing_ == kAntiAliased);
c->clipPath(sk_path, SkClipOp::kIntersect, clip_antialiasing_ == kAntiAliased,
use_paint_cache);
}
void BaseRenderingContext2D::clip(const String& winding_rule_string) {
ClipInternal(path_, winding_rule_string);
ClipInternal(path_, winding_rule_string, UsePaintCache::kDisabled);
}
void BaseRenderingContext2D::clip(Path2D* dom_path,
const String& winding_rule_string) {
ClipInternal(dom_path->GetPath(), winding_rule_string);
ClipInternal(dom_path->GetPath(), winding_rule_string,
UsePaintCache::kEnabled);
}
bool BaseRenderingContext2D::isPointInPath(const double x,

@ -28,6 +28,7 @@ class Image;
class Path2D;
class V8UnionCSSColorValueOrCanvasGradientOrCanvasPatternOrString;
class V8UnionCanvasFilterOrString;
using cc::UsePaintCache;
class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
public CanvasPath {
@ -498,7 +499,8 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
void DrawPathInternal(const Path&,
CanvasRenderingContext2DState::PaintType,
SkPathFillType = SkPathFillType::kWinding);
SkPathFillType,
UsePaintCache);
void DrawImageInternal(cc::PaintCanvas*,
CanvasImageSource*,
Image*,
@ -506,7 +508,9 @@ class MODULES_EXPORT BaseRenderingContext2D : public GarbageCollectedMixin,
const FloatRect& dst_rect,
const SkSamplingOptions&,
const PaintFlags*);
void ClipInternal(const Path&, const String& winding_rule_string);
void ClipInternal(const Path&,
const String& winding_rule_string,
UsePaintCache);
bool IsPointInPathInternal(const Path&,
const double x,

@ -40,8 +40,11 @@ class MockPaintCanvas : public cc::PaintCanvas {
void(const SkRect& rect, SkClipOp op, bool do_anti_alias));
MOCK_METHOD3(clipRRect,
void(const SkRRect& rrect, SkClipOp op, bool do_anti_alias));
MOCK_METHOD3(clipPath,
void(const SkPath& path, SkClipOp op, bool do_anti_alias));
MOCK_METHOD4(clipPath,
void(const SkPath& path,
SkClipOp op,
bool do_anti_alias,
cc::UsePaintCache use_paint_cache));
MOCK_CONST_METHOD0(getLocalClipBounds, SkRect());
MOCK_CONST_METHOD1(getLocalClipBounds, bool(SkRect* bounds));
MOCK_CONST_METHOD0(getDeviceClipBounds, SkIRect());
@ -67,7 +70,10 @@ class MockPaintCanvas : public cc::PaintCanvas {
SkScalar rx,
SkScalar ry,
const PaintFlags& flags));
MOCK_METHOD2(drawPath, void(const SkPath& path, const PaintFlags& flags));
MOCK_METHOD3(drawPath,
void(const SkPath& path,
const PaintFlags& flags,
cc::UsePaintCache use_paint_cache));
MOCK_METHOD5(drawImage,
void(const PaintImage& image,
SkScalar left,

@ -271,6 +271,7 @@ _CONFIG = [
'cc::PaintWorkletInput',
'cc::NodeId',
'cc::NodeInfo',
'cc::UsePaintCache',
# Chromium geometry types.
'gfx::Insets',