mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Reland "Split DisplayListBuilder into DlCanvas optimizer and DlOp recorder classes #44718" (flutter/engine#45085)
Fixes: https://github.com/flutter/flutter/issues/133200
This commit is contained in:
parent
eb6be31280
commit
5a9d0ee712
@ -717,18 +717,22 @@ ORIGIN: ../../../flutter/display_list/benchmarking/dl_complexity_metal.h + ../..
|
||||
ORIGIN: ../../../flutter/display_list/benchmarking/dl_region_benchmarks.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/display_list.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/display_list.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/display_list_builder.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/display_list_builder.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_attributes.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_blend_mode.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_blend_mode.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_builder.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_builder.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_canvas.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_canvas.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_canvas_to_receiver.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_canvas_to_receiver.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_color.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_op_flags.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_op_flags.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_op_receiver.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_op_receiver.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_op_recorder.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_op_recorder.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_op_records.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_op_records.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/display_list/dl_paint.cc + ../../../flutter/LICENSE
|
||||
@ -3455,18 +3459,22 @@ FILE: ../../../flutter/display_list/benchmarking/dl_complexity_metal.h
|
||||
FILE: ../../../flutter/display_list/benchmarking/dl_region_benchmarks.cc
|
||||
FILE: ../../../flutter/display_list/display_list.cc
|
||||
FILE: ../../../flutter/display_list/display_list.h
|
||||
FILE: ../../../flutter/display_list/display_list_builder.cc
|
||||
FILE: ../../../flutter/display_list/display_list_builder.h
|
||||
FILE: ../../../flutter/display_list/dl_attributes.h
|
||||
FILE: ../../../flutter/display_list/dl_blend_mode.cc
|
||||
FILE: ../../../flutter/display_list/dl_blend_mode.h
|
||||
FILE: ../../../flutter/display_list/dl_builder.cc
|
||||
FILE: ../../../flutter/display_list/dl_builder.h
|
||||
FILE: ../../../flutter/display_list/dl_canvas.cc
|
||||
FILE: ../../../flutter/display_list/dl_canvas.h
|
||||
FILE: ../../../flutter/display_list/dl_canvas_to_receiver.cc
|
||||
FILE: ../../../flutter/display_list/dl_canvas_to_receiver.h
|
||||
FILE: ../../../flutter/display_list/dl_color.h
|
||||
FILE: ../../../flutter/display_list/dl_op_flags.cc
|
||||
FILE: ../../../flutter/display_list/dl_op_flags.h
|
||||
FILE: ../../../flutter/display_list/dl_op_receiver.cc
|
||||
FILE: ../../../flutter/display_list/dl_op_receiver.h
|
||||
FILE: ../../../flutter/display_list/dl_op_recorder.cc
|
||||
FILE: ../../../flutter/display_list/dl_op_recorder.h
|
||||
FILE: ../../../flutter/display_list/dl_op_records.cc
|
||||
FILE: ../../../flutter/display_list/dl_op_records.h
|
||||
FILE: ../../../flutter/display_list/dl_paint.cc
|
||||
|
||||
@ -25,18 +25,22 @@ source_set("display_list") {
|
||||
"benchmarking/dl_complexity_metal.h",
|
||||
"display_list.cc",
|
||||
"display_list.h",
|
||||
"display_list_builder.cc",
|
||||
"display_list_builder.h",
|
||||
"dl_attributes.h",
|
||||
"dl_blend_mode.cc",
|
||||
"dl_blend_mode.h",
|
||||
"dl_builder.cc",
|
||||
"dl_builder.h",
|
||||
"dl_canvas.cc",
|
||||
"dl_canvas.h",
|
||||
"dl_canvas_to_receiver.cc",
|
||||
"dl_canvas_to_receiver.h",
|
||||
"dl_color.h",
|
||||
"dl_op_flags.cc",
|
||||
"dl_op_flags.h",
|
||||
"dl_op_receiver.cc",
|
||||
"dl_op_receiver.h",
|
||||
"dl_op_recorder.cc",
|
||||
"dl_op_recorder.h",
|
||||
"dl_op_records.cc",
|
||||
"dl_op_records.h",
|
||||
"dl_paint.cc",
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/display_list/benchmarking/dl_benchmarks.h"
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/display_list/dl_op_flags.h"
|
||||
#include "flutter/display_list/skia/dl_sk_canvas.h"
|
||||
|
||||
|
||||
@ -503,7 +503,7 @@ void DisplayListGLComplexityCalculator::GLHelper::drawVertices(
|
||||
}
|
||||
|
||||
void DisplayListGLComplexityCalculator::GLHelper::drawImage(
|
||||
const sk_sp<DlImage> image,
|
||||
const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) {
|
||||
@ -583,7 +583,7 @@ void DisplayListGLComplexityCalculator::GLHelper::ImageRect(
|
||||
}
|
||||
|
||||
void DisplayListGLComplexityCalculator::GLHelper::drawImageNine(
|
||||
const sk_sp<DlImage> image,
|
||||
const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
@ -608,7 +608,7 @@ void DisplayListGLComplexityCalculator::GLHelper::drawImageNine(
|
||||
}
|
||||
|
||||
void DisplayListGLComplexityCalculator::GLHelper::drawDisplayList(
|
||||
const sk_sp<DisplayList> display_list,
|
||||
const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity) {
|
||||
if (IsComplex()) {
|
||||
return;
|
||||
@ -622,7 +622,7 @@ void DisplayListGLComplexityCalculator::GLHelper::drawDisplayList(
|
||||
}
|
||||
|
||||
void DisplayListGLComplexityCalculator::GLHelper::drawTextBlob(
|
||||
const sk_sp<SkTextBlob> blob,
|
||||
const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) {
|
||||
if (IsComplex()) {
|
||||
|
||||
@ -56,18 +56,18 @@ class DisplayListGLComplexityCalculator
|
||||
uint32_t count,
|
||||
const SkPoint points[]) override;
|
||||
void drawVertices(const DlVertices* vertices, DlBlendMode mode) override;
|
||||
void drawImage(const sk_sp<DlImage> image,
|
||||
void drawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) override;
|
||||
void drawImageNine(const sk_sp<DlImage> image,
|
||||
void drawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
bool render_with_attributes) override;
|
||||
void drawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
void drawDisplayList(const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity) override;
|
||||
void drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
void drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) override;
|
||||
void drawShadow(const SkPath& path,
|
||||
|
||||
@ -146,7 +146,7 @@ class ComplexityCalculatorHelper
|
||||
}
|
||||
|
||||
void drawImageRect(
|
||||
const sk_sp<DlImage> image,
|
||||
const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
@ -159,7 +159,7 @@ class ComplexityCalculatorHelper
|
||||
render_with_attributes, constraint == SrcRectConstraint::kStrict);
|
||||
}
|
||||
|
||||
void drawAtlas(const sk_sp<DlImage> atlas,
|
||||
void drawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
|
||||
@ -455,7 +455,7 @@ void DisplayListMetalComplexityCalculator::MetalHelper::drawVertices(
|
||||
}
|
||||
|
||||
void DisplayListMetalComplexityCalculator::MetalHelper::drawImage(
|
||||
const sk_sp<DlImage> image,
|
||||
const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) {
|
||||
@ -532,7 +532,7 @@ void DisplayListMetalComplexityCalculator::MetalHelper::ImageRect(
|
||||
}
|
||||
|
||||
void DisplayListMetalComplexityCalculator::MetalHelper::drawImageNine(
|
||||
const sk_sp<DlImage> image,
|
||||
const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
@ -552,7 +552,7 @@ void DisplayListMetalComplexityCalculator::MetalHelper::drawImageNine(
|
||||
}
|
||||
|
||||
void DisplayListMetalComplexityCalculator::MetalHelper::drawDisplayList(
|
||||
const sk_sp<DisplayList> display_list,
|
||||
const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity) {
|
||||
if (IsComplex()) {
|
||||
return;
|
||||
@ -566,7 +566,7 @@ void DisplayListMetalComplexityCalculator::MetalHelper::drawDisplayList(
|
||||
}
|
||||
|
||||
void DisplayListMetalComplexityCalculator::MetalHelper::drawTextBlob(
|
||||
const sk_sp<SkTextBlob> blob,
|
||||
const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) {
|
||||
if (IsComplex()) {
|
||||
|
||||
@ -56,18 +56,18 @@ class DisplayListMetalComplexityCalculator
|
||||
uint32_t count,
|
||||
const SkPoint points[]) override;
|
||||
void drawVertices(const DlVertices* vertices, DlBlendMode mode) override;
|
||||
void drawImage(const sk_sp<DlImage> image,
|
||||
void drawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) override;
|
||||
void drawImageNine(const sk_sp<DlImage> image,
|
||||
void drawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
bool render_with_attributes) override;
|
||||
void drawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
void drawDisplayList(const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity) override;
|
||||
void drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
void drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) override;
|
||||
void drawShadow(const SkPath& path,
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#include "flutter/display_list/benchmarking/dl_complexity_gl.h"
|
||||
#include "flutter/display_list/benchmarking/dl_complexity_metal.h"
|
||||
#include "flutter/display_list/display_list.h"
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/display_list/dl_sampling_options.h"
|
||||
#include "flutter/display_list/testing/dl_test_snippets.h"
|
||||
#include "flutter/testing/testing.h"
|
||||
@ -102,7 +102,7 @@ TEST(DisplayListComplexity, StrokeWidth) {
|
||||
auto display_list_stroke_0 = builder_stroke_0.Build();
|
||||
|
||||
DisplayListBuilder builder_stroke_1;
|
||||
builder_stroke_0.DrawLine(SkPoint::Make(0, 0), SkPoint::Make(100, 100),
|
||||
builder_stroke_1.DrawLine(SkPoint::Make(0, 0), SkPoint::Make(100, 100),
|
||||
DlPaint().setStrokeWidth(1.0f));
|
||||
auto display_list_stroke_1 = builder_stroke_1.Build();
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ const SaveLayerOptions SaveLayerOptions::kWithAttributes =
|
||||
kNoAttributes.with_renders_with_attributes();
|
||||
|
||||
DisplayList::DisplayList()
|
||||
: byte_count_(0),
|
||||
: storage_(),
|
||||
op_count_(0),
|
||||
nested_byte_count_(0),
|
||||
nested_op_count_(0),
|
||||
@ -25,8 +25,7 @@ DisplayList::DisplayList()
|
||||
is_ui_thread_safe_(true),
|
||||
modifies_transparent_black_(false) {}
|
||||
|
||||
DisplayList::DisplayList(DisplayListStorage&& storage,
|
||||
size_t byte_count,
|
||||
DisplayList::DisplayList(DlStorage&& storage,
|
||||
unsigned int op_count,
|
||||
size_t nested_byte_count,
|
||||
unsigned int nested_op_count,
|
||||
@ -36,7 +35,6 @@ DisplayList::DisplayList(DisplayListStorage&& storage,
|
||||
bool modifies_transparent_black,
|
||||
sk_sp<const DlRTree> rtree)
|
||||
: storage_(std::move(storage)),
|
||||
byte_count_(byte_count),
|
||||
op_count_(op_count),
|
||||
nested_byte_count_(nested_byte_count),
|
||||
nested_op_count_(nested_op_count),
|
||||
@ -47,9 +45,65 @@ DisplayList::DisplayList(DisplayListStorage&& storage,
|
||||
modifies_transparent_black_(modifies_transparent_black),
|
||||
rtree_(std::move(rtree)) {}
|
||||
|
||||
DisplayList::~DisplayList() {
|
||||
uint8_t* ptr = storage_.get();
|
||||
DisposeOps(ptr, ptr + byte_count_);
|
||||
DisplayList::DlStorage::DlStorage(DisplayList::DlStorage&& source)
|
||||
: ptr_(std::move(source.ptr_)),
|
||||
used_(source.used_),
|
||||
allocated_(source.allocated_) {
|
||||
FML_DCHECK(source.ptr_.get() == nullptr);
|
||||
FML_DCHECK(!source.disabled_);
|
||||
source.ptr_ = nullptr;
|
||||
source.used_ = 0u;
|
||||
source.allocated_ = 0u;
|
||||
source.disabled_ = true;
|
||||
}
|
||||
|
||||
DisplayList::DlStorage::~DlStorage() {
|
||||
uint8_t* ptr = get();
|
||||
if (ptr != nullptr) {
|
||||
FML_DCHECK(used_ <= allocated_);
|
||||
DisposeOps(ptr, ptr + used_);
|
||||
} else {
|
||||
FML_DCHECK(used_ == 0u);
|
||||
FML_DCHECK(allocated_ == 0u);
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr inline bool is_power_of_two(int value) {
|
||||
return (value & (value - 1)) == 0;
|
||||
}
|
||||
|
||||
uint8_t* DisplayList::DlStorage::alloc(size_t bytes) {
|
||||
if (disabled_) {
|
||||
FML_DCHECK(is_valid());
|
||||
return nullptr;
|
||||
}
|
||||
FML_DCHECK(bytes < (1 << 24));
|
||||
if (used_ + bytes > allocated_) {
|
||||
static_assert(is_power_of_two(kPageSize),
|
||||
"This math needs updating for non-pow2.");
|
||||
// Next greater multiple of DL_BUILDER_PAGE.
|
||||
allocated_ = (used_ + bytes + kPageSize) & ~(kPageSize - 1);
|
||||
realloc(allocated_);
|
||||
FML_DCHECK(get());
|
||||
memset(get() + used_, 0, allocated_ - used_);
|
||||
}
|
||||
FML_DCHECK(used_ + bytes <= allocated_);
|
||||
uint8_t* ret = get() + used_;
|
||||
used_ += bytes;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DisplayList::DlStorage::realloc(size_t count) {
|
||||
FML_DCHECK(is_valid());
|
||||
FML_DCHECK(count >= used_);
|
||||
ptr_.reset(static_cast<uint8_t*>(std::realloc(ptr_.release(), count)));
|
||||
allocated_ = count;
|
||||
FML_CHECK(ptr_);
|
||||
}
|
||||
|
||||
DisplayList::DlStorage DisplayList::DlStorage::take() {
|
||||
realloc(used_);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
uint32_t DisplayList::next_unique_id() {
|
||||
@ -112,10 +166,10 @@ class VectorCuller final : public Culler {
|
||||
}
|
||||
}
|
||||
void update(DispatchContext& context) override {
|
||||
if (++context.cur_index > context.next_render_index) {
|
||||
if (context.cur_render_index > context.next_render_index) {
|
||||
while (cur_ < end_) {
|
||||
context.next_render_index = rtree_->id(*cur_++);
|
||||
if (context.next_render_index >= context.cur_index) {
|
||||
if (context.next_render_index >= context.cur_render_index) {
|
||||
// It should be rare that we have duplicate indices
|
||||
// but if we do, then having a while loop is a cheap
|
||||
// insurance for those cases.
|
||||
@ -139,8 +193,7 @@ class VectorCuller final : public Culler {
|
||||
};
|
||||
|
||||
void DisplayList::Dispatch(DlOpReceiver& receiver) const {
|
||||
uint8_t* ptr = storage_.get();
|
||||
Dispatch(receiver, ptr, ptr + byte_count_, NopCuller::instance);
|
||||
Dispatch(receiver, storage_.get(), storage_.end(), NopCuller::instance);
|
||||
}
|
||||
|
||||
void DisplayList::Dispatch(DlOpReceiver& receiver,
|
||||
@ -164,11 +217,10 @@ void DisplayList::Dispatch(DlOpReceiver& receiver,
|
||||
Dispatch(receiver);
|
||||
return;
|
||||
}
|
||||
uint8_t* ptr = storage_.get();
|
||||
std::vector<int> rect_indices;
|
||||
rtree->search(cull_rect, &rect_indices);
|
||||
VectorCuller culler(rtree, rect_indices);
|
||||
Dispatch(receiver, ptr, ptr + byte_count_, culler);
|
||||
Dispatch(receiver, storage_.get(), storage_.end(), culler);
|
||||
}
|
||||
|
||||
void DisplayList::Dispatch(DlOpReceiver& receiver,
|
||||
@ -177,7 +229,7 @@ void DisplayList::Dispatch(DlOpReceiver& receiver,
|
||||
Culler& culler) const {
|
||||
DispatchContext context = {
|
||||
.receiver = receiver,
|
||||
.cur_index = 0,
|
||||
.cur_render_index = 0,
|
||||
// next_render_index will be initialized by culler.init()
|
||||
.next_restore_index = std::numeric_limits<int>::max(),
|
||||
};
|
||||
@ -209,7 +261,7 @@ void DisplayList::Dispatch(DlOpReceiver& receiver,
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayList::DisposeOps(uint8_t* ptr, uint8_t* end) {
|
||||
void DisplayList::DlStorage::DisposeOps(uint8_t* ptr, uint8_t* end) {
|
||||
while (ptr < end) {
|
||||
auto op = reinterpret_cast<const DLOp*>(ptr);
|
||||
ptr += op->size;
|
||||
@ -309,7 +361,8 @@ bool DisplayList::Equals(const DisplayList* other) const {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (byte_count_ != other->byte_count_ || op_count_ != other->op_count_) {
|
||||
if (storage_.used() != other->storage_.used() ||
|
||||
op_count_ != other->op_count_) {
|
||||
return false;
|
||||
}
|
||||
uint8_t* ptr = storage_.get();
|
||||
@ -317,7 +370,7 @@ bool DisplayList::Equals(const DisplayList* other) const {
|
||||
if (ptr == o_ptr) {
|
||||
return true;
|
||||
}
|
||||
return CompareOps(ptr, ptr + byte_count_, o_ptr, o_ptr + other->byte_count_);
|
||||
return CompareOps(ptr, storage_.end(), o_ptr, other->storage_.end());
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@ -150,7 +150,6 @@ enum class DisplayListOpType {
|
||||
#undef DL_OP_TO_ENUM_VALUE
|
||||
|
||||
class DlOpReceiver;
|
||||
class DisplayListBuilder;
|
||||
|
||||
class SaveLayerOptions {
|
||||
public:
|
||||
@ -202,26 +201,6 @@ class SaveLayerOptions {
|
||||
};
|
||||
};
|
||||
|
||||
// Manages a buffer allocated with malloc.
|
||||
class DisplayListStorage {
|
||||
public:
|
||||
DisplayListStorage() = default;
|
||||
DisplayListStorage(DisplayListStorage&&) = default;
|
||||
|
||||
uint8_t* get() const { return ptr_.get(); }
|
||||
|
||||
void realloc(size_t count) {
|
||||
ptr_.reset(static_cast<uint8_t*>(std::realloc(ptr_.release(), count)));
|
||||
FML_CHECK(ptr_);
|
||||
}
|
||||
|
||||
private:
|
||||
struct FreeDeleter {
|
||||
void operator()(uint8_t* p) { std::free(p); }
|
||||
};
|
||||
std::unique_ptr<uint8_t, FreeDeleter> ptr_;
|
||||
};
|
||||
|
||||
class Culler;
|
||||
|
||||
// The base class that contains a sequence of rendering operations
|
||||
@ -231,7 +210,7 @@ class DisplayList : public SkRefCnt {
|
||||
public:
|
||||
DisplayList();
|
||||
|
||||
~DisplayList();
|
||||
~DisplayList() = default;
|
||||
|
||||
void Dispatch(DlOpReceiver& ctx) const;
|
||||
void Dispatch(DlOpReceiver& ctx, const SkRect& cull_rect) const;
|
||||
@ -241,7 +220,8 @@ class DisplayList : public SkRefCnt {
|
||||
// but nested ops are only included if requested. The defaults used
|
||||
// here for these accessors follow that pattern.
|
||||
size_t bytes(bool nested = true) const {
|
||||
return sizeof(DisplayList) + byte_count_ +
|
||||
FML_DCHECK(storage_.used() == storage_.allocated());
|
||||
return sizeof(DisplayList) + storage_.allocated() +
|
||||
(nested ? nested_byte_count_ : 0);
|
||||
}
|
||||
|
||||
@ -279,8 +259,40 @@ class DisplayList : public SkRefCnt {
|
||||
}
|
||||
|
||||
private:
|
||||
DisplayList(DisplayListStorage&& ptr,
|
||||
size_t byte_count,
|
||||
// Manages a buffer allocated with malloc.
|
||||
class DlStorage {
|
||||
public:
|
||||
DlStorage() = default;
|
||||
DlStorage(DlStorage&& source);
|
||||
|
||||
~DlStorage();
|
||||
|
||||
uint8_t* get() const { return ptr_.get(); }
|
||||
uint8_t* end() const { return ptr_.get() + used_; }
|
||||
size_t used() const { return used_; }
|
||||
size_t allocated() const { return allocated_; }
|
||||
bool is_valid() const { return !disabled_; }
|
||||
|
||||
uint8_t* alloc(size_t bytes);
|
||||
void realloc(size_t count);
|
||||
DlStorage take();
|
||||
|
||||
private:
|
||||
static constexpr size_t kPageSize = 4096u;
|
||||
|
||||
static void DisposeOps(uint8_t* ptr, uint8_t* end);
|
||||
|
||||
struct FreeDeleter {
|
||||
void operator()(uint8_t* p) { std::free(p); }
|
||||
};
|
||||
std::unique_ptr<uint8_t, FreeDeleter> ptr_;
|
||||
|
||||
bool disabled_ = false;
|
||||
size_t used_ = 0u;
|
||||
size_t allocated_ = 0u;
|
||||
};
|
||||
|
||||
DisplayList(DlStorage&& ptr,
|
||||
unsigned int op_count,
|
||||
size_t nested_byte_count,
|
||||
unsigned int nested_op_count,
|
||||
@ -292,10 +304,7 @@ class DisplayList : public SkRefCnt {
|
||||
|
||||
static uint32_t next_unique_id();
|
||||
|
||||
static void DisposeOps(uint8_t* ptr, uint8_t* end);
|
||||
|
||||
const DisplayListStorage storage_;
|
||||
const size_t byte_count_;
|
||||
const DlStorage storage_;
|
||||
const unsigned int op_count_;
|
||||
|
||||
const size_t nested_byte_count_;
|
||||
@ -315,6 +324,7 @@ class DisplayList : public SkRefCnt {
|
||||
uint8_t* end,
|
||||
Culler& culler) const;
|
||||
|
||||
friend class DlOpRecorder;
|
||||
friend class DisplayListBuilder;
|
||||
};
|
||||
|
||||
|
||||
34
engine/src/flutter/display_list/display_list_builder.cc
Normal file
34
engine/src/flutter/display_list/display_list_builder.cc
Normal file
@ -0,0 +1,34 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
DisplayListBuilder::DisplayListBuilder(const SkRect& cull_rect,
|
||||
bool prepare_rtree)
|
||||
: DisplayListBuilder(
|
||||
std::make_shared<DlOpRecorder>(cull_rect, prepare_rtree)) {}
|
||||
|
||||
DisplayListBuilder::DisplayListBuilder(
|
||||
const std::shared_ptr<DlOpRecorder>& recorder)
|
||||
: DlCanvasToReceiver(recorder), recorder_(recorder) {}
|
||||
|
||||
sk_sp<DisplayList> DisplayListBuilder::Build() {
|
||||
FML_CHECK(recorder_ != nullptr);
|
||||
FML_CHECK(receiver_ != nullptr);
|
||||
|
||||
RestoreToCount(1);
|
||||
|
||||
sk_sp<DisplayList> dl =
|
||||
recorder_->Build(current_group_opacity_compatibility(),
|
||||
current_affects_transparent_layer());
|
||||
|
||||
recorder_ = nullptr;
|
||||
receiver_ = nullptr;
|
||||
|
||||
return dl;
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
59
engine/src/flutter/display_list/display_list_builder.h
Normal file
59
engine/src/flutter/display_list/display_list_builder.h
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_H_
|
||||
#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_H_
|
||||
|
||||
#include "flutter/display_list/dl_canvas.h"
|
||||
#include "flutter/display_list/dl_canvas_to_receiver.h"
|
||||
#include "flutter/display_list/dl_op_flags.h"
|
||||
#include "flutter/display_list/dl_op_receiver.h"
|
||||
#include "flutter/display_list/dl_op_recorder.h"
|
||||
#include "flutter/display_list/utils/dl_bounds_accumulator.h"
|
||||
#include "flutter/display_list/utils/dl_matrix_clip_tracker.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
// The primary class used to build a display list. The list of methods
|
||||
// here matches the list of methods invoked on a |DlOpReceiver| combined
|
||||
// with the list of methods invoked on a |DlCanvas|.
|
||||
class DisplayListBuilder final : public DlCanvasToReceiver, //
|
||||
public SkRefCnt {
|
||||
public:
|
||||
static constexpr SkRect kMaxCullRect =
|
||||
SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F);
|
||||
|
||||
explicit DisplayListBuilder(bool prepare_rtree)
|
||||
: DisplayListBuilder(kMaxCullRect, prepare_rtree) {}
|
||||
|
||||
explicit DisplayListBuilder(const SkRect& cull_rect = kMaxCullRect,
|
||||
bool prepare_rtree = false);
|
||||
|
||||
~DisplayListBuilder() = default;
|
||||
|
||||
sk_sp<DisplayList> Build();
|
||||
|
||||
private:
|
||||
explicit DisplayListBuilder(const std::shared_ptr<DlOpRecorder>& recorder);
|
||||
|
||||
std::shared_ptr<DlOpRecorder> recorder_;
|
||||
|
||||
// This method exposes the internal stateful DlOpReceiver implementation
|
||||
// of the DisplayListBuilder, primarily for testing purposes. Its use
|
||||
// is obsolete and forbidden in every other case and is only shared to a
|
||||
// pair of "friend" accessors in the benchmark/unittest files.
|
||||
DlOpReceiver& asReceiver() { return *receiver_; }
|
||||
|
||||
friend DlOpReceiver& DisplayListBuilderBenchmarkAccessor(
|
||||
DisplayListBuilder& builder);
|
||||
friend DlOpReceiver& DisplayListBuilderTestingAccessor(
|
||||
DisplayListBuilder& builder);
|
||||
friend DlPaint DisplayListBuilderTestingAttributes(
|
||||
DisplayListBuilder& builder);
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_H_
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,780 +0,0 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_H_
|
||||
#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_H_
|
||||
|
||||
#include "flutter/display_list/display_list.h"
|
||||
#include "flutter/display_list/dl_blend_mode.h"
|
||||
#include "flutter/display_list/dl_canvas.h"
|
||||
#include "flutter/display_list/dl_op_flags.h"
|
||||
#include "flutter/display_list/dl_op_receiver.h"
|
||||
#include "flutter/display_list/dl_paint.h"
|
||||
#include "flutter/display_list/dl_sampling_options.h"
|
||||
#include "flutter/display_list/effects/dl_path_effect.h"
|
||||
#include "flutter/display_list/image/dl_image.h"
|
||||
#include "flutter/display_list/utils/dl_bounds_accumulator.h"
|
||||
#include "flutter/display_list/utils/dl_comparable.h"
|
||||
#include "flutter/display_list/utils/dl_matrix_clip_tracker.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
// The primary class used to build a display list. The list of methods
|
||||
// here matches the list of methods invoked on a |DlOpReceiver| combined
|
||||
// with the list of methods invoked on a |DlCanvas|.
|
||||
class DisplayListBuilder final : public virtual DlCanvas,
|
||||
public SkRefCnt,
|
||||
virtual DlOpReceiver,
|
||||
DisplayListOpFlags {
|
||||
public:
|
||||
static constexpr SkRect kMaxCullRect =
|
||||
SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F);
|
||||
|
||||
explicit DisplayListBuilder(bool prepare_rtree)
|
||||
: DisplayListBuilder(kMaxCullRect, prepare_rtree) {}
|
||||
|
||||
explicit DisplayListBuilder(const SkRect& cull_rect = kMaxCullRect,
|
||||
bool prepare_rtree = false);
|
||||
|
||||
~DisplayListBuilder();
|
||||
|
||||
// |DlCanvas|
|
||||
SkISize GetBaseLayerSize() const override;
|
||||
// |DlCanvas|
|
||||
SkImageInfo GetImageInfo() const override;
|
||||
|
||||
// |DlCanvas|
|
||||
void Save() override;
|
||||
|
||||
// |DlCanvas|
|
||||
void SaveLayer(const SkRect* bounds,
|
||||
const DlPaint* paint = nullptr,
|
||||
const DlImageFilter* backdrop = nullptr) override;
|
||||
// |DlCanvas|
|
||||
void Restore() override;
|
||||
// |DlCanvas|
|
||||
int GetSaveCount() const override { return layer_stack_.size(); }
|
||||
// |DlCanvas|
|
||||
void RestoreToCount(int restore_count) override;
|
||||
|
||||
// |DlCanvas|
|
||||
void Translate(SkScalar tx, SkScalar ty) override;
|
||||
// |DlCanvas|
|
||||
void Scale(SkScalar sx, SkScalar sy) override;
|
||||
// |DlCanvas|
|
||||
void Rotate(SkScalar degrees) override;
|
||||
// |DlCanvas|
|
||||
void Skew(SkScalar sx, SkScalar sy) override;
|
||||
|
||||
// clang-format off
|
||||
// 2x3 2D affine subset of a 4x4 transform in row major order
|
||||
// |DlCanvas|
|
||||
void Transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt,
|
||||
SkScalar myx, SkScalar myy, SkScalar myt) override;
|
||||
// full 4x4 transform in row major order
|
||||
// |DlCanvas|
|
||||
void TransformFullPerspective(
|
||||
SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt,
|
||||
SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt,
|
||||
SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt,
|
||||
SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) override;
|
||||
// clang-format on
|
||||
// |DlCanvas|
|
||||
void TransformReset() override;
|
||||
// |DlCanvas|
|
||||
void Transform(const SkMatrix* matrix) override;
|
||||
// |DlCanvas|
|
||||
void Transform(const SkM44* matrix44) override;
|
||||
// |DlCanvas|
|
||||
void SetTransform(const SkMatrix* matrix) override {
|
||||
TransformReset();
|
||||
Transform(matrix);
|
||||
}
|
||||
// |DlCanvas|
|
||||
void SetTransform(const SkM44* matrix44) override {
|
||||
TransformReset();
|
||||
Transform(matrix44);
|
||||
}
|
||||
using DlCanvas::Transform;
|
||||
|
||||
/// Returns the 4x4 full perspective transform representing all transform
|
||||
/// operations executed so far in this DisplayList within the enclosing
|
||||
/// save stack.
|
||||
// |DlCanvas|
|
||||
SkM44 GetTransformFullPerspective() const override {
|
||||
return tracker_.matrix_4x4();
|
||||
}
|
||||
/// Returns the 3x3 partial perspective transform representing all transform
|
||||
/// operations executed so far in this DisplayList within the enclosing
|
||||
/// save stack.
|
||||
// |DlCanvas|
|
||||
SkMatrix GetTransform() const override { return tracker_.matrix_3x3(); }
|
||||
|
||||
// |DlCanvas|
|
||||
void ClipRect(const SkRect& rect,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) override;
|
||||
// |DlCanvas|
|
||||
void ClipRRect(const SkRRect& rrect,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) override;
|
||||
// |DlCanvas|
|
||||
void ClipPath(const SkPath& path,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) override;
|
||||
|
||||
/// Conservative estimate of the bounds of all outstanding clip operations
|
||||
/// measured in the coordinate space within which this DisplayList will
|
||||
/// be rendered.
|
||||
// |DlCanvas|
|
||||
SkRect GetDestinationClipBounds() const override {
|
||||
return tracker_.device_cull_rect();
|
||||
}
|
||||
/// Conservative estimate of the bounds of all outstanding clip operations
|
||||
/// transformed into the local coordinate space in which currently
|
||||
/// recorded rendering operations are interpreted.
|
||||
// |DlCanvas|
|
||||
SkRect GetLocalClipBounds() const override {
|
||||
return tracker_.local_cull_rect();
|
||||
}
|
||||
|
||||
/// Return true iff the supplied bounds are easily shown to be outside
|
||||
/// of the current clip bounds. This method may conservatively return
|
||||
/// false if it cannot make the determination.
|
||||
// |DlCanvas|
|
||||
bool QuickReject(const SkRect& bounds) const override;
|
||||
|
||||
// |DlCanvas|
|
||||
void DrawPaint(const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawColor(DlColor color, DlBlendMode mode) override;
|
||||
// |DlCanvas|
|
||||
void DrawLine(const SkPoint& p0,
|
||||
const SkPoint& p1,
|
||||
const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawRect(const SkRect& rect, const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawOval(const SkRect& bounds, const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawCircle(const SkPoint& center,
|
||||
SkScalar radius,
|
||||
const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawRRect(const SkRRect& rrect, const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawDRRect(const SkRRect& outer,
|
||||
const SkRRect& inner,
|
||||
const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawPath(const SkPath& path, const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawArc(const SkRect& bounds,
|
||||
SkScalar start,
|
||||
SkScalar sweep,
|
||||
bool useCenter,
|
||||
const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawPoints(PointMode mode,
|
||||
uint32_t count,
|
||||
const SkPoint pts[],
|
||||
const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawVertices(const DlVertices* vertices,
|
||||
DlBlendMode mode,
|
||||
const DlPaint& paint) override;
|
||||
using DlCanvas::DrawVertices;
|
||||
// |DlCanvas|
|
||||
void DrawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
const DlPaint* paint = nullptr) override;
|
||||
// |DlCanvas|
|
||||
void DrawImageRect(
|
||||
const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
const DlPaint* paint = nullptr,
|
||||
SrcRectConstraint constraint = SrcRectConstraint::kFast) override;
|
||||
using DlCanvas::DrawImageRect;
|
||||
// |DlCanvas|
|
||||
void DrawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
const DlPaint* paint = nullptr) override;
|
||||
// |DlCanvas|
|
||||
void DrawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
int count,
|
||||
DlBlendMode mode,
|
||||
DlImageSampling sampling,
|
||||
const SkRect* cullRect,
|
||||
const DlPaint* paint = nullptr) override;
|
||||
// |DlCanvas|
|
||||
void DrawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
SkScalar opacity = SK_Scalar1) override;
|
||||
// |DlCanvas|
|
||||
void DrawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y,
|
||||
const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawShadow(const SkPath& path,
|
||||
const DlColor color,
|
||||
const SkScalar elevation,
|
||||
bool transparent_occluder,
|
||||
SkScalar dpr) override;
|
||||
|
||||
// |DlCanvas|
|
||||
void Flush() override {}
|
||||
|
||||
sk_sp<DisplayList> Build();
|
||||
|
||||
private:
|
||||
// This method exposes the internal stateful DlOpReceiver implementation
|
||||
// of the DisplayListBuilder, primarily for testing purposes. Its use
|
||||
// is obsolete and forbidden in every other case and is only shared to a
|
||||
// pair of "friend" accessors in the benchmark/unittest files.
|
||||
DlOpReceiver& asReceiver() { return *this; }
|
||||
|
||||
friend DlOpReceiver& DisplayListBuilderBenchmarkAccessor(
|
||||
DisplayListBuilder& builder);
|
||||
friend DlOpReceiver& DisplayListBuilderTestingAccessor(
|
||||
DisplayListBuilder& builder);
|
||||
friend DlPaint DisplayListBuilderTestingAttributes(
|
||||
DisplayListBuilder& builder);
|
||||
|
||||
void SetAttributesFromPaint(const DlPaint& paint,
|
||||
const DisplayListAttributeFlags flags);
|
||||
|
||||
// |DlOpReceiver|
|
||||
void setAntiAlias(bool aa) override {
|
||||
if (current_.isAntiAlias() != aa) {
|
||||
onSetAntiAlias(aa);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setDither(bool dither) override {
|
||||
if (current_.isDither() != dither) {
|
||||
onSetDither(dither);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setInvertColors(bool invert) override {
|
||||
if (current_.isInvertColors() != invert) {
|
||||
onSetInvertColors(invert);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setStrokeCap(DlStrokeCap cap) override {
|
||||
if (current_.getStrokeCap() != cap) {
|
||||
onSetStrokeCap(cap);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setStrokeJoin(DlStrokeJoin join) override {
|
||||
if (current_.getStrokeJoin() != join) {
|
||||
onSetStrokeJoin(join);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setDrawStyle(DlDrawStyle style) override {
|
||||
if (current_.getDrawStyle() != style) {
|
||||
onSetDrawStyle(style);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setStrokeWidth(float width) override {
|
||||
if (current_.getStrokeWidth() != width) {
|
||||
onSetStrokeWidth(width);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setStrokeMiter(float limit) override {
|
||||
if (current_.getStrokeMiter() != limit) {
|
||||
onSetStrokeMiter(limit);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setColor(DlColor color) override {
|
||||
if (current_.getColor() != color) {
|
||||
onSetColor(color);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setBlendMode(DlBlendMode mode) override {
|
||||
if (current_.getBlendMode() != mode) {
|
||||
onSetBlendMode(mode);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setColorSource(const DlColorSource* source) override {
|
||||
if (NotEquals(current_.getColorSource(), source)) {
|
||||
onSetColorSource(source);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setImageFilter(const DlImageFilter* filter) override {
|
||||
if (NotEquals(current_.getImageFilter(), filter)) {
|
||||
onSetImageFilter(filter);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setColorFilter(const DlColorFilter* filter) override {
|
||||
if (NotEquals(current_.getColorFilter(), filter)) {
|
||||
onSetColorFilter(filter);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setPathEffect(const DlPathEffect* effect) override {
|
||||
if (NotEquals(current_.getPathEffect(), effect)) {
|
||||
onSetPathEffect(effect);
|
||||
}
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void setMaskFilter(const DlMaskFilter* filter) override {
|
||||
if (NotEquals(current_.getMaskFilter(), filter)) {
|
||||
onSetMaskFilter(filter);
|
||||
}
|
||||
}
|
||||
|
||||
DlPaint CurrentAttributes() const { return current_; }
|
||||
|
||||
// |DlOpReceiver|
|
||||
void save() override { Save(); }
|
||||
// Only the |renders_with_attributes()| option will be accepted here. Any
|
||||
// other flags will be ignored and calculated anew as the DisplayList is
|
||||
// built. Alternatively, use the |saveLayer(SkRect, bool)| method.
|
||||
// |DlOpReceiver|
|
||||
void saveLayer(const SkRect* bounds,
|
||||
const SaveLayerOptions options,
|
||||
const DlImageFilter* backdrop) override;
|
||||
// |DlOpReceiver|
|
||||
void restore() override { Restore(); }
|
||||
|
||||
// |DlOpReceiver|
|
||||
void translate(SkScalar tx, SkScalar ty) override { Translate(tx, ty); }
|
||||
// |DlOpReceiver|
|
||||
void scale(SkScalar sx, SkScalar sy) override { Scale(sx, sy); }
|
||||
// |DlOpReceiver|
|
||||
void rotate(SkScalar degrees) override { Rotate(degrees); }
|
||||
// |DlOpReceiver|
|
||||
void skew(SkScalar sx, SkScalar sy) override { Skew(sx, sy); }
|
||||
|
||||
// clang-format off
|
||||
// |DlOpReceiver|
|
||||
void transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt,
|
||||
SkScalar myx, SkScalar myy, SkScalar myt) override {
|
||||
Transform2DAffine(mxx, mxy, mxt, myx, myy, myt);
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void transformFullPerspective(
|
||||
SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt,
|
||||
SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt,
|
||||
SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt,
|
||||
SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) override {
|
||||
TransformFullPerspective(mxx, mxy, mxz, mxt,
|
||||
myx, myy, myz, myt,
|
||||
mzx, mzy, mzz, mzt,
|
||||
mwx, mwy, mwz, mwt);
|
||||
}
|
||||
// clang-format off
|
||||
// |DlOpReceiver|
|
||||
void transformReset() override { TransformReset(); }
|
||||
|
||||
// |DlOpReceiver|
|
||||
void clipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) override {
|
||||
ClipRect(rect, clip_op, is_aa);
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) override {
|
||||
ClipRRect(rrect, clip_op, is_aa);
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void clipPath(const SkPath& path, ClipOp clip_op, bool is_aa) override {
|
||||
ClipPath(path, clip_op, is_aa);
|
||||
}
|
||||
|
||||
// |DlOpReceiver|
|
||||
void drawPaint() override;
|
||||
// |DlOpReceiver|
|
||||
void drawColor(DlColor color, DlBlendMode mode) override {
|
||||
DrawColor(color, mode);
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void drawLine(const SkPoint& p0, const SkPoint& p1) override;
|
||||
// |DlOpReceiver|
|
||||
void drawRect(const SkRect& rect) override;
|
||||
// |DlOpReceiver|
|
||||
void drawOval(const SkRect& bounds) override;
|
||||
// |DlOpReceiver|
|
||||
void drawCircle(const SkPoint& center, SkScalar radius) override;
|
||||
// |DlOpReceiver|
|
||||
void drawRRect(const SkRRect& rrect) override;
|
||||
// |DlOpReceiver|
|
||||
void drawDRRect(const SkRRect& outer, const SkRRect& inner) override;
|
||||
// |DlOpReceiver|
|
||||
void drawPath(const SkPath& path) override;
|
||||
// |DlOpReceiver|
|
||||
void drawArc(const SkRect& bounds,
|
||||
SkScalar start,
|
||||
SkScalar sweep,
|
||||
bool useCenter) override;
|
||||
// |DlOpReceiver|
|
||||
void drawPoints(PointMode mode, uint32_t count, const SkPoint pts[]) override;
|
||||
// |DlOpReceiver|
|
||||
void drawVertices(const DlVertices* vertices, DlBlendMode mode) override;
|
||||
|
||||
// |DlOpReceiver|
|
||||
void drawImage(const sk_sp<DlImage> image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) override;
|
||||
// |DlOpReceiver|
|
||||
void drawImageRect(
|
||||
const sk_sp<DlImage> image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes,
|
||||
SrcRectConstraint constraint = SrcRectConstraint::kFast) override;
|
||||
// |DlOpReceiver|
|
||||
void drawImageNine(const sk_sp<DlImage> image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
bool render_with_attributes) override;
|
||||
// |DlOpReceiver|
|
||||
void drawAtlas(const sk_sp<DlImage> atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
int count,
|
||||
DlBlendMode mode,
|
||||
DlImageSampling sampling,
|
||||
const SkRect* cullRect,
|
||||
bool render_with_attributes) override;
|
||||
|
||||
// |DlOpReceiver|
|
||||
void drawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
SkScalar opacity) override {
|
||||
DrawDisplayList(display_list, opacity);
|
||||
}
|
||||
// |DlOpReceiver|
|
||||
void drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
SkScalar x,
|
||||
SkScalar y) override;
|
||||
// |DlOpReceiver|
|
||||
void drawShadow(const SkPath& path,
|
||||
const DlColor color,
|
||||
const SkScalar elevation,
|
||||
bool transparent_occluder,
|
||||
SkScalar dpr) override {
|
||||
DrawShadow(path, color, elevation, transparent_occluder, dpr);
|
||||
}
|
||||
|
||||
void checkForDeferredSave();
|
||||
|
||||
DisplayListStorage storage_;
|
||||
size_t used_ = 0;
|
||||
size_t allocated_ = 0;
|
||||
int render_op_count_ = 0;
|
||||
int op_index_ = 0;
|
||||
|
||||
// bytes and ops from |drawPicture| and |drawDisplayList|
|
||||
size_t nested_bytes_ = 0;
|
||||
int nested_op_count_ = 0;
|
||||
|
||||
bool is_ui_thread_safe_ = true;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
void* Push(size_t extra, int op_inc, Args&&... args);
|
||||
|
||||
void intersect(const SkRect& rect);
|
||||
|
||||
// kInvalidSigma is used to indicate that no MaskBlur is currently set.
|
||||
static constexpr SkScalar kInvalidSigma = 0.0;
|
||||
static bool mask_sigma_valid(SkScalar sigma) {
|
||||
return SkScalarIsFinite(sigma) && sigma > 0.0;
|
||||
}
|
||||
|
||||
class LayerInfo {
|
||||
public:
|
||||
explicit LayerInfo(
|
||||
size_t save_offset = 0,
|
||||
bool has_layer = false,
|
||||
const std::shared_ptr<const DlImageFilter>& filter = nullptr)
|
||||
: save_offset_(save_offset),
|
||||
has_layer_(has_layer),
|
||||
filter_(filter) {}
|
||||
|
||||
// The offset into the memory buffer where the saveLayer DLOp record
|
||||
// for this saveLayer() call is placed. This may be needed if the
|
||||
// eventual restore() call has discovered important information about
|
||||
// the records inside the saveLayer that may impact how the saveLayer
|
||||
// is handled (e.g., |cannot_inherit_opacity| == false).
|
||||
// This offset is only valid if |has_layer| is true.
|
||||
size_t save_offset() const { return save_offset_; }
|
||||
|
||||
bool has_layer() const { return has_layer_; }
|
||||
bool cannot_inherit_opacity() const { return cannot_inherit_opacity_; }
|
||||
bool has_compatible_op() const { return has_compatible_op_; }
|
||||
bool affects_transparent_layer() const {
|
||||
return affects_transparent_layer_;
|
||||
}
|
||||
|
||||
bool is_group_opacity_compatible() const {
|
||||
return !cannot_inherit_opacity_;
|
||||
}
|
||||
|
||||
void mark_incompatible() { cannot_inherit_opacity_ = true; }
|
||||
|
||||
// For now this only allows a single compatible op to mark the
|
||||
// layer as being compatible with group opacity. If we start
|
||||
// computing bounds of ops in the Builder methods then we
|
||||
// can upgrade this to checking for overlapping ops.
|
||||
// See https://github.com/flutter/flutter/issues/93899
|
||||
void add_compatible_op() {
|
||||
if (!cannot_inherit_opacity_) {
|
||||
if (has_compatible_op_) {
|
||||
cannot_inherit_opacity_ = true;
|
||||
} else {
|
||||
has_compatible_op_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Records that the current layer contains an op that produces visible
|
||||
// output on a transparent surface.
|
||||
void add_visible_op() {
|
||||
affects_transparent_layer_ = true;
|
||||
}
|
||||
|
||||
// The filter to apply to the layer bounds when it is restored
|
||||
std::shared_ptr<const DlImageFilter> filter() { return filter_; }
|
||||
|
||||
// is_unbounded should be set to true if we ever encounter an operation
|
||||
// on a layer that either is unrestricted (|drawColor| or |drawPaint|)
|
||||
// or cannot compute its bounds (some effects and filters) and there
|
||||
// was no outstanding clip op at the time.
|
||||
// When the layer is restored, the outer layer may then process this
|
||||
// unbounded state by accumulating its own clip or transferring the
|
||||
// unbounded state to its own outer layer.
|
||||
// Typically the DisplayList will have been constructed with a cull
|
||||
// rect which will act as a default clip for the outermost layer and
|
||||
// the unbounded state of all sub layers will eventually be caught by
|
||||
// that cull rect so that the overall unbounded state of the entire
|
||||
// DisplayList will never be true.
|
||||
//
|
||||
// For historical consistency it is worth noting that SkPicture used
|
||||
// to treat these same conditions as a Nop (they accumulate the
|
||||
// SkPicture cull rect, but if no cull rect was specified then it is
|
||||
// an empty Rect and so has no effect on the bounds).
|
||||
//
|
||||
// Flutter is unlikely to ever run into this as the Dart mechanisms
|
||||
// all supply a non-null cull rect for all Dart Picture objects,
|
||||
// even if that cull rect is kGiantRect.
|
||||
void set_unbounded() { is_unbounded_ = true; }
|
||||
|
||||
// |is_unbounded| should be called after |getLayerBounds| in case
|
||||
// a problem was found during the computation of those bounds,
|
||||
// the layer will have one last chance to flag an unbounded state.
|
||||
bool is_unbounded() const { return is_unbounded_; }
|
||||
|
||||
private:
|
||||
size_t save_offset_;
|
||||
bool has_layer_;
|
||||
bool cannot_inherit_opacity_ = false;
|
||||
bool has_compatible_op_ = false;
|
||||
std::shared_ptr<const DlImageFilter> filter_;
|
||||
bool is_unbounded_ = false;
|
||||
bool has_deferred_save_op_ = false;
|
||||
bool is_nop_ = false;
|
||||
bool affects_transparent_layer_ = false;
|
||||
|
||||
friend class DisplayListBuilder;
|
||||
};
|
||||
|
||||
std::vector<LayerInfo> layer_stack_;
|
||||
LayerInfo* current_layer_;
|
||||
DisplayListMatrixClipTracker tracker_;
|
||||
std::unique_ptr<BoundsAccumulator> accumulator_;
|
||||
BoundsAccumulator* accumulator() { return accumulator_.get(); }
|
||||
|
||||
// This flag indicates whether or not the current rendering attributes
|
||||
// are compatible with rendering ops applying an inherited opacity.
|
||||
bool current_opacity_compatibility_ = true;
|
||||
|
||||
// Returns the compatibility of a given blend mode for applying an
|
||||
// inherited opacity value to modulate the visibility of the op.
|
||||
// For now we only accept SrcOver blend modes but this could be expanded
|
||||
// in the future to include other (rarely used) modes that also modulate
|
||||
// the opacity of a rendering operation at the cost of a switch statement
|
||||
// or lookup table.
|
||||
static bool IsOpacityCompatible(DlBlendMode mode) {
|
||||
return (mode == DlBlendMode::kSrcOver);
|
||||
}
|
||||
|
||||
void UpdateCurrentOpacityCompatibility() {
|
||||
current_opacity_compatibility_ = //
|
||||
current_.getColorFilter() == nullptr && //
|
||||
!current_.isInvertColors() && //
|
||||
IsOpacityCompatible(current_.getBlendMode());
|
||||
}
|
||||
|
||||
// Update the opacity compatibility flags of the current layer for an op
|
||||
// that has determined its compatibility as indicated by |compatible|.
|
||||
void UpdateLayerOpacityCompatibility(bool compatible) {
|
||||
if (compatible) {
|
||||
current_layer_->add_compatible_op();
|
||||
} else {
|
||||
current_layer_->mark_incompatible();
|
||||
}
|
||||
}
|
||||
|
||||
// Check for opacity compatibility for an op that may or may not use the
|
||||
// current rendering attributes as indicated by |uses_blend_attribute|.
|
||||
// If the flag is false then the rendering op will be able to substitute
|
||||
// a default Paint object with the opacity applied using the default SrcOver
|
||||
// blend mode which is always compatible with applying an inherited opacity.
|
||||
void CheckLayerOpacityCompatibility(bool uses_blend_attribute = true) {
|
||||
UpdateLayerOpacityCompatibility(!uses_blend_attribute ||
|
||||
current_opacity_compatibility_);
|
||||
}
|
||||
|
||||
void CheckLayerOpacityHairlineCompatibility() {
|
||||
UpdateLayerOpacityCompatibility(
|
||||
current_opacity_compatibility_ &&
|
||||
(current_.getDrawStyle() == DlDrawStyle::kFill ||
|
||||
current_.getStrokeWidth() > 0));
|
||||
}
|
||||
|
||||
// Check for opacity compatibility for an op that ignores the current
|
||||
// attributes and uses the indicated blend |mode| to render to the layer.
|
||||
// This is only used by |drawColor| currently.
|
||||
void CheckLayerOpacityCompatibility(DlBlendMode mode) {
|
||||
UpdateLayerOpacityCompatibility(IsOpacityCompatible(mode));
|
||||
}
|
||||
|
||||
void onSetAntiAlias(bool aa);
|
||||
void onSetDither(bool dither);
|
||||
void onSetInvertColors(bool invert);
|
||||
void onSetStrokeCap(DlStrokeCap cap);
|
||||
void onSetStrokeJoin(DlStrokeJoin join);
|
||||
void onSetDrawStyle(DlDrawStyle style);
|
||||
void onSetStrokeWidth(SkScalar width);
|
||||
void onSetStrokeMiter(SkScalar limit);
|
||||
void onSetColor(DlColor color);
|
||||
void onSetBlendMode(DlBlendMode mode);
|
||||
void onSetColorSource(const DlColorSource* source);
|
||||
void onSetImageFilter(const DlImageFilter* filter);
|
||||
void onSetColorFilter(const DlColorFilter* filter);
|
||||
void onSetPathEffect(const DlPathEffect* effect);
|
||||
void onSetMaskFilter(const DlMaskFilter* filter);
|
||||
|
||||
// The DisplayList had an unbounded call with no cull rect or clip
|
||||
// to contain it. Should only be called after the stream is fully
|
||||
// built.
|
||||
// Unbounded operations are calls like |drawColor| which are defined
|
||||
// to flood the entire surface, or calls that relied on a rendering
|
||||
// attribute which is unable to compute bounds (should be rare).
|
||||
// In those cases the bounds will represent only the accumulation
|
||||
// of the bounded calls and this flag will be set to indicate that
|
||||
// condition.
|
||||
bool is_unbounded() const {
|
||||
FML_DCHECK(layer_stack_.size() == 1);
|
||||
return layer_stack_.front().is_unbounded();
|
||||
}
|
||||
|
||||
SkRect bounds() const {
|
||||
FML_DCHECK(layer_stack_.size() == 1);
|
||||
if (is_unbounded()) {
|
||||
FML_LOG(INFO) << "returning partial bounds for unbounded DisplayList";
|
||||
}
|
||||
|
||||
return accumulator_->bounds();
|
||||
}
|
||||
|
||||
sk_sp<DlRTree> rtree() {
|
||||
FML_DCHECK(layer_stack_.size() == 1);
|
||||
if (is_unbounded()) {
|
||||
FML_LOG(INFO) << "returning partial rtree for unbounded DisplayList";
|
||||
}
|
||||
|
||||
return accumulator_->rtree();
|
||||
}
|
||||
|
||||
static DisplayListAttributeFlags FlagsForPointMode(PointMode mode);
|
||||
|
||||
enum class OpResult {
|
||||
kNoEffect,
|
||||
kPreservesTransparency,
|
||||
kAffectsAll,
|
||||
};
|
||||
|
||||
bool paint_nops_on_transparency();
|
||||
OpResult PaintResult(const DlPaint& paint,
|
||||
DisplayListAttributeFlags flags = kDrawPaintFlags);
|
||||
|
||||
void UpdateLayerResult(OpResult result) {
|
||||
switch (result) {
|
||||
case OpResult::kNoEffect:
|
||||
case OpResult::kPreservesTransparency:
|
||||
break;
|
||||
case OpResult::kAffectsAll:
|
||||
current_layer_->add_visible_op();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// kAnyColor is a non-opaque and non-transparent color that will not
|
||||
// trigger any short-circuit tests about the results of a blend.
|
||||
static constexpr DlColor kAnyColor = DlColor::kMidGrey().withAlpha(0x80);
|
||||
static_assert(!kAnyColor.isOpaque());
|
||||
static_assert(!kAnyColor.isTransparent());
|
||||
static DlColor GetEffectiveColor(const DlPaint& paint,
|
||||
DisplayListAttributeFlags flags);
|
||||
|
||||
// Computes the bounds of an operation adjusted for a given ImageFilter
|
||||
// and returns whether the computation was possible. If the method
|
||||
// returns false then the caller should assume the worst about the bounds.
|
||||
static bool ComputeFilteredBounds(SkRect& bounds,
|
||||
const DlImageFilter* filter);
|
||||
|
||||
// Adjusts the indicated bounds for the given flags and returns true if
|
||||
// the calculation was possible, or false if it could not be estimated.
|
||||
bool AdjustBoundsForPaint(SkRect& bounds, DisplayListAttributeFlags flags);
|
||||
|
||||
// Records the fact that we encountered an op that either could not
|
||||
// estimate its bounds or that fills all of the destination space.
|
||||
bool AccumulateUnbounded();
|
||||
|
||||
// Records the bounds for an op after modifying them according to the
|
||||
// supplied attribute flags and transforming by the current matrix.
|
||||
bool AccumulateOpBounds(const SkRect& bounds,
|
||||
DisplayListAttributeFlags flags) {
|
||||
SkRect safe_bounds = bounds;
|
||||
return AccumulateOpBounds(safe_bounds, flags);
|
||||
}
|
||||
|
||||
// Records the bounds for an op after modifying them according to the
|
||||
// supplied attribute flags and transforming by the current matrix
|
||||
// and clipping against the current clip.
|
||||
bool AccumulateOpBounds(SkRect& bounds, DisplayListAttributeFlags flags);
|
||||
|
||||
// Records the given bounds after transforming by the current matrix
|
||||
// and clipping against the current clip.
|
||||
bool AccumulateBounds(SkRect& bounds);
|
||||
|
||||
DlPaint current_;
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_BUILDER_H_
|
||||
1152
engine/src/flutter/display_list/dl_canvas_to_receiver.cc
Normal file
1152
engine/src/flutter/display_list/dl_canvas_to_receiver.cc
Normal file
File diff suppressed because it is too large
Load Diff
565
engine/src/flutter/display_list/dl_canvas_to_receiver.h
Normal file
565
engine/src/flutter/display_list/dl_canvas_to_receiver.h
Normal file
@ -0,0 +1,565 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_DISPLAY_LIST_DL_CANVAS_TO_RECEIVER_H_
|
||||
#define FLUTTER_DISPLAY_LIST_DL_CANVAS_TO_RECEIVER_H_
|
||||
|
||||
#include "flutter/display_list/dl_canvas.h"
|
||||
#include "flutter/display_list/dl_op_flags.h"
|
||||
#include "flutter/display_list/dl_op_receiver.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
class DlCanvasReceiver : public DlOpReceiver {
|
||||
private:
|
||||
using ClipOp = DlCanvas::ClipOp;
|
||||
|
||||
public:
|
||||
virtual ~DlCanvasReceiver() = default;
|
||||
|
||||
virtual SkRect base_device_cull_rect() const = 0;
|
||||
|
||||
virtual SkM44 matrix_4x4() const = 0;
|
||||
virtual SkMatrix matrix_3x3() const { return matrix_4x4().asM33(); }
|
||||
|
||||
virtual SkRect device_cull_rect() const = 0;
|
||||
virtual SkRect local_cull_rect() const = 0;
|
||||
virtual bool is_cull_rect_empty() const = 0;
|
||||
virtual bool content_culled(const SkRect& content_bounds) const = 0;
|
||||
|
||||
/*--------- Methods below here are optional optimizations --------*/
|
||||
|
||||
/// Optional - only needed if performing bounds culling via the accumulate
|
||||
/// methods
|
||||
/// Note: The bounds are only advisory for implementing bounds culling
|
||||
/// and should not trigger an actual clip operation.
|
||||
/// The default implementation ignores the advisory information.
|
||||
///
|
||||
/// This method should almost never be used as it breaks the encapsulation
|
||||
/// of the enclosing clips. However it is needed for practical purposes in
|
||||
/// some rare cases - such as when a saveLayer is collecting rendering
|
||||
/// operations prior to applying a filter on the entire layer bounds and
|
||||
/// some of those operations fall outside the enclosing clip, but their
|
||||
/// filtered content will spread out from where they were rendered on the
|
||||
/// layer into the enclosing clipped area.
|
||||
/// Omitting the |cull_rect| argument, or passing nullptr, will restore the
|
||||
/// cull rect to the initial value it had when the tracker was constructed.
|
||||
virtual void resetCullRect(const SkRect* cull_rect = nullptr) {}
|
||||
|
||||
/// Optional - only needed if performing bounds culling via the accumulate
|
||||
/// methods
|
||||
/// Note: The bounds are only advisory for implementing bounds culling
|
||||
/// and should not trigger an actual clip operation.
|
||||
/// The default implementation ignores the advisory information.
|
||||
///
|
||||
/// This method is used to add an additional culling bounds without
|
||||
/// actually performing a clip on the destination. The bounds will
|
||||
/// help avoid recording content of a saveLayer that lies entirely
|
||||
/// outside the save layer bounds if it had them.
|
||||
virtual void intersectCullRect(const SkRect& cull_rect) {}
|
||||
|
||||
/// Optional - only needed if implementing the accumulate methods
|
||||
/// The default implementation returns false to prevent extra work in
|
||||
/// the adapter.
|
||||
///
|
||||
/// If the receiver is accumulating bounds into, say, an rtree format,
|
||||
/// or wants granular bounds for any other reason, this query will let
|
||||
/// the adapter know that it should deliver the bounds of methods such
|
||||
/// as DrawDisplayList granularly if possible (i.e. if the DL being
|
||||
/// drawn itself has an RTree for its bounds).
|
||||
///
|
||||
/// Returns: true if the implementation can make use of granular bounds
|
||||
virtual bool wants_granular_bounds() const { return false; }
|
||||
|
||||
/// Optional - only needed if accumulating bounds or implementing bounds
|
||||
/// culling
|
||||
/// The default implementation ignores the bounds and returns true to
|
||||
/// prevent culling.
|
||||
///
|
||||
/// The indicated bounds were calculated for the next rendering op call.
|
||||
/// The receiver can ignore them if it is not accumulating the bounds,
|
||||
/// and can tag them appropriately if recording the bounds per rendering op.
|
||||
/// The receiver can also indicate if the bounds are clipped out with
|
||||
/// the returned boolean.
|
||||
///
|
||||
/// Returns: true if the bounds were not clipped
|
||||
/// or false if there is no way for these bounds to be visible
|
||||
virtual bool accumulateLocalBoundsForNextOp(const SkRect& r) { return true; }
|
||||
|
||||
/// Optional - only needed if accumulating bounds or implementing bounds
|
||||
/// culling
|
||||
/// The default implementation ignores the condition and returns true to
|
||||
/// prevent culling.
|
||||
///
|
||||
/// The bounds for the next rendering op will be "unbounded" by anything
|
||||
/// other than the current clip, whether because it is a |drawPaint| or
|
||||
/// |drawColor| call or because it is rendered with a filter that modifies
|
||||
/// all pixels (even transparent) out to infinity (or the clip).
|
||||
/// The receiver can ignore the information if it is not accumulating
|
||||
/// the bounds, and can tag them appropriately if recording the bounds
|
||||
/// per rendering op.
|
||||
/// The receiver can also indicate if the bounds are clipped out with
|
||||
/// the returned boolean.
|
||||
///
|
||||
/// Returns: true if the bounds were not clipped
|
||||
/// or false if there is no way for these bounds to be visible
|
||||
virtual bool accumulateUnboundedForNextOp() { return true; }
|
||||
|
||||
/// Optional - only needed if the provided information is useful to the
|
||||
/// implementation
|
||||
/// By default this method will simply call the regular |restore| method
|
||||
/// and the information will be ignored.
|
||||
///
|
||||
/// Called in lieue of a call to |restore| when the upstream code calls
|
||||
/// a restore on a |saveLayer| and there is information about the contents
|
||||
/// of the layer that the receiver might find interesting.
|
||||
virtual void restoreLayer(const DlImageFilter* filter,
|
||||
bool layer_content_was_unbounded,
|
||||
bool layer_could_distribute_opacity) {
|
||||
restore();
|
||||
}
|
||||
|
||||
/// Optional - useful to indicate non-renderable state such as an empty
|
||||
/// clip or collapsed transform to suspend rendering calls
|
||||
/// until the state is overridden or popped by a |restore|.
|
||||
/// By default this method returns false to prevent state culling.
|
||||
///
|
||||
/// The |is_nop| method will be called after any of the clip or
|
||||
/// transform methods to detect if the current conditions are
|
||||
/// now a NOP. The receiver will receive no more calls until the
|
||||
/// associated restore() call which will be dispatched to it, or
|
||||
/// a subsequent clip or transform "reset" operation.
|
||||
///
|
||||
/// Returns: true if either the clip or transform prevent rendering
|
||||
virtual bool is_nop() { return false; }
|
||||
};
|
||||
|
||||
// The primary class used to build a display list. The list of methods
|
||||
// here matches the list of methods invoked on a |DlOpReceiver| combined
|
||||
// with the list of methods invoked on a |DlCanvas|.
|
||||
class DlCanvasToReceiver : public virtual DlCanvas, //
|
||||
DisplayListOpFlags {
|
||||
public:
|
||||
explicit DlCanvasToReceiver(std::shared_ptr<DlCanvasReceiver> receiver);
|
||||
|
||||
~DlCanvasToReceiver() = default;
|
||||
|
||||
// |DlCanvas|
|
||||
SkISize GetBaseLayerSize() const override;
|
||||
// |DlCanvas|
|
||||
SkImageInfo GetImageInfo() const override;
|
||||
|
||||
// |DlCanvas|
|
||||
void Save() override;
|
||||
|
||||
// |DlCanvas|
|
||||
void SaveLayer(const SkRect* bounds,
|
||||
const DlPaint* paint = nullptr,
|
||||
const DlImageFilter* backdrop = nullptr) override;
|
||||
// |DlCanvas|
|
||||
void Restore() override;
|
||||
// |DlCanvas|
|
||||
int GetSaveCount() const override {
|
||||
CheckAlive();
|
||||
return layer_stack_.size();
|
||||
}
|
||||
// |DlCanvas|
|
||||
void RestoreToCount(int restore_count) override;
|
||||
|
||||
// |DlCanvas|
|
||||
void Translate(SkScalar tx, SkScalar ty) override;
|
||||
// |DlCanvas|
|
||||
void Scale(SkScalar sx, SkScalar sy) override;
|
||||
// |DlCanvas|
|
||||
void Rotate(SkScalar degrees) override;
|
||||
// |DlCanvas|
|
||||
void Skew(SkScalar sx, SkScalar sy) override;
|
||||
|
||||
// clang-format off
|
||||
// 2x3 2D affine subset of a 4x4 transform in row major order
|
||||
// |DlCanvas|
|
||||
void Transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt,
|
||||
SkScalar myx, SkScalar myy, SkScalar myt) override;
|
||||
// full 4x4 transform in row major order
|
||||
// |DlCanvas|
|
||||
void TransformFullPerspective(
|
||||
SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt,
|
||||
SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt,
|
||||
SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt,
|
||||
SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) override;
|
||||
// clang-format on
|
||||
// |DlCanvas|
|
||||
void TransformReset() override;
|
||||
// |DlCanvas|
|
||||
void Transform(const SkMatrix* matrix) override;
|
||||
// |DlCanvas|
|
||||
void Transform(const SkM44* matrix44) override;
|
||||
// |DlCanvas|
|
||||
void SetTransform(const SkMatrix* matrix) override {
|
||||
CheckAlive();
|
||||
TransformReset();
|
||||
Transform(matrix);
|
||||
}
|
||||
// |DlCanvas|
|
||||
void SetTransform(const SkM44* matrix44) override {
|
||||
CheckAlive();
|
||||
TransformReset();
|
||||
Transform(matrix44);
|
||||
}
|
||||
using DlCanvas::Transform;
|
||||
|
||||
/// Returns the 4x4 full perspective transform representing all transform
|
||||
/// operations executed so far in this DisplayList within the enclosing
|
||||
/// save stack.
|
||||
// |DlCanvas|
|
||||
SkM44 GetTransformFullPerspective() const override {
|
||||
CheckAlive();
|
||||
return receiver_->matrix_4x4();
|
||||
}
|
||||
/// Returns the 3x3 partial perspective transform representing all transform
|
||||
/// operations executed so far in this DisplayList within the enclosing
|
||||
/// save stack.
|
||||
// |DlCanvas|
|
||||
SkMatrix GetTransform() const override {
|
||||
CheckAlive();
|
||||
return receiver_->matrix_3x3();
|
||||
}
|
||||
|
||||
// |DlCanvas|
|
||||
void ClipRect(const SkRect& rect,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) override;
|
||||
// |DlCanvas|
|
||||
void ClipRRect(const SkRRect& rrect,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) override;
|
||||
// |DlCanvas|
|
||||
void ClipPath(const SkPath& path,
|
||||
ClipOp clip_op = ClipOp::kIntersect,
|
||||
bool is_aa = false) override;
|
||||
|
||||
/// Conservative estimate of the bounds of all outstanding clip operations
|
||||
/// measured in the coordinate space within which this DisplayList will
|
||||
/// be rendered.
|
||||
// |DlCanvas|
|
||||
SkRect GetDestinationClipBounds() const override {
|
||||
CheckAlive();
|
||||
return receiver_->device_cull_rect();
|
||||
}
|
||||
/// Conservative estimate of the bounds of all outstanding clip operations
|
||||
/// transformed into the local coordinate space in which currently
|
||||
/// recorded rendering operations are interpreted.
|
||||
// |DlCanvas|
|
||||
SkRect GetLocalClipBounds() const override {
|
||||
CheckAlive();
|
||||
return receiver_->local_cull_rect();
|
||||
}
|
||||
|
||||
/// Return true iff the supplied bounds are easily shown to be outside
|
||||
/// of the current clip bounds. This method may conservatively return
|
||||
/// false if it cannot make the determination.
|
||||
// |DlCanvas|
|
||||
bool QuickReject(const SkRect& bounds) const override;
|
||||
|
||||
// |DlCanvas|
|
||||
void DrawPaint(const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawColor(DlColor color, DlBlendMode mode) override;
|
||||
// |DlCanvas|
|
||||
void DrawLine(const SkPoint& p0,
|
||||
const SkPoint& p1,
|
||||
const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawRect(const SkRect& rect, const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawOval(const SkRect& bounds, const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawCircle(const SkPoint& center,
|
||||
SkScalar radius,
|
||||
const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawRRect(const SkRRect& rrect, const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawDRRect(const SkRRect& outer,
|
||||
const SkRRect& inner,
|
||||
const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawPath(const SkPath& path, const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawArc(const SkRect& bounds,
|
||||
SkScalar start,
|
||||
SkScalar sweep,
|
||||
bool useCenter,
|
||||
const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawPoints(PointMode mode,
|
||||
uint32_t count,
|
||||
const SkPoint pts[],
|
||||
const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawVertices(const DlVertices* vertices,
|
||||
DlBlendMode mode,
|
||||
const DlPaint& paint) override;
|
||||
using DlCanvas::DrawVertices;
|
||||
// |DlCanvas|
|
||||
void DrawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
const DlPaint* paint = nullptr) override;
|
||||
// |DlCanvas|
|
||||
void DrawImageRect(
|
||||
const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
const DlPaint* paint = nullptr,
|
||||
SrcRectConstraint constraint = SrcRectConstraint::kFast) override;
|
||||
using DlCanvas::DrawImageRect;
|
||||
// |DlCanvas|
|
||||
void DrawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
const DlPaint* paint = nullptr) override;
|
||||
// |DlCanvas|
|
||||
void DrawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
int count,
|
||||
DlBlendMode mode,
|
||||
DlImageSampling sampling,
|
||||
const SkRect* cullRect,
|
||||
const DlPaint* paint = nullptr) override;
|
||||
// |DlCanvas|
|
||||
void DrawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
SkScalar opacity = SK_Scalar1) override;
|
||||
// |DlCanvas|
|
||||
void DrawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y,
|
||||
const DlPaint& paint) override;
|
||||
// |DlCanvas|
|
||||
void DrawShadow(const SkPath& path,
|
||||
const DlColor color,
|
||||
const SkScalar elevation,
|
||||
bool transparent_occluder,
|
||||
SkScalar dpr) override;
|
||||
|
||||
// |DlCanvas|
|
||||
void Flush() override { CheckAlive(); }
|
||||
|
||||
protected:
|
||||
inline void CheckAlive() const { FML_CHECK(receiver_ != nullptr); }
|
||||
|
||||
std::shared_ptr<DlCanvasReceiver> receiver_;
|
||||
|
||||
bool current_group_opacity_compatibility() {
|
||||
return current_layer_->is_group_opacity_compatible();
|
||||
}
|
||||
bool current_affects_transparent_layer() {
|
||||
return current_layer_->affects_transparent_layer();
|
||||
}
|
||||
|
||||
DlPaint CurrentAttributes() const { return current_; }
|
||||
|
||||
private:
|
||||
// Returns whether or not the paint was compatible with opacity inheritance
|
||||
[[nodiscard]] bool SetAttributesFromPaint(
|
||||
const DlPaint* paint,
|
||||
const DisplayListAttributeFlags flags);
|
||||
|
||||
enum class OpResult {
|
||||
kNoEffect,
|
||||
kPreservesTransparency,
|
||||
kAffectsAll,
|
||||
};
|
||||
|
||||
class LayerInfo {
|
||||
public:
|
||||
explicit LayerInfo(
|
||||
bool has_layer = false,
|
||||
const std::shared_ptr<const DlImageFilter>& filter = nullptr)
|
||||
: has_layer_(has_layer), filter_(filter) {}
|
||||
|
||||
bool has_layer() const { return has_layer_; }
|
||||
bool cannot_inherit_opacity() const { return cannot_inherit_opacity_; }
|
||||
bool has_compatible_op() const { return has_compatible_op_; }
|
||||
bool affects_transparent_layer() const {
|
||||
return affects_transparent_layer_;
|
||||
}
|
||||
|
||||
void Update(OpResult result, bool can_inherit_opacity) {
|
||||
switch (result) {
|
||||
case OpResult::kNoEffect:
|
||||
// We should have stopped processing the rendering operation
|
||||
// well before we tried to update the layer information.
|
||||
FML_DCHECK(result != OpResult::kNoEffect);
|
||||
return;
|
||||
|
||||
case OpResult::kPreservesTransparency:
|
||||
break;
|
||||
|
||||
case OpResult::kAffectsAll:
|
||||
add_visible_op();
|
||||
break;
|
||||
}
|
||||
|
||||
if (can_inherit_opacity) {
|
||||
add_compatible_op();
|
||||
} else {
|
||||
mark_incompatible();
|
||||
}
|
||||
}
|
||||
|
||||
bool is_group_opacity_compatible() const {
|
||||
return !cannot_inherit_opacity_;
|
||||
}
|
||||
|
||||
void mark_incompatible() { cannot_inherit_opacity_ = true; }
|
||||
|
||||
// For now this only allows a single compatible op to mark the
|
||||
// layer as being compatible with group opacity. If we start
|
||||
// computing bounds of ops in the Builder methods then we
|
||||
// can upgrade this to checking for overlapping ops.
|
||||
// See https://github.com/flutter/flutter/issues/93899
|
||||
void add_compatible_op() {
|
||||
if (!cannot_inherit_opacity_) {
|
||||
if (has_compatible_op_) {
|
||||
cannot_inherit_opacity_ = true;
|
||||
} else {
|
||||
has_compatible_op_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Records that the current layer contains an op that produces visible
|
||||
// output on a transparent surface.
|
||||
void add_visible_op() { affects_transparent_layer_ = true; }
|
||||
|
||||
// The filter to apply to the layer bounds when it is restored
|
||||
std::shared_ptr<const DlImageFilter> filter() { return filter_; }
|
||||
|
||||
// is_unbounded should be set to true if we ever encounter an operation
|
||||
// on a layer that either is unrestricted (|drawColor| or |drawPaint|)
|
||||
// or cannot compute its bounds (some effects and filters) and there
|
||||
// was no outstanding clip op at the time.
|
||||
// When the layer is restored, the outer layer may then process this
|
||||
// unbounded state by accumulating its own clip or transferring the
|
||||
// unbounded state to its own outer layer.
|
||||
// Typically the DisplayList will have been constructed with a cull
|
||||
// rect which will act as a default clip for the outermost layer and
|
||||
// the unbounded state of all sub layers will eventually be caught by
|
||||
// that cull rect so that the overall unbounded state of the entire
|
||||
// DisplayList will never be true.
|
||||
//
|
||||
// For historical consistency it is worth noting that SkPicture used
|
||||
// to treat these same conditions as a Nop (they accumulate the
|
||||
// SkPicture cull rect, but if no cull rect was specified then it is
|
||||
// an empty Rect and so has no effect on the bounds).
|
||||
//
|
||||
// Flutter is unlikely to ever run into this as the Dart mechanisms
|
||||
// all supply a non-null cull rect for all Dart Picture objects,
|
||||
// even if that cull rect is kGiantRect.
|
||||
void set_unbounded() { is_unbounded_ = true; }
|
||||
|
||||
// |is_unbounded| should be called after |getLayerBounds| in case
|
||||
// a problem was found during the computation of those bounds,
|
||||
// the layer will have one last chance to flag an unbounded state.
|
||||
bool is_unbounded() const { return is_unbounded_; }
|
||||
|
||||
private:
|
||||
bool has_layer_;
|
||||
bool cannot_inherit_opacity_ = false;
|
||||
bool has_compatible_op_ = false;
|
||||
std::shared_ptr<const DlImageFilter> filter_;
|
||||
bool is_unbounded_ = false;
|
||||
bool state_is_nop_ = false;
|
||||
bool affects_transparent_layer_ = false;
|
||||
|
||||
friend class DlCanvasToReceiver;
|
||||
};
|
||||
|
||||
std::vector<LayerInfo> layer_stack_;
|
||||
LayerInfo* current_layer_;
|
||||
|
||||
// Returns the compatibility of a given blend mode for applying an
|
||||
// inherited opacity value to modulate the visibility of the op.
|
||||
// For now we only accept SrcOver blend modes but this could be expanded
|
||||
// in the future to include other (rarely used) modes that also modulate
|
||||
// the opacity of a rendering operation at the cost of a switch statement
|
||||
// or lookup table.
|
||||
static inline bool IsOpacityCompatible(DlBlendMode mode) {
|
||||
return (mode == DlBlendMode::kSrcOver);
|
||||
}
|
||||
|
||||
static DisplayListAttributeFlags FlagsForPointMode(PointMode mode);
|
||||
|
||||
bool paint_nops_on_transparency(const DlPaint* paint);
|
||||
OpResult PaintResult(const DlPaint& paint,
|
||||
DisplayListAttributeFlags flags = kDrawPaintFlags);
|
||||
OpResult PaintResult(const DlPaint* paint,
|
||||
DisplayListAttributeFlags flags = kDrawPaintFlags) {
|
||||
if (paint) {
|
||||
return PaintResult(*paint, flags);
|
||||
} else if (current_layer_->state_is_nop_) {
|
||||
return OpResult::kNoEffect;
|
||||
} else {
|
||||
FML_DCHECK(PaintResult(kDefaultPaint_, flags) == OpResult::kAffectsAll);
|
||||
return OpResult::kAffectsAll;
|
||||
}
|
||||
}
|
||||
|
||||
// kAnyColor is a non-opaque and non-transparent color that will not
|
||||
// trigger any short-circuit tests about the results of a blend.
|
||||
static constexpr DlColor kAnyColor = DlColor::kMidGrey().withAlpha(0x80);
|
||||
static_assert(!kAnyColor.isOpaque());
|
||||
static_assert(!kAnyColor.isTransparent());
|
||||
static DlColor GetEffectiveColor(const DlPaint& paint,
|
||||
DisplayListAttributeFlags flags);
|
||||
|
||||
// Computes the bounds of an operation adjusted for a given ImageFilter
|
||||
// and returns whether the computation was possible. If the method
|
||||
// returns false then the caller should assume the worst about the bounds.
|
||||
static bool ComputeFilteredBounds(SkRect& bounds,
|
||||
const DlImageFilter* filter);
|
||||
|
||||
// Adjusts the indicated bounds for the given flags and returns true if
|
||||
// the calculation was possible, or false if it could not be estimated.
|
||||
bool AdjustBoundsForPaint(SkRect& bounds,
|
||||
const DlPaint* paint,
|
||||
DisplayListAttributeFlags flags);
|
||||
|
||||
// Records the fact that we encountered an op that either could not
|
||||
// estimate its bounds or that fills all of the destination space.
|
||||
bool AccumulateUnbounded();
|
||||
|
||||
// Records the bounds for an op after modifying them according to the
|
||||
// supplied attribute flags and transforming by the current matrix.
|
||||
bool AccumulateOpBounds(const SkRect& bounds,
|
||||
const DlPaint* paint,
|
||||
DisplayListAttributeFlags flags) {
|
||||
SkRect safe_bounds = bounds;
|
||||
return AccumulateOpBounds(safe_bounds, paint, flags);
|
||||
}
|
||||
|
||||
// Records the bounds for an op after modifying them according to the
|
||||
// supplied attribute flags and transforming by the current matrix
|
||||
// and clipping against the current clip.
|
||||
bool AccumulateOpBounds(SkRect& bounds,
|
||||
const DlPaint* paint,
|
||||
DisplayListAttributeFlags flags);
|
||||
|
||||
// Records the given bounds after transforming by the current matrix
|
||||
// and clipping against the current clip.
|
||||
bool AccumulateBounds(SkRect& bounds);
|
||||
|
||||
DlPaint current_;
|
||||
static DlPaint kDefaultPaint_;
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_DISPLAY_LIST_DL_CANVAS_TO_RECEIVER_H_
|
||||
@ -75,6 +75,13 @@ class DisplayListFlags {
|
||||
// mitered extensions outside the pre-transformed bounding box.
|
||||
static constexpr int kMayHaveAcuteJoins_ = 1 << 8;
|
||||
|
||||
// Some primitives render with a different algorithm on Skia
|
||||
// when the line width is a hairline and that algorithm does
|
||||
// not apply inherited opacity appropriately. We mark these
|
||||
// operations with a flag so that we only disallow opacity
|
||||
// inheritance on hairlines for those primitives.
|
||||
static constexpr int kMayHaveTroubleWithHairlines_ = 1 << 9;
|
||||
|
||||
static constexpr int kAnySpecialGeometryMask_ = //
|
||||
kMayHaveCaps_ | kMayHaveJoins_ | kButtCapIsSquare_ | //
|
||||
kMayHaveDiagonalCaps_ | kMayHaveAcuteJoins_;
|
||||
@ -220,6 +227,12 @@ class DisplayListAttributeFlags : DisplayListFlagsBase {
|
||||
(style != DlDrawStyle::kFill && has_any(kIsDrawnGeometry_)));
|
||||
}
|
||||
|
||||
/// The operation may use an implementation for hairlines that
|
||||
/// does not inherit opacity properly
|
||||
constexpr bool may_have_trouble_with_hairlines() const {
|
||||
return has_any(kMayHaveTroubleWithHairlines_);
|
||||
}
|
||||
|
||||
constexpr bool is_flood() const { return has_any(kFloodsSurface_); }
|
||||
|
||||
constexpr bool operator==(DisplayListAttributeFlags const& other) const {
|
||||
@ -336,12 +349,13 @@ class DisplayListOpFlags : DisplayListFlags {
|
||||
kBASE_StrokeOrFillFlags_ //
|
||||
};
|
||||
static constexpr DisplayListAttributeFlags kDrawPathFlags{
|
||||
kBASE_PaintFlags_ | //
|
||||
kBASE_StrokeOrFillFlags_ | //
|
||||
kMayHaveCaps_ | //
|
||||
kMayHaveDiagonalCaps_ | //
|
||||
kMayHaveJoins_ | //
|
||||
kMayHaveAcuteJoins_ //
|
||||
kBASE_PaintFlags_ | //
|
||||
kBASE_StrokeOrFillFlags_ | //
|
||||
kMayHaveCaps_ | //
|
||||
kMayHaveDiagonalCaps_ | //
|
||||
kMayHaveJoins_ | //
|
||||
kMayHaveAcuteJoins_ | //
|
||||
kMayHaveTroubleWithHairlines_ //
|
||||
};
|
||||
static constexpr DisplayListAttributeFlags kDrawArcNoCenterFlags{
|
||||
kBASE_PaintFlags_ | //
|
||||
@ -350,10 +364,11 @@ class DisplayListOpFlags : DisplayListFlags {
|
||||
kMayHaveDiagonalCaps_ //
|
||||
};
|
||||
static constexpr DisplayListAttributeFlags kDrawArcWithCenterFlags{
|
||||
kBASE_PaintFlags_ | //
|
||||
kBASE_StrokeOrFillFlags_ | //
|
||||
kMayHaveJoins_ | //
|
||||
kMayHaveAcuteJoins_ //
|
||||
kBASE_PaintFlags_ | //
|
||||
kBASE_StrokeOrFillFlags_ | //
|
||||
kMayHaveJoins_ | //
|
||||
kMayHaveAcuteJoins_ | //
|
||||
kMayHaveTroubleWithHairlines_ //
|
||||
};
|
||||
static constexpr DisplayListAttributeFlags kDrawPointsAsPointsFlags{
|
||||
kBASE_PaintFlags_ | //
|
||||
|
||||
@ -2,8 +2,8 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_DISPLAY_LIST_DISPLAY_LIST_DISPATCHER_H_
|
||||
#define FLUTTER_DISPLAY_LIST_DISPLAY_LIST_DISPATCHER_H_
|
||||
#ifndef FLUTTER_DISPLAY_LIST_DL_OP_RECEIVER_H_
|
||||
#define FLUTTER_DISPLAY_LIST_DL_OP_RECEIVER_H_
|
||||
|
||||
#include "flutter/display_list/display_list.h"
|
||||
#include "flutter/display_list/dl_blend_mode.h"
|
||||
@ -38,6 +38,8 @@ class DlOpReceiver {
|
||||
// MaxDrawPointsCount * sizeof(SkPoint) must be less than 1 << 32
|
||||
static constexpr int kMaxDrawPointsCount = ((1 << 29) - 1);
|
||||
|
||||
virtual ~DlOpReceiver() = default;
|
||||
|
||||
// The following methods are nearly 1:1 with the methods on DlPaint and
|
||||
// carry the same meanings. Each method sets a persistent value for the
|
||||
// attribute for the rest of the display list or until it is reset by
|
||||
@ -216,23 +218,23 @@ class DlOpReceiver {
|
||||
uint32_t count,
|
||||
const SkPoint points[]) = 0;
|
||||
virtual void drawVertices(const DlVertices* vertices, DlBlendMode mode) = 0;
|
||||
virtual void drawImage(const sk_sp<DlImage> image,
|
||||
virtual void drawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) = 0;
|
||||
virtual void drawImageRect(
|
||||
const sk_sp<DlImage> image,
|
||||
const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes,
|
||||
SrcRectConstraint constraint = SrcRectConstraint::kFast) = 0;
|
||||
virtual void drawImageNine(const sk_sp<DlImage> image,
|
||||
virtual void drawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
bool render_with_attributes) = 0;
|
||||
virtual void drawAtlas(const sk_sp<DlImage> atlas,
|
||||
virtual void drawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
@ -241,9 +243,9 @@ class DlOpReceiver {
|
||||
DlImageSampling sampling,
|
||||
const SkRect* cull_rect,
|
||||
bool render_with_attributes) = 0;
|
||||
virtual void drawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
virtual void drawDisplayList(const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity = SK_Scalar1) = 0;
|
||||
virtual void drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
virtual void drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) = 0;
|
||||
virtual void drawShadow(const SkPath& path,
|
||||
@ -255,4 +257,4 @@ class DlOpReceiver {
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_DISPLAY_LIST_DISPLAY_LIST_DISPATCHER_H_
|
||||
#endif // FLUTTER_DISPLAY_LIST_DL_OP_RECEIVER_H_
|
||||
|
||||
691
engine/src/flutter/display_list/dl_op_recorder.cc
Normal file
691
engine/src/flutter/display_list/dl_op_recorder.cc
Normal file
@ -0,0 +1,691 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/display_list/dl_op_recorder.h"
|
||||
|
||||
#include "flutter/display_list/dl_attributes.h"
|
||||
#include "flutter/display_list/dl_op_records.h"
|
||||
#include "flutter/display_list/effects/dl_color_source.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
#define DL_BUILDER_PAGE 4096
|
||||
|
||||
// CopyV(dst, src,n, src,n, ...) copies any number of typed srcs into dst.
|
||||
static void CopyV(void* dst) {}
|
||||
|
||||
template <typename S, typename... Rest>
|
||||
static void CopyV(void* dst, const S* src, int n, Rest&&... rest) {
|
||||
FML_DCHECK(((uintptr_t)dst & (alignof(S) - 1)) == 0)
|
||||
<< "Expected " << dst << " to be aligned for at least " << alignof(S)
|
||||
<< " bytes.";
|
||||
// If n is 0, there is nothing to copy into dst from src.
|
||||
if (n > 0) {
|
||||
memcpy(dst, src, n * sizeof(S));
|
||||
dst = reinterpret_cast<void*>(reinterpret_cast<uint8_t*>(dst) +
|
||||
n * sizeof(S));
|
||||
}
|
||||
// Repeat for the next items, if any
|
||||
CopyV(dst, std::forward<Rest>(rest)...);
|
||||
}
|
||||
|
||||
DlOpRecorder::DlOpRecorder(const SkRect& cull_rect, bool keep_rtree) {
|
||||
tracker_ =
|
||||
std::make_shared<DisplayListMatrixClipTracker>(cull_rect, SkMatrix::I());
|
||||
if (keep_rtree) {
|
||||
accumulator_ = std::make_shared<RTreeBoundsAccumulator>();
|
||||
} else {
|
||||
accumulator_ = std::make_shared<RectBoundsAccumulator>();
|
||||
}
|
||||
save_infos_.push_back({
|
||||
.offset = 0u,
|
||||
.deferred = false,
|
||||
.is_layer = false,
|
||||
});
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
void* DlOpRecorder::Push(size_t pod, int render_op_inc, Args&&... args) {
|
||||
size_t size = SkAlignPtr(sizeof(T) + pod);
|
||||
auto op = reinterpret_cast<T*>(storage_.alloc(size));
|
||||
new (op) T{std::forward<Args>(args)...};
|
||||
op->type = T::kType;
|
||||
op->size = size;
|
||||
render_op_count_ += render_op_inc;
|
||||
op_index_++;
|
||||
return op + 1;
|
||||
}
|
||||
|
||||
void DlOpRecorder::setAntiAlias(bool aa) {
|
||||
Push<SetAntiAliasOp>(0, 0, aa);
|
||||
}
|
||||
void DlOpRecorder::setDither(bool dither) {
|
||||
Push<SetDitherOp>(0, 0, dither);
|
||||
}
|
||||
void DlOpRecorder::setInvertColors(bool invert) {
|
||||
Push<SetInvertColorsOp>(0, 0, invert);
|
||||
}
|
||||
void DlOpRecorder::setStrokeCap(DlStrokeCap cap) {
|
||||
Push<SetStrokeCapOp>(0, 0, cap);
|
||||
}
|
||||
void DlOpRecorder::setStrokeJoin(DlStrokeJoin join) {
|
||||
Push<SetStrokeJoinOp>(0, 0, join);
|
||||
}
|
||||
void DlOpRecorder::setDrawStyle(DlDrawStyle style) {
|
||||
Push<SetStyleOp>(0, 0, style);
|
||||
}
|
||||
void DlOpRecorder::setStrokeWidth(float width) {
|
||||
Push<SetStrokeWidthOp>(0, 0, width);
|
||||
}
|
||||
void DlOpRecorder::setStrokeMiter(float limit) {
|
||||
Push<SetStrokeMiterOp>(0, 0, limit);
|
||||
}
|
||||
void DlOpRecorder::setColor(DlColor color) {
|
||||
Push<SetColorOp>(0, 0, color);
|
||||
}
|
||||
void DlOpRecorder::setBlendMode(DlBlendMode mode) {
|
||||
Push<SetBlendModeOp>(0, 0, mode);
|
||||
}
|
||||
|
||||
void DlOpRecorder::setColorSource(const DlColorSource* source) {
|
||||
if (source == nullptr) {
|
||||
Push<ClearColorSourceOp>(0, 0);
|
||||
} else {
|
||||
is_ui_thread_safe_ = is_ui_thread_safe_ && source->isUIThreadSafe();
|
||||
switch (source->type()) {
|
||||
case DlColorSourceType::kColor: {
|
||||
const DlColorColorSource* color_source = source->asColor();
|
||||
setColor(color_source->color());
|
||||
break;
|
||||
}
|
||||
case DlColorSourceType::kImage: {
|
||||
const DlImageColorSource* image_source = source->asImage();
|
||||
FML_DCHECK(image_source);
|
||||
Push<SetImageColorSourceOp>(0, 0, image_source);
|
||||
break;
|
||||
}
|
||||
case DlColorSourceType::kLinearGradient: {
|
||||
const DlLinearGradientColorSource* linear = source->asLinearGradient();
|
||||
FML_DCHECK(linear);
|
||||
void* pod = Push<SetPodColorSourceOp>(linear->size(), 0);
|
||||
new (pod) DlLinearGradientColorSource(linear);
|
||||
break;
|
||||
}
|
||||
case DlColorSourceType::kRadialGradient: {
|
||||
const DlRadialGradientColorSource* radial = source->asRadialGradient();
|
||||
FML_DCHECK(radial);
|
||||
void* pod = Push<SetPodColorSourceOp>(radial->size(), 0);
|
||||
new (pod) DlRadialGradientColorSource(radial);
|
||||
break;
|
||||
}
|
||||
case DlColorSourceType::kConicalGradient: {
|
||||
const DlConicalGradientColorSource* conical =
|
||||
source->asConicalGradient();
|
||||
FML_DCHECK(conical);
|
||||
void* pod = Push<SetPodColorSourceOp>(conical->size(), 0);
|
||||
new (pod) DlConicalGradientColorSource(conical);
|
||||
break;
|
||||
}
|
||||
case DlColorSourceType::kSweepGradient: {
|
||||
const DlSweepGradientColorSource* sweep = source->asSweepGradient();
|
||||
FML_DCHECK(sweep);
|
||||
void* pod = Push<SetPodColorSourceOp>(sweep->size(), 0);
|
||||
new (pod) DlSweepGradientColorSource(sweep);
|
||||
break;
|
||||
}
|
||||
case DlColorSourceType::kRuntimeEffect: {
|
||||
const DlRuntimeEffectColorSource* effect = source->asRuntimeEffect();
|
||||
FML_DCHECK(effect);
|
||||
Push<SetRuntimeEffectColorSourceOp>(0, 0, effect);
|
||||
break;
|
||||
}
|
||||
#ifdef IMPELLER_ENABLE_3D
|
||||
case DlColorSourceType::kScene: {
|
||||
const DlSceneColorSource* scene = source->asScene();
|
||||
FML_DCHECK(scene);
|
||||
Push<SetSceneColorSourceOp>(0, 0, scene);
|
||||
break;
|
||||
}
|
||||
#endif // IMPELLER_ENABLE_3D
|
||||
}
|
||||
}
|
||||
}
|
||||
void DlOpRecorder::setImageFilter(const DlImageFilter* filter) {
|
||||
if (filter == nullptr) {
|
||||
Push<ClearImageFilterOp>(0, 0);
|
||||
} else {
|
||||
switch (filter->type()) {
|
||||
case DlImageFilterType::kBlur: {
|
||||
const DlBlurImageFilter* blur_filter = filter->asBlur();
|
||||
FML_DCHECK(blur_filter);
|
||||
void* pod = Push<SetPodImageFilterOp>(blur_filter->size(), 0);
|
||||
new (pod) DlBlurImageFilter(blur_filter);
|
||||
break;
|
||||
}
|
||||
case DlImageFilterType::kDilate: {
|
||||
const DlDilateImageFilter* dilate_filter = filter->asDilate();
|
||||
FML_DCHECK(dilate_filter);
|
||||
void* pod = Push<SetPodImageFilterOp>(dilate_filter->size(), 0);
|
||||
new (pod) DlDilateImageFilter(dilate_filter);
|
||||
break;
|
||||
}
|
||||
case DlImageFilterType::kErode: {
|
||||
const DlErodeImageFilter* erode_filter = filter->asErode();
|
||||
FML_DCHECK(erode_filter);
|
||||
void* pod = Push<SetPodImageFilterOp>(erode_filter->size(), 0);
|
||||
new (pod) DlErodeImageFilter(erode_filter);
|
||||
break;
|
||||
}
|
||||
case DlImageFilterType::kMatrix: {
|
||||
const DlMatrixImageFilter* matrix_filter = filter->asMatrix();
|
||||
FML_DCHECK(matrix_filter);
|
||||
void* pod = Push<SetPodImageFilterOp>(matrix_filter->size(), 0);
|
||||
new (pod) DlMatrixImageFilter(matrix_filter);
|
||||
break;
|
||||
}
|
||||
case DlImageFilterType::kCompose:
|
||||
case DlImageFilterType::kLocalMatrix:
|
||||
case DlImageFilterType::kColorFilter: {
|
||||
Push<SetSharedImageFilterOp>(0, 0, filter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void DlOpRecorder::setColorFilter(const DlColorFilter* filter) {
|
||||
if (filter == nullptr) {
|
||||
Push<ClearColorFilterOp>(0, 0);
|
||||
} else {
|
||||
switch (filter->type()) {
|
||||
case DlColorFilterType::kBlend: {
|
||||
const DlBlendColorFilter* blend_filter = filter->asBlend();
|
||||
FML_DCHECK(blend_filter);
|
||||
void* pod = Push<SetPodColorFilterOp>(blend_filter->size(), 0);
|
||||
new (pod) DlBlendColorFilter(blend_filter);
|
||||
break;
|
||||
}
|
||||
case DlColorFilterType::kMatrix: {
|
||||
const DlMatrixColorFilter* matrix_filter = filter->asMatrix();
|
||||
FML_DCHECK(matrix_filter);
|
||||
void* pod = Push<SetPodColorFilterOp>(matrix_filter->size(), 0);
|
||||
new (pod) DlMatrixColorFilter(matrix_filter);
|
||||
break;
|
||||
}
|
||||
case DlColorFilterType::kSrgbToLinearGamma: {
|
||||
void* pod = Push<SetPodColorFilterOp>(filter->size(), 0);
|
||||
new (pod) DlSrgbToLinearGammaColorFilter();
|
||||
break;
|
||||
}
|
||||
case DlColorFilterType::kLinearToSrgbGamma: {
|
||||
void* pod = Push<SetPodColorFilterOp>(filter->size(), 0);
|
||||
new (pod) DlLinearToSrgbGammaColorFilter();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void DlOpRecorder::setPathEffect(const DlPathEffect* effect) {
|
||||
if (effect == nullptr) {
|
||||
Push<ClearPathEffectOp>(0, 0);
|
||||
} else {
|
||||
switch (effect->type()) {
|
||||
case DlPathEffectType::kDash: {
|
||||
const DlDashPathEffect* dash_effect = effect->asDash();
|
||||
void* pod = Push<SetPodPathEffectOp>(dash_effect->size(), 0);
|
||||
new (pod) DlDashPathEffect(dash_effect);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void DlOpRecorder::setMaskFilter(const DlMaskFilter* filter) {
|
||||
if (filter == nullptr) {
|
||||
Push<ClearMaskFilterOp>(0, 0);
|
||||
} else {
|
||||
switch (filter->type()) {
|
||||
case DlMaskFilterType::kBlur: {
|
||||
const DlBlurMaskFilter* blur_filter = filter->asBlur();
|
||||
FML_DCHECK(blur_filter);
|
||||
void* pod = Push<SetPodMaskFilterOp>(blur_filter->size(), 0);
|
||||
new (pod) DlBlurMaskFilter(blur_filter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DlOpRecorder::save() {
|
||||
save_infos_.push_back({
|
||||
.offset = 0u,
|
||||
.deferred = true,
|
||||
.is_layer = false,
|
||||
});
|
||||
tracker_->save();
|
||||
accumulator_->save();
|
||||
}
|
||||
void DlOpRecorder::ResolveDeferredSave() {
|
||||
SaveInfo& save_info_ref = save_infos_.back();
|
||||
if (save_info_ref.deferred) {
|
||||
FML_DCHECK(save_info_ref.is_layer == false);
|
||||
FML_DCHECK(save_info_ref.offset == 0u);
|
||||
save_info_ref.offset = storage_.used();
|
||||
save_info_ref.deferred = false;
|
||||
Push<SaveOp>(0, 1);
|
||||
}
|
||||
}
|
||||
void DlOpRecorder::saveLayer(const SkRect* bounds,
|
||||
const SaveLayerOptions options,
|
||||
const DlImageFilter* backdrop) {
|
||||
save_infos_.push_back({
|
||||
.offset = storage_.used(),
|
||||
.deferred = false,
|
||||
.is_layer = true,
|
||||
});
|
||||
tracker_->save();
|
||||
accumulator_->save();
|
||||
if (backdrop) {
|
||||
bounds //
|
||||
? Push<SaveLayerBackdropBoundsOp>(0, 1, options, *bounds, backdrop)
|
||||
: Push<SaveLayerBackdropOp>(0, 1, options, backdrop);
|
||||
} else {
|
||||
bounds //
|
||||
? Push<SaveLayerBoundsOp>(0, 1, options, *bounds)
|
||||
: Push<SaveLayerOp>(0, 1, options);
|
||||
}
|
||||
}
|
||||
|
||||
void DlOpRecorder::restore() {
|
||||
FML_DCHECK(!save_infos_.empty());
|
||||
{ // Ensure all uses of save_info_ref occur before pop_back()
|
||||
const SaveInfo& save_info_ref = save_infos_.back();
|
||||
if (save_info_ref.is_layer) {
|
||||
// This should only happen when unrolling the save stack
|
||||
// in the Build() method.
|
||||
restoreLayer(nullptr, false, false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!save_info_ref.deferred) {
|
||||
SaveOpBase* op =
|
||||
reinterpret_cast<SaveOpBase*>(storage_.get() + save_info_ref.offset);
|
||||
FML_DCHECK(op->type == DisplayListOpType::kSave);
|
||||
op->restore_index = op_index_;
|
||||
|
||||
Push<RestoreOp>(0, 1);
|
||||
}
|
||||
} // save_info_ref no longer accessible
|
||||
save_infos_.pop_back();
|
||||
|
||||
tracker_->restore();
|
||||
accumulator_->restore();
|
||||
}
|
||||
void DlOpRecorder::restoreLayer(const DlImageFilter* filter,
|
||||
bool layer_content_was_unbounded,
|
||||
bool layer_could_distribute_opacity) {
|
||||
FML_DCHECK(!save_infos_.empty());
|
||||
{ // Ensure all uses of save_info_ref occur before pop_back()
|
||||
SaveInfo& save_info_ref = save_infos_.back();
|
||||
FML_DCHECK(save_info_ref.is_layer == true);
|
||||
FML_DCHECK(save_info_ref.deferred == false);
|
||||
|
||||
SaveOpBase* op =
|
||||
reinterpret_cast<SaveOpBase*>(storage_.get() + save_info_ref.offset);
|
||||
FML_DCHECK(op->type == DisplayListOpType::kSaveLayer ||
|
||||
op->type == DisplayListOpType::kSaveLayerBounds ||
|
||||
op->type == DisplayListOpType::kSaveLayerBackdrop ||
|
||||
op->type == DisplayListOpType::kSaveLayerBackdropBounds);
|
||||
op->restore_index = op_index_;
|
||||
if (layer_could_distribute_opacity) {
|
||||
op->options = op->options.with_can_distribute_opacity();
|
||||
}
|
||||
} // save_info_ref no longer accessible
|
||||
save_infos_.pop_back();
|
||||
|
||||
Push<RestoreOp>(0, 1);
|
||||
|
||||
// Manage the layer bounds before we push the restore op so that any
|
||||
// bounds we need to adjust get tagged on the RestoreOp rather than
|
||||
// the rendering op that follows it.
|
||||
|
||||
// Restore the tracker before we manage the layer bounds so that we use
|
||||
// the enclosing cull_rect and transform for filtering bounds.
|
||||
tracker_->restore();
|
||||
const SkRect clip = tracker_->device_cull_rect();
|
||||
|
||||
// As we pop the accumulator we will adjust the bounds associated with
|
||||
// the layer content by the layer filter.
|
||||
// We have already restored the tracker so that the cull_rect information
|
||||
// we use in the adjustment is from the environment outside of the layer.
|
||||
// If there is a failure in converting the bounds within the layer due
|
||||
// to an issue with the layer filter, or if the content of the layer
|
||||
// was already unbounded, we will propagate the unbounded status to the
|
||||
// enclosing layer.
|
||||
if (filter) {
|
||||
const SkMatrix matrix = tracker_->matrix_3x3();
|
||||
if (!accumulator_->restore(
|
||||
[filter, matrix](const SkRect& input, SkRect& output) {
|
||||
SkIRect output_bounds;
|
||||
bool ret = filter->map_device_bounds(input.roundOut(), matrix,
|
||||
output_bounds);
|
||||
output.set(output_bounds);
|
||||
return ret;
|
||||
},
|
||||
&clip)) {
|
||||
layer_content_was_unbounded = true;
|
||||
}
|
||||
} else {
|
||||
accumulator_->restore();
|
||||
}
|
||||
|
||||
if (layer_content_was_unbounded) {
|
||||
// Ideally we would insert this back in the list of rects with the
|
||||
// OpID of the original SaveLayer...
|
||||
if (!clip.isEmpty()) {
|
||||
accumulator_->accumulate(clip, render_op_count_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DlOpRecorder::translate(SkScalar tx, SkScalar ty) {
|
||||
ResolveDeferredSave();
|
||||
tracker_->translate(tx, ty);
|
||||
Push<TranslateOp>(0, 1, tx, ty);
|
||||
}
|
||||
void DlOpRecorder::scale(SkScalar sx, SkScalar sy) {
|
||||
ResolveDeferredSave();
|
||||
tracker_->scale(sx, sy);
|
||||
Push<ScaleOp>(0, 1, sx, sy);
|
||||
}
|
||||
void DlOpRecorder::rotate(SkScalar degrees) {
|
||||
ResolveDeferredSave();
|
||||
tracker_->rotate(degrees);
|
||||
Push<RotateOp>(0, 1, degrees);
|
||||
}
|
||||
void DlOpRecorder::skew(SkScalar sx, SkScalar sy) {
|
||||
ResolveDeferredSave();
|
||||
tracker_->skew(sx, sy);
|
||||
Push<SkewOp>(0, 1, sx, sy);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
|
||||
// 2x3 2D affine subset of a 4x4 transform in row major order
|
||||
void DlOpRecorder::transform2DAffine(
|
||||
SkScalar mxx, SkScalar mxy, SkScalar mxt,
|
||||
SkScalar myx, SkScalar myy, SkScalar myt) {
|
||||
ResolveDeferredSave();
|
||||
tracker_->transform2DAffine(mxx, mxy, mxt,
|
||||
myx, myy, myt);
|
||||
Push<Transform2DAffineOp>(0, 1,
|
||||
mxx, mxy, mxt,
|
||||
myx, myy, myt);
|
||||
}
|
||||
// full 4x4 transform in row major order
|
||||
void DlOpRecorder::transformFullPerspective(
|
||||
SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt,
|
||||
SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt,
|
||||
SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt,
|
||||
SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) {
|
||||
ResolveDeferredSave();
|
||||
tracker_->transformFullPerspective(mxx, mxy, mxz, mxt,
|
||||
myx, myy, myz, myt,
|
||||
mzx, mzy, mzz, mzt,
|
||||
mwx, mwy, mwz, mwt);
|
||||
Push<TransformFullPerspectiveOp>(0, 1,
|
||||
mxx, mxy, mxz, mxt,
|
||||
myx, myy, myz, myt,
|
||||
mzx, mzy, mzz, mzt,
|
||||
mwx, mwy, mwz, mwt);
|
||||
}
|
||||
// clang-format on
|
||||
void DlOpRecorder::transformReset() {
|
||||
ResolveDeferredSave();
|
||||
tracker_->setIdentity();
|
||||
Push<TransformResetOp>(0, 0);
|
||||
}
|
||||
|
||||
void DlOpRecorder::clipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) {
|
||||
ResolveDeferredSave();
|
||||
tracker_->clipRect(rect, clip_op, is_aa);
|
||||
if (!tracker_->is_cull_rect_empty()) {
|
||||
switch (clip_op) {
|
||||
case ClipOp::kIntersect:
|
||||
Push<ClipIntersectRectOp>(0, 1, rect, is_aa);
|
||||
break;
|
||||
case ClipOp::kDifference:
|
||||
Push<ClipDifferenceRectOp>(0, 1, rect, is_aa);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DlOpRecorder::clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) {
|
||||
ResolveDeferredSave();
|
||||
tracker_->clipRRect(rrect, clip_op, is_aa);
|
||||
if (!tracker_->is_cull_rect_empty()) {
|
||||
switch (clip_op) {
|
||||
case ClipOp::kIntersect:
|
||||
Push<ClipIntersectRRectOp>(0, 1, rrect, is_aa);
|
||||
break;
|
||||
case ClipOp::kDifference:
|
||||
Push<ClipDifferenceRRectOp>(0, 1, rrect, is_aa);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DlOpRecorder::clipPath(const SkPath& path, ClipOp clip_op, bool is_aa) {
|
||||
ResolveDeferredSave();
|
||||
tracker_->clipPath(path, clip_op, is_aa);
|
||||
if (!tracker_->is_cull_rect_empty()) {
|
||||
switch (clip_op) {
|
||||
case ClipOp::kIntersect:
|
||||
Push<ClipIntersectPathOp>(0, 1, path, is_aa);
|
||||
break;
|
||||
case ClipOp::kDifference:
|
||||
Push<ClipDifferencePathOp>(0, 1, path, is_aa);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void DlOpRecorder::resetCullRect(const SkRect* cull_rect) {
|
||||
tracker_->resetCullRect(cull_rect);
|
||||
}
|
||||
void DlOpRecorder::intersectCullRect(const SkRect& cull_rect) {
|
||||
tracker_->clipRect(cull_rect, DlCanvas::ClipOp::kIntersect, false);
|
||||
}
|
||||
|
||||
void DlOpRecorder::drawPaint() {
|
||||
Push<DrawPaintOp>(0, 1);
|
||||
}
|
||||
void DlOpRecorder::drawColor(DlColor color, DlBlendMode mode) {
|
||||
Push<DrawColorOp>(0, 1, color, mode);
|
||||
}
|
||||
void DlOpRecorder::drawLine(const SkPoint& p0, const SkPoint& p1) {
|
||||
Push<DrawLineOp>(0, 1, p0, p1);
|
||||
}
|
||||
void DlOpRecorder::drawRect(const SkRect& rect) {
|
||||
Push<DrawRectOp>(0, 1, rect);
|
||||
}
|
||||
void DlOpRecorder::drawOval(const SkRect& bounds) {
|
||||
Push<DrawOvalOp>(0, 1, bounds);
|
||||
}
|
||||
void DlOpRecorder::drawCircle(const SkPoint& center, SkScalar radius) {
|
||||
Push<DrawCircleOp>(0, 1, center, radius);
|
||||
}
|
||||
void DlOpRecorder::drawRRect(const SkRRect& rrect) {
|
||||
Push<DrawRRectOp>(0, 1, rrect);
|
||||
}
|
||||
void DlOpRecorder::drawDRRect(const SkRRect& outer, const SkRRect& inner) {
|
||||
Push<DrawDRRectOp>(0, 1, outer, inner);
|
||||
}
|
||||
void DlOpRecorder::drawPath(const SkPath& path) {
|
||||
Push<DrawPathOp>(0, 1, path);
|
||||
}
|
||||
|
||||
void DlOpRecorder::drawArc(const SkRect& bounds,
|
||||
SkScalar start,
|
||||
SkScalar sweep,
|
||||
bool useCenter) {
|
||||
Push<DrawArcOp>(0, 1, bounds, start, sweep, useCenter);
|
||||
}
|
||||
|
||||
void DlOpRecorder::drawPoints(PointMode mode,
|
||||
uint32_t count,
|
||||
const SkPoint pts[]) {
|
||||
FML_DCHECK(count > 0);
|
||||
FML_DCHECK(count < DlOpReceiver::kMaxDrawPointsCount);
|
||||
int bytes = count * sizeof(SkPoint);
|
||||
void* data_ptr;
|
||||
switch (mode) {
|
||||
case PointMode::kPoints:
|
||||
data_ptr = Push<DrawPointsOp>(bytes, 1, count);
|
||||
break;
|
||||
case PointMode::kLines:
|
||||
data_ptr = Push<DrawLinesOp>(bytes, 1, count);
|
||||
break;
|
||||
case PointMode::kPolygon:
|
||||
data_ptr = Push<DrawPolygonOp>(bytes, 1, count);
|
||||
break;
|
||||
default:
|
||||
FML_UNREACHABLE();
|
||||
return;
|
||||
}
|
||||
CopyV(data_ptr, pts, count);
|
||||
}
|
||||
void DlOpRecorder::drawVertices(const DlVertices* vertices, DlBlendMode mode) {
|
||||
void* pod = Push<DrawVerticesOp>(vertices->size(), 1, mode);
|
||||
new (pod) DlVertices(vertices);
|
||||
}
|
||||
|
||||
void DlOpRecorder::drawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) {
|
||||
render_with_attributes
|
||||
? Push<DrawImageWithAttrOp>(0, 1, image, point, sampling)
|
||||
: Push<DrawImageOp>(0, 1, image, point, sampling);
|
||||
is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe();
|
||||
}
|
||||
void DlOpRecorder::drawImageRect(const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes,
|
||||
SrcRectConstraint constraint) {
|
||||
Push<DrawImageRectOp>(0, 1, image, src, dst, sampling, //
|
||||
render_with_attributes, constraint);
|
||||
is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe();
|
||||
}
|
||||
void DlOpRecorder::drawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
bool render_with_attributes) {
|
||||
render_with_attributes
|
||||
? Push<DrawImageNineWithAttrOp>(0, 1, image, center, dst, filter)
|
||||
: Push<DrawImageNineOp>(0, 1, image, center, dst, filter);
|
||||
is_ui_thread_safe_ = is_ui_thread_safe_ && image->isUIThreadSafe();
|
||||
}
|
||||
void DlOpRecorder::drawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
int count,
|
||||
DlBlendMode mode,
|
||||
DlImageSampling sampling,
|
||||
const SkRect* cull_rect,
|
||||
bool render_with_attributes) {
|
||||
int bytes = count * (sizeof(SkRSXform) + sizeof(SkRect));
|
||||
void* data_ptr;
|
||||
if (colors != nullptr) {
|
||||
bytes += count * sizeof(DlColor);
|
||||
if (cull_rect != nullptr) {
|
||||
data_ptr =
|
||||
Push<DrawAtlasCulledOp>(bytes, 1, atlas, count, mode, sampling, true,
|
||||
*cull_rect, render_with_attributes);
|
||||
} else {
|
||||
data_ptr = Push<DrawAtlasOp>(bytes, 1, atlas, count, mode, sampling, true,
|
||||
render_with_attributes);
|
||||
}
|
||||
CopyV(data_ptr, xform, count, tex, count, colors, count);
|
||||
} else {
|
||||
if (cull_rect != nullptr) {
|
||||
data_ptr =
|
||||
Push<DrawAtlasCulledOp>(bytes, 1, atlas, count, mode, sampling, false,
|
||||
*cull_rect, render_with_attributes);
|
||||
} else {
|
||||
data_ptr = Push<DrawAtlasOp>(bytes, 1, atlas, count, mode, sampling,
|
||||
false, render_with_attributes);
|
||||
}
|
||||
CopyV(data_ptr, xform, count, tex, count);
|
||||
}
|
||||
is_ui_thread_safe_ = is_ui_thread_safe_ && atlas->isUIThreadSafe();
|
||||
}
|
||||
|
||||
void DlOpRecorder::drawDisplayList(const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity) {
|
||||
Push<DrawDisplayListOp>(0, 1, display_list, opacity);
|
||||
nested_op_count_ += display_list->op_count(true) - 1;
|
||||
nested_bytes_ += display_list->bytes(true);
|
||||
is_ui_thread_safe_ = is_ui_thread_safe_ && display_list->isUIThreadSafe();
|
||||
}
|
||||
void DlOpRecorder::drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) {
|
||||
Push<DrawTextBlobOp>(0, 1, blob, x, y);
|
||||
}
|
||||
void DlOpRecorder::drawShadow(const SkPath& path,
|
||||
const DlColor color,
|
||||
const SkScalar elevation,
|
||||
bool transparent_occluder,
|
||||
SkScalar dpr) {
|
||||
transparent_occluder //
|
||||
? Push<DrawShadowTransparentOccluderOp>(0, 1, path, color, elevation, dpr)
|
||||
: Push<DrawShadowOp>(0, 1, path, color, elevation, dpr);
|
||||
}
|
||||
|
||||
bool DlOpRecorder::accumulateLocalBoundsForNextOp(const SkRect& r) {
|
||||
if (!r.isEmpty()) {
|
||||
SkRect bounds = r;
|
||||
tracker_->mapRect(&bounds);
|
||||
if (bounds.intersect(tracker_->device_cull_rect())) {
|
||||
accumulator_->accumulate(bounds, render_op_count_);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool DlOpRecorder::accumulateUnboundedForNextOp() {
|
||||
SkRect clip = tracker_->device_cull_rect();
|
||||
if (!clip.isEmpty()) {
|
||||
accumulator_->accumulate(clip, render_op_count_);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
sk_sp<DisplayList> DlOpRecorder::Build(bool can_distribute_opacity,
|
||||
bool affects_transparent_layer) {
|
||||
if (!storage_.is_valid()) {
|
||||
FML_DCHECK(storage_.is_valid());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
while (save_infos_.size() > 1u) {
|
||||
restore();
|
||||
}
|
||||
|
||||
auto rtree = accumulator_->rtree();
|
||||
// It is faster to ask the completed rtree for bounds than to ask
|
||||
// the accumulator to run through all of its rects for the bounds.
|
||||
auto bounds = rtree ? rtree->bounds() : accumulator_->bounds();
|
||||
|
||||
return sk_sp<DisplayList>(
|
||||
new DisplayList(storage_.take(), render_op_count_, nested_bytes_,
|
||||
nested_op_count_, bounds, can_distribute_opacity,
|
||||
is_ui_thread_safe_, affects_transparent_layer, rtree));
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
210
engine/src/flutter/display_list/dl_op_recorder.h
Normal file
210
engine/src/flutter/display_list/dl_op_recorder.h
Normal file
@ -0,0 +1,210 @@
|
||||
// Copyright 2013 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef FLUTTER_DISPLAY_LIST_DL_OP_RECORDER_H_
|
||||
#define FLUTTER_DISPLAY_LIST_DL_OP_RECORDER_H_
|
||||
|
||||
#include "flutter/display_list/dl_canvas_to_receiver.h"
|
||||
#include "flutter/display_list/dl_op_receiver.h"
|
||||
#include "flutter/display_list/utils/dl_bounds_accumulator.h"
|
||||
#include "flutter/display_list/utils/dl_matrix_clip_tracker.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
class DisplayList;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// @brief An implementation of DlOpReceiver that records the calls into
|
||||
/// a buffer, typically driven from a DisplayListBuilder.
|
||||
///
|
||||
class DlOpRecorder : public DlCanvasReceiver {
|
||||
private:
|
||||
using ClipOp = DlCanvas::ClipOp;
|
||||
|
||||
public:
|
||||
static constexpr SkRect kMaxCullRect =
|
||||
SkRect::MakeLTRB(-1E9F, -1E9F, 1E9F, 1E9F);
|
||||
|
||||
DlOpRecorder(const SkRect& cull_rect = kMaxCullRect, bool keep_rtree = false);
|
||||
|
||||
~DlOpRecorder() = default;
|
||||
|
||||
// | DlCanvasReceiver|
|
||||
SkRect base_device_cull_rect() const override {
|
||||
return tracker_->base_device_cull_rect();
|
||||
}
|
||||
SkRect device_cull_rect() const override {
|
||||
return tracker_->device_cull_rect();
|
||||
}
|
||||
SkRect local_cull_rect() const override {
|
||||
return tracker_->local_cull_rect();
|
||||
}
|
||||
bool is_cull_rect_empty() const override {
|
||||
return tracker_->is_cull_rect_empty();
|
||||
}
|
||||
bool content_culled(const SkRect& content_bounds) const override {
|
||||
return tracker_->content_culled(content_bounds);
|
||||
}
|
||||
|
||||
// | DlCanvasReceiver|
|
||||
SkM44 matrix_4x4() const override { return tracker_->matrix_4x4(); }
|
||||
SkMatrix matrix_3x3() const override { return tracker_->matrix_3x3(); }
|
||||
|
||||
// | DlCanvasReceiver|
|
||||
void resetCullRect(const SkRect* cull_rect = nullptr) override;
|
||||
void intersectCullRect(const SkRect& cull_rect) override;
|
||||
|
||||
// | DlCanvasReceiver|
|
||||
bool wants_granular_bounds() const override {
|
||||
return accumulator_->type() == BoundsAccumulator::Type::kRTree;
|
||||
}
|
||||
|
||||
// |DlOpReceiver| all set methods
|
||||
void setAntiAlias(bool aa) override;
|
||||
void setDither(bool dither) override;
|
||||
void setDrawStyle(DlDrawStyle style) override;
|
||||
void setColor(DlColor color) override;
|
||||
void setStrokeWidth(float width) override;
|
||||
void setStrokeMiter(float limit) override;
|
||||
void setStrokeCap(DlStrokeCap cap) override;
|
||||
void setStrokeJoin(DlStrokeJoin join) override;
|
||||
void setColorSource(const DlColorSource* source) override;
|
||||
void setColorFilter(const DlColorFilter* filter) override;
|
||||
void setInvertColors(bool invert) override;
|
||||
void setBlendMode(DlBlendMode mode) override;
|
||||
void setPathEffect(const DlPathEffect* effect) override;
|
||||
void setMaskFilter(const DlMaskFilter* filter) override;
|
||||
void setImageFilter(const DlImageFilter* filter) override;
|
||||
|
||||
// |DlOpReceiver|
|
||||
void save() override;
|
||||
// |DlOpReceiver|
|
||||
void saveLayer(const SkRect* bounds,
|
||||
const SaveLayerOptions options,
|
||||
const DlImageFilter* backdrop = nullptr) override;
|
||||
|
||||
// |DlOpReceiver|
|
||||
void restore() override;
|
||||
// |DlCanvasReceiver|
|
||||
void restoreLayer(const DlImageFilter*,
|
||||
bool layer_content_was_unbounded,
|
||||
bool layer_could_distribute_opacity) override;
|
||||
|
||||
// |DlOpReceiver| all transform methods
|
||||
void translate(SkScalar tx, SkScalar ty) override;
|
||||
void scale(SkScalar sx, SkScalar sy) override;
|
||||
void rotate(SkScalar degrees) override;
|
||||
void skew(SkScalar sx, SkScalar sy) override;
|
||||
|
||||
// clang-format off
|
||||
// |DlOpReceiver|
|
||||
void transform2DAffine(SkScalar mxx, SkScalar mxy, SkScalar mxt,
|
||||
SkScalar myx, SkScalar myy, SkScalar myt) override;
|
||||
// |DlOpReceiver|
|
||||
void transformFullPerspective(
|
||||
SkScalar mxx, SkScalar mxy, SkScalar mxz, SkScalar mxt,
|
||||
SkScalar myx, SkScalar myy, SkScalar myz, SkScalar myt,
|
||||
SkScalar mzx, SkScalar mzy, SkScalar mzz, SkScalar mzt,
|
||||
SkScalar mwx, SkScalar mwy, SkScalar mwz, SkScalar mwt) override;
|
||||
// clang-format on
|
||||
|
||||
// |DlOpReceiver|
|
||||
void transformReset() override;
|
||||
|
||||
// |DlOpReceiver| all clip methods
|
||||
void clipRect(const SkRect& rect, ClipOp clip_op, bool is_aa) override;
|
||||
void clipRRect(const SkRRect& rrect, ClipOp clip_op, bool is_aa) override;
|
||||
void clipPath(const SkPath& path, ClipOp clip_op, bool is_aa) override;
|
||||
|
||||
// |DlOpReceiver| all render methods
|
||||
void drawColor(DlColor color, DlBlendMode mode) override;
|
||||
void drawPaint() override;
|
||||
void drawLine(const SkPoint& p0, const SkPoint& p1) override;
|
||||
void drawRect(const SkRect& rect) override;
|
||||
void drawOval(const SkRect& bounds) override;
|
||||
void drawCircle(const SkPoint& center, SkScalar radius) override;
|
||||
void drawRRect(const SkRRect& rrect) override;
|
||||
void drawDRRect(const SkRRect& outer, const SkRRect& inner) override;
|
||||
void drawPath(const SkPath& path) override;
|
||||
void drawArc(const SkRect& oval_bounds,
|
||||
SkScalar start_degrees,
|
||||
SkScalar sweep_degrees,
|
||||
bool use_center) override;
|
||||
void drawPoints(PointMode mode,
|
||||
uint32_t count,
|
||||
const SkPoint points[]) override;
|
||||
void drawVertices(const DlVertices* vertices, DlBlendMode mode) override;
|
||||
void drawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) override;
|
||||
void drawImageRect(
|
||||
const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes,
|
||||
SrcRectConstraint constraint = SrcRectConstraint::kFast) override;
|
||||
void drawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
bool render_with_attributes) override;
|
||||
void drawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
int count,
|
||||
DlBlendMode mode,
|
||||
DlImageSampling sampling,
|
||||
const SkRect* cull_rect,
|
||||
bool render_with_attributes) override;
|
||||
void drawDisplayList(const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity = SK_Scalar1) override;
|
||||
void drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) override;
|
||||
void drawShadow(const SkPath& path,
|
||||
const DlColor color,
|
||||
const SkScalar elevation,
|
||||
bool transparent_occluder,
|
||||
SkScalar dpr) override;
|
||||
|
||||
bool accumulateLocalBoundsForNextOp(const SkRect& r) override;
|
||||
bool accumulateUnboundedForNextOp() override;
|
||||
|
||||
bool is_nop() override { return tracker_->is_cull_rect_empty(); }
|
||||
|
||||
sk_sp<DisplayList> Build(bool can_distribute_opacity = false,
|
||||
bool affects_transparent_layer = true);
|
||||
|
||||
private:
|
||||
std::shared_ptr<DisplayListMatrixClipTracker> tracker_;
|
||||
std::shared_ptr<BoundsAccumulator> accumulator_;
|
||||
DisplayList::DlStorage storage_;
|
||||
|
||||
struct SaveInfo {
|
||||
size_t offset;
|
||||
bool deferred;
|
||||
bool is_layer;
|
||||
};
|
||||
std::vector<SaveInfo> save_infos_;
|
||||
void ResolveDeferredSave();
|
||||
|
||||
int render_op_count_ = 0;
|
||||
int op_index_ = 0;
|
||||
|
||||
// bytes and ops from |drawPicture| and |drawDisplayList|
|
||||
size_t nested_bytes_ = 0;
|
||||
int nested_op_count_ = 0;
|
||||
|
||||
bool is_ui_thread_safe_ = true;
|
||||
|
||||
template <typename T, typename... Args>
|
||||
void* Push(size_t extra, int op_inc, Args&&... args);
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_DISPLAY_LIST_DL_OP_RECORDER_H_
|
||||
@ -19,7 +19,7 @@ namespace flutter {
|
||||
// Structure holding the information necessary to dispatch and
|
||||
// potentially cull the DLOps during playback.
|
||||
//
|
||||
// Generally drawing ops will execute as long as |cur_index|
|
||||
// Generally drawing ops will execute as long as |cur_render_index|
|
||||
// is at or after |next_render_index|, so setting the latter
|
||||
// to 0 will render all primitives and setting it to MAX_INT
|
||||
// will skip all remaining rendering primitives.
|
||||
@ -40,7 +40,7 @@ namespace flutter {
|
||||
struct DispatchContext {
|
||||
DlOpReceiver& receiver;
|
||||
|
||||
int cur_index;
|
||||
int cur_render_index;
|
||||
int next_render_index;
|
||||
|
||||
int next_restore_index;
|
||||
@ -328,6 +328,7 @@ struct SaveOpBase : DLOp {
|
||||
bool needed = ctx.next_render_index <= restore_index;
|
||||
ctx.save_infos.emplace_back(ctx.next_restore_index, needed);
|
||||
ctx.next_restore_index = restore_index;
|
||||
ctx.cur_render_index++;
|
||||
return needed;
|
||||
}
|
||||
};
|
||||
@ -417,25 +418,44 @@ struct SaveLayerBackdropBoundsOp final : SaveOpBase {
|
||||
: DisplayListCompare::kNotEqual;
|
||||
}
|
||||
};
|
||||
// The base object for the restore() op
|
||||
// 4 byte header + no payload uses minimum 8 bytes (4 bytes unused)
|
||||
struct RestoreOp final : DLOp {
|
||||
struct RestoreOpBase : DLOp {
|
||||
RestoreOpBase() {}
|
||||
|
||||
inline bool restore_needed(DispatchContext& ctx) const {
|
||||
bool restore_needed;
|
||||
{
|
||||
// ensure all use of save_infos.back happens before the pop
|
||||
DispatchContext::SaveInfo& info = ctx.save_infos.back();
|
||||
restore_needed = info.save_was_needed;
|
||||
ctx.next_restore_index = info.previous_restore_index;
|
||||
}
|
||||
ctx.cur_render_index++;
|
||||
ctx.save_infos.pop_back();
|
||||
return restore_needed;
|
||||
}
|
||||
};
|
||||
// 4 byte header + no payload uses minimum 8 bytes (4 bytes unused)
|
||||
struct RestoreOp final : RestoreOpBase {
|
||||
static const auto kType = DisplayListOpType::kRestore;
|
||||
|
||||
RestoreOp() {}
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
DispatchContext::SaveInfo& info = ctx.save_infos.back();
|
||||
if (info.save_was_needed) {
|
||||
if (restore_needed(ctx)) {
|
||||
ctx.receiver.restore();
|
||||
}
|
||||
ctx.next_restore_index = info.previous_restore_index;
|
||||
ctx.save_infos.pop_back();
|
||||
}
|
||||
};
|
||||
|
||||
struct TransformClipOpBase : DLOp {
|
||||
inline bool op_needed(const DispatchContext& context) const {
|
||||
return context.next_render_index <= context.next_restore_index;
|
||||
inline bool tx_clip_needed(DispatchContext& ctx) const {
|
||||
// We only dispatch a transform or clip if we are going to render
|
||||
// something before it gets erased by the next restore.
|
||||
bool tx_clip_needed = (ctx.next_render_index <= ctx.next_restore_index);
|
||||
ctx.cur_render_index++;
|
||||
return tx_clip_needed;
|
||||
}
|
||||
};
|
||||
// 4 byte header + 8 byte payload uses 12 bytes but is rounded up to 16 bytes
|
||||
@ -449,7 +469,7 @@ struct TranslateOp final : TransformClipOpBase {
|
||||
const SkScalar ty;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (tx_clip_needed(ctx)) {
|
||||
ctx.receiver.translate(tx, ty);
|
||||
}
|
||||
}
|
||||
@ -465,7 +485,7 @@ struct ScaleOp final : TransformClipOpBase {
|
||||
const SkScalar sy;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (tx_clip_needed(ctx)) {
|
||||
ctx.receiver.scale(sx, sy);
|
||||
}
|
||||
}
|
||||
@ -479,7 +499,7 @@ struct RotateOp final : TransformClipOpBase {
|
||||
const SkScalar degrees;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (tx_clip_needed(ctx)) {
|
||||
ctx.receiver.rotate(degrees);
|
||||
}
|
||||
}
|
||||
@ -495,7 +515,7 @@ struct SkewOp final : TransformClipOpBase {
|
||||
const SkScalar sy;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (tx_clip_needed(ctx)) {
|
||||
ctx.receiver.skew(sx, sy);
|
||||
}
|
||||
}
|
||||
@ -515,7 +535,7 @@ struct Transform2DAffineOp final : TransformClipOpBase {
|
||||
const SkScalar myx, myy, myt;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (tx_clip_needed(ctx)) {
|
||||
ctx.receiver.transform2DAffine(mxx, mxy, mxt, //
|
||||
myx, myy, myt);
|
||||
}
|
||||
@ -544,7 +564,7 @@ struct TransformFullPerspectiveOp final : TransformClipOpBase {
|
||||
const SkScalar mwx, mwy, mwz, mwt;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (tx_clip_needed(ctx)) {
|
||||
ctx.receiver.transformFullPerspective(mxx, mxy, mxz, mxt, //
|
||||
myx, myy, myz, myt, //
|
||||
mzx, mzy, mzz, mzt, //
|
||||
@ -560,7 +580,7 @@ struct TransformResetOp final : TransformClipOpBase {
|
||||
TransformResetOp() = default;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (tx_clip_needed(ctx)) {
|
||||
ctx.receiver.transformReset();
|
||||
}
|
||||
}
|
||||
@ -587,7 +607,7 @@ struct TransformResetOp final : TransformClipOpBase {
|
||||
const Sk##shapetype shape; \
|
||||
\
|
||||
void dispatch(DispatchContext& ctx) const { \
|
||||
if (op_needed(ctx)) { \
|
||||
if (tx_clip_needed(ctx)) { \
|
||||
ctx.receiver.clip##shapetype(shape, DlCanvas::ClipOp::k##clipop, \
|
||||
is_aa); \
|
||||
} \
|
||||
@ -610,7 +630,7 @@ DEFINE_CLIP_SHAPE_OP(RRect, Difference)
|
||||
const SkPath path; \
|
||||
\
|
||||
void dispatch(DispatchContext& ctx) const { \
|
||||
if (op_needed(ctx)) { \
|
||||
if (tx_clip_needed(ctx)) { \
|
||||
ctx.receiver.clipPath(path, DlCanvas::ClipOp::k##clipop, is_aa); \
|
||||
} \
|
||||
} \
|
||||
@ -626,8 +646,8 @@ DEFINE_CLIP_PATH_OP(Difference)
|
||||
#undef DEFINE_CLIP_PATH_OP
|
||||
|
||||
struct DrawOpBase : DLOp {
|
||||
inline bool op_needed(const DispatchContext& ctx) const {
|
||||
return ctx.cur_index >= ctx.next_render_index;
|
||||
inline bool draw_needed(DispatchContext& ctx) const {
|
||||
return ctx.cur_render_index++ >= ctx.next_render_index;
|
||||
}
|
||||
};
|
||||
|
||||
@ -638,7 +658,7 @@ struct DrawPaintOp final : DrawOpBase {
|
||||
DrawPaintOp() {}
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (draw_needed(ctx)) {
|
||||
ctx.receiver.drawPaint();
|
||||
}
|
||||
}
|
||||
@ -654,7 +674,7 @@ struct DrawColorOp final : DrawOpBase {
|
||||
const DlBlendMode mode;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (draw_needed(ctx)) {
|
||||
ctx.receiver.drawColor(color, mode);
|
||||
}
|
||||
}
|
||||
@ -674,7 +694,7 @@ struct DrawColorOp final : DrawOpBase {
|
||||
const arg_type arg_name; \
|
||||
\
|
||||
void dispatch(DispatchContext& ctx) const { \
|
||||
if (op_needed(ctx)) { \
|
||||
if (draw_needed(ctx)) { \
|
||||
ctx.receiver.draw##op_name(arg_name); \
|
||||
} \
|
||||
} \
|
||||
@ -694,7 +714,7 @@ struct DrawPathOp final : DrawOpBase {
|
||||
const SkPath path;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (draw_needed(ctx)) {
|
||||
ctx.receiver.drawPath(path);
|
||||
}
|
||||
}
|
||||
@ -722,7 +742,7 @@ struct DrawPathOp final : DrawOpBase {
|
||||
const type2 name2; \
|
||||
\
|
||||
void dispatch(DispatchContext& ctx) const { \
|
||||
if (op_needed(ctx)) { \
|
||||
if (draw_needed(ctx)) { \
|
||||
ctx.receiver.draw##op_name(name1, name2); \
|
||||
} \
|
||||
} \
|
||||
@ -745,7 +765,7 @@ struct DrawArcOp final : DrawOpBase {
|
||||
const bool center;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (draw_needed(ctx)) {
|
||||
ctx.receiver.drawArc(bounds, start, sweep, center);
|
||||
}
|
||||
}
|
||||
@ -766,7 +786,7 @@ struct DrawArcOp final : DrawOpBase {
|
||||
const uint32_t count; \
|
||||
\
|
||||
void dispatch(DispatchContext& ctx) const { \
|
||||
if (op_needed(ctx)) { \
|
||||
if (draw_needed(ctx)) { \
|
||||
const SkPoint* pts = reinterpret_cast<const SkPoint*>(this + 1); \
|
||||
ctx.receiver.drawPoints(DlCanvas::PointMode::mode, count, pts); \
|
||||
} \
|
||||
@ -792,7 +812,7 @@ struct DrawVerticesOp final : DrawOpBase {
|
||||
const DlBlendMode mode;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (draw_needed(ctx)) {
|
||||
const DlVertices* vertices =
|
||||
reinterpret_cast<const DlVertices*>(this + 1);
|
||||
ctx.receiver.drawVertices(vertices, mode);
|
||||
@ -816,7 +836,7 @@ struct DrawVerticesOp final : DrawOpBase {
|
||||
const sk_sp<DlImage> image; \
|
||||
\
|
||||
void dispatch(DispatchContext& ctx) const { \
|
||||
if (op_needed(ctx)) { \
|
||||
if (draw_needed(ctx)) { \
|
||||
ctx.receiver.drawImage(image, point, sampling, with_attributes); \
|
||||
} \
|
||||
} \
|
||||
@ -858,7 +878,7 @@ struct DrawImageRectOp final : DrawOpBase {
|
||||
const sk_sp<DlImage> image;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (draw_needed(ctx)) {
|
||||
ctx.receiver.drawImageRect(image, src, dst, sampling,
|
||||
render_with_attributes, constraint);
|
||||
}
|
||||
@ -891,7 +911,7 @@ struct DrawImageRectOp final : DrawOpBase {
|
||||
const sk_sp<DlImage> image; \
|
||||
\
|
||||
void dispatch(DispatchContext& ctx) const { \
|
||||
if (op_needed(ctx)) { \
|
||||
if (draw_needed(ctx)) { \
|
||||
ctx.receiver.drawImageNine(image, center, dst, mode, \
|
||||
render_with_attributes); \
|
||||
} \
|
||||
@ -973,7 +993,7 @@ struct DrawAtlasOp final : DrawAtlasBaseOp {
|
||||
render_with_attributes) {}
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (draw_needed(ctx)) {
|
||||
const SkRSXform* xform = reinterpret_cast<const SkRSXform*>(this + 1);
|
||||
const SkRect* tex = reinterpret_cast<const SkRect*>(xform + count);
|
||||
const DlColor* colors =
|
||||
@ -1018,7 +1038,7 @@ struct DrawAtlasCulledOp final : DrawAtlasBaseOp {
|
||||
const SkRect cull_rect;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (draw_needed(ctx)) {
|
||||
const SkRSXform* xform = reinterpret_cast<const SkRSXform*>(this + 1);
|
||||
const SkRect* tex = reinterpret_cast<const SkRect*>(xform + count);
|
||||
const DlColor* colors =
|
||||
@ -1052,7 +1072,7 @@ struct DrawDisplayListOp final : DrawOpBase {
|
||||
const sk_sp<DisplayList> display_list;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (draw_needed(ctx)) {
|
||||
ctx.receiver.drawDisplayList(display_list, opacity);
|
||||
}
|
||||
}
|
||||
@ -1078,7 +1098,7 @@ struct DrawTextBlobOp final : DrawOpBase {
|
||||
const sk_sp<SkTextBlob> blob;
|
||||
|
||||
void dispatch(DispatchContext& ctx) const {
|
||||
if (op_needed(ctx)) {
|
||||
if (draw_needed(ctx)) {
|
||||
ctx.receiver.drawTextBlob(blob, x, y);
|
||||
}
|
||||
}
|
||||
@ -1101,7 +1121,7 @@ struct DrawTextBlobOp final : DrawOpBase {
|
||||
const SkPath path; \
|
||||
\
|
||||
void dispatch(DispatchContext& ctx) const { \
|
||||
if (op_needed(ctx)) { \
|
||||
if (draw_needed(ctx)) { \
|
||||
ctx.receiver.drawShadow(path, color, elevation, transparent_occluder, \
|
||||
dpr); \
|
||||
} \
|
||||
|
||||
@ -176,7 +176,7 @@ class DlPaint {
|
||||
return maskFilter_;
|
||||
}
|
||||
const DlMaskFilter* getMaskFilterPtr() const { return maskFilter_.get(); }
|
||||
DlPaint& setMaskFilter(std::shared_ptr<DlMaskFilter> filter) {
|
||||
DlPaint& setMaskFilter(std::shared_ptr<const DlMaskFilter> filter) {
|
||||
maskFilter_ = filter;
|
||||
return *this;
|
||||
}
|
||||
@ -189,7 +189,7 @@ class DlPaint {
|
||||
return pathEffect_;
|
||||
}
|
||||
const DlPathEffect* getPathEffectPtr() const { return pathEffect_.get(); }
|
||||
DlPaint& setPathEffect(std::shared_ptr<DlPathEffect> pathEffect) {
|
||||
DlPaint& setPathEffect(std::shared_ptr<const DlPathEffect> pathEffect) {
|
||||
pathEffect_ = pathEffect;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -279,7 +279,7 @@ class DlVertices {
|
||||
return static_cast<const char*>(base) + offset;
|
||||
}
|
||||
|
||||
friend class DisplayListBuilder;
|
||||
friend class DlOpRecorder;
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/display_list/dl_vertices.h"
|
||||
#include "flutter/display_list/testing/dl_test_equality.h"
|
||||
#include "flutter/display_list/utils/dl_comparable.h"
|
||||
|
||||
@ -418,7 +418,7 @@ class DlLinearGradientColorSource final : public DlGradientColorSourceBase {
|
||||
SkPoint end_point_;
|
||||
|
||||
friend class DlColorSource;
|
||||
friend class DisplayListBuilder;
|
||||
friend class DlOpRecorder;
|
||||
|
||||
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlLinearGradientColorSource);
|
||||
};
|
||||
@ -481,7 +481,7 @@ class DlRadialGradientColorSource final : public DlGradientColorSourceBase {
|
||||
SkScalar radius_;
|
||||
|
||||
friend class DlColorSource;
|
||||
friend class DisplayListBuilder;
|
||||
friend class DlOpRecorder;
|
||||
|
||||
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlRadialGradientColorSource);
|
||||
};
|
||||
@ -557,7 +557,7 @@ class DlConicalGradientColorSource final : public DlGradientColorSourceBase {
|
||||
SkScalar end_radius_;
|
||||
|
||||
friend class DlColorSource;
|
||||
friend class DisplayListBuilder;
|
||||
friend class DlOpRecorder;
|
||||
|
||||
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlConicalGradientColorSource);
|
||||
};
|
||||
@ -625,7 +625,7 @@ class DlSweepGradientColorSource final : public DlGradientColorSourceBase {
|
||||
SkScalar end_;
|
||||
|
||||
friend class DlColorSource;
|
||||
friend class DisplayListBuilder;
|
||||
friend class DlOpRecorder;
|
||||
|
||||
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlSweepGradientColorSource);
|
||||
};
|
||||
|
||||
@ -114,7 +114,7 @@ class DlDashPathEffect final : public DlPathEffect {
|
||||
int count_;
|
||||
SkScalar phase_;
|
||||
|
||||
friend class DisplayListBuilder;
|
||||
friend class DlOpRecorder;
|
||||
friend class DlPathEffect;
|
||||
|
||||
FML_DISALLOW_COPY_ASSIGN_AND_MOVE(DlDashPathEffect);
|
||||
|
||||
@ -182,14 +182,14 @@ void DlSkCanvasDispatcher::drawVertices(const DlVertices* vertices,
|
||||
DlBlendMode mode) {
|
||||
canvas_->drawVertices(ToSk(vertices), ToSk(mode), paint());
|
||||
}
|
||||
void DlSkCanvasDispatcher::drawImage(const sk_sp<DlImage> image,
|
||||
void DlSkCanvasDispatcher::drawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) {
|
||||
canvas_->drawImage(image ? image->skia_image() : nullptr, point.fX, point.fY,
|
||||
ToSk(sampling), safe_paint(render_with_attributes));
|
||||
}
|
||||
void DlSkCanvasDispatcher::drawImageRect(const sk_sp<DlImage> image,
|
||||
void DlSkCanvasDispatcher::drawImageRect(const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
@ -199,7 +199,7 @@ void DlSkCanvasDispatcher::drawImageRect(const sk_sp<DlImage> image,
|
||||
ToSk(sampling), safe_paint(render_with_attributes),
|
||||
ToSk(constraint));
|
||||
}
|
||||
void DlSkCanvasDispatcher::drawImageNine(const sk_sp<DlImage> image,
|
||||
void DlSkCanvasDispatcher::drawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
@ -214,7 +214,7 @@ void DlSkCanvasDispatcher::drawImageNine(const sk_sp<DlImage> image,
|
||||
canvas_->drawImageNine(skia_image.get(), center, dst, ToSk(filter),
|
||||
safe_paint(render_with_attributes));
|
||||
}
|
||||
void DlSkCanvasDispatcher::drawAtlas(const sk_sp<DlImage> atlas,
|
||||
void DlSkCanvasDispatcher::drawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
@ -236,7 +236,7 @@ void DlSkCanvasDispatcher::drawAtlas(const sk_sp<DlImage> atlas,
|
||||
safe_paint(render_with_attributes));
|
||||
}
|
||||
void DlSkCanvasDispatcher::drawDisplayList(
|
||||
const sk_sp<DisplayList> display_list,
|
||||
const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity) {
|
||||
const int restore_count = canvas_->getSaveCount();
|
||||
|
||||
@ -264,7 +264,7 @@ void DlSkCanvasDispatcher::drawDisplayList(
|
||||
// Restore canvas state to what it was before dispatching.
|
||||
canvas_->restoreToCount(restore_count);
|
||||
}
|
||||
void DlSkCanvasDispatcher::drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
void DlSkCanvasDispatcher::drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) {
|
||||
canvas_->drawTextBlob(blob, x, y, paint());
|
||||
|
||||
@ -71,22 +71,22 @@ class DlSkCanvasDispatcher : public virtual DlOpReceiver,
|
||||
bool useCenter) override;
|
||||
void drawPoints(PointMode mode, uint32_t count, const SkPoint pts[]) override;
|
||||
void drawVertices(const DlVertices* vertices, DlBlendMode mode) override;
|
||||
void drawImage(const sk_sp<DlImage> image,
|
||||
void drawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) override;
|
||||
void drawImageRect(const sk_sp<DlImage> image,
|
||||
void drawImageRect(const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes,
|
||||
SrcRectConstraint constraint) override;
|
||||
void drawImageNine(const sk_sp<DlImage> image,
|
||||
void drawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
bool render_with_attributes) override;
|
||||
void drawAtlas(const sk_sp<DlImage> atlas,
|
||||
void drawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
@ -95,9 +95,9 @@ class DlSkCanvasDispatcher : public virtual DlOpReceiver,
|
||||
DlImageSampling sampling,
|
||||
const SkRect* cullRect,
|
||||
bool render_with_attributes) override;
|
||||
void drawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
void drawDisplayList(const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity) override;
|
||||
void drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
void drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) override;
|
||||
void drawShadow(const SkPath& path,
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "flutter/display_list/display_list.h"
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/display_list/dl_op_flags.h"
|
||||
#include "flutter/display_list/dl_sampling_options.h"
|
||||
#include "flutter/display_list/skia/dl_sk_canvas.h"
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/display_list/testing/dl_test_snippets.h"
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/display_list/dl_op_receiver.h"
|
||||
|
||||
namespace flutter {
|
||||
@ -46,17 +46,17 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
|
||||
{"SetAntiAlias",
|
||||
{
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setAntiAlias(true); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.setAntiAlias(false); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setAntiAlias(false); }},
|
||||
}},
|
||||
{"SetDither",
|
||||
{
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setDither(true); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.setDither(false); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setDither(false); }},
|
||||
}},
|
||||
{"SetInvertColors",
|
||||
{
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setInvertColors(true); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.setInvertColors(false); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setInvertColors(false); }},
|
||||
}},
|
||||
{"SetStrokeCap",
|
||||
{
|
||||
@ -64,7 +64,7 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
|
||||
[](DlOpReceiver& r) { r.setStrokeCap(DlStrokeCap::kRound); }},
|
||||
{0, 8, 0, 0,
|
||||
[](DlOpReceiver& r) { r.setStrokeCap(DlStrokeCap::kSquare); }},
|
||||
{0, 0, 0, 0,
|
||||
{0, 8, 0, 0,
|
||||
[](DlOpReceiver& r) { r.setStrokeCap(DlStrokeCap::kButt); }},
|
||||
}},
|
||||
{"SetStrokeJoin",
|
||||
@ -73,7 +73,7 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
|
||||
[](DlOpReceiver& r) { r.setStrokeJoin(DlStrokeJoin::kBevel); }},
|
||||
{0, 8, 0, 0,
|
||||
[](DlOpReceiver& r) { r.setStrokeJoin(DlStrokeJoin::kRound); }},
|
||||
{0, 0, 0, 0,
|
||||
{0, 8, 0, 0,
|
||||
[](DlOpReceiver& r) { r.setStrokeJoin(DlStrokeJoin::kMiter); }},
|
||||
}},
|
||||
{"SetStyle",
|
||||
@ -84,26 +84,26 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
|
||||
[](DlOpReceiver& r) {
|
||||
r.setDrawStyle(DlDrawStyle::kStrokeAndFill);
|
||||
}},
|
||||
{0, 0, 0, 0,
|
||||
{0, 8, 0, 0,
|
||||
[](DlOpReceiver& r) { r.setDrawStyle(DlDrawStyle::kFill); }},
|
||||
}},
|
||||
{"SetStrokeWidth",
|
||||
{
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setStrokeWidth(1.0); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setStrokeWidth(5.0); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.setStrokeWidth(0.0); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setStrokeWidth(0.0); }},
|
||||
}},
|
||||
{"SetStrokeMiter",
|
||||
{
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setStrokeMiter(0.0); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setStrokeMiter(5.0); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.setStrokeMiter(4.0); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setStrokeMiter(4.0); }},
|
||||
}},
|
||||
{"SetColor",
|
||||
{
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setColor(SK_ColorGREEN); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setColor(SK_ColorBLUE); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.setColor(SK_ColorBLACK); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setColor(SK_ColorBLACK); }},
|
||||
}},
|
||||
{"SetBlendMode",
|
||||
{
|
||||
@ -111,7 +111,7 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
|
||||
[](DlOpReceiver& r) { r.setBlendMode(DlBlendMode::kSrcIn); }},
|
||||
{0, 8, 0, 0,
|
||||
[](DlOpReceiver& r) { r.setBlendMode(DlBlendMode::kDstIn); }},
|
||||
{0, 0, 0, 0,
|
||||
{0, 8, 0, 0,
|
||||
[](DlOpReceiver& r) { r.setBlendMode(DlBlendMode::kSrcOver); }},
|
||||
}},
|
||||
{"SetColorSource",
|
||||
@ -127,7 +127,7 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
|
||||
[](DlOpReceiver& r) { r.setColorSource(kTestSource4.get()); }},
|
||||
{0, 80 + 6 * 4, 0, 0,
|
||||
[](DlOpReceiver& r) { r.setColorSource(kTestSource5.get()); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.setColorSource(nullptr); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setColorSource(nullptr); }},
|
||||
}},
|
||||
{"SetImageFilter",
|
||||
{
|
||||
@ -185,7 +185,7 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
|
||||
[](DlOpReceiver& r) { r.setImageFilter(&kTestCFImageFilter1); }},
|
||||
{0, 24, 0, 0,
|
||||
[](DlOpReceiver& r) { r.setImageFilter(&kTestCFImageFilter2); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.setImageFilter(nullptr); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setImageFilter(nullptr); }},
|
||||
{0, 24, 0, 0,
|
||||
[](DlOpReceiver& r) {
|
||||
r.setImageFilter(
|
||||
@ -218,7 +218,7 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
|
||||
[](DlOpReceiver& r) {
|
||||
r.setColorFilter(DlLinearToSrgbGammaColorFilter::instance.get());
|
||||
}},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.setColorFilter(nullptr); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setColorFilter(nullptr); }},
|
||||
}},
|
||||
{"SetPathEffect",
|
||||
{
|
||||
@ -227,7 +227,7 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
|
||||
[](DlOpReceiver& r) { r.setPathEffect(kTestPathEffect1.get()); }},
|
||||
{0, 32, 0, 0,
|
||||
[](DlOpReceiver& r) { r.setPathEffect(kTestPathEffect2.get()); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.setPathEffect(nullptr); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setPathEffect(nullptr); }},
|
||||
}},
|
||||
{"SetMaskFilter",
|
||||
{
|
||||
@ -241,7 +241,7 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
|
||||
[](DlOpReceiver& r) { r.setMaskFilter(&kTestMaskFilter4); }},
|
||||
{0, 32, 0, 0,
|
||||
[](DlOpReceiver& r) { r.setMaskFilter(&kTestMaskFilter5); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.setMaskFilter(nullptr); }},
|
||||
{0, 8, 0, 0, [](DlOpReceiver& r) { r.setMaskFilter(nullptr); }},
|
||||
}},
|
||||
};
|
||||
}
|
||||
@ -354,7 +354,7 @@ std::vector<DisplayListInvocationGroup> CreateAllTransformOps() {
|
||||
{1, 16, 1, 16, [](DlOpReceiver& r) { r.translate(10, 10); }},
|
||||
{1, 16, 1, 16, [](DlOpReceiver& r) { r.translate(10, 15); }},
|
||||
{1, 16, 1, 16, [](DlOpReceiver& r) { r.translate(15, 10); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.translate(0, 0); }},
|
||||
{1, 16, 1, 16, [](DlOpReceiver& r) { r.translate(0, 0); }},
|
||||
}},
|
||||
{"Scale",
|
||||
{
|
||||
@ -362,15 +362,15 @@ std::vector<DisplayListInvocationGroup> CreateAllTransformOps() {
|
||||
{1, 16, 1, 16, [](DlOpReceiver& r) { r.scale(2, 2); }},
|
||||
{1, 16, 1, 16, [](DlOpReceiver& r) { r.scale(2, 3); }},
|
||||
{1, 16, 1, 16, [](DlOpReceiver& r) { r.scale(3, 2); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.scale(1, 1); }},
|
||||
{1, 16, 1, 16, [](DlOpReceiver& r) { r.scale(1, 1); }},
|
||||
}},
|
||||
{"Rotate",
|
||||
{
|
||||
// cv.rotate(0) is ignored, otherwise expressed as concat(rotmatrix)
|
||||
{1, 8, 1, 32, [](DlOpReceiver& r) { r.rotate(30); }},
|
||||
{1, 8, 1, 32, [](DlOpReceiver& r) { r.rotate(45); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.rotate(0); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.rotate(360); }},
|
||||
{1, 8, 1, 32, [](DlOpReceiver& r) { r.rotate(0); }},
|
||||
{1, 8, 1, 32, [](DlOpReceiver& r) { r.rotate(360); }},
|
||||
}},
|
||||
{"Skew",
|
||||
{
|
||||
@ -379,14 +379,14 @@ std::vector<DisplayListInvocationGroup> CreateAllTransformOps() {
|
||||
{1, 16, 1, 32, [](DlOpReceiver& r) { r.skew(0.1, 0.1); }},
|
||||
{1, 16, 1, 32, [](DlOpReceiver& r) { r.skew(0.1, 0.2); }},
|
||||
{1, 16, 1, 32, [](DlOpReceiver& r) { r.skew(0.2, 0.1); }},
|
||||
{0, 0, 0, 0, [](DlOpReceiver& r) { r.skew(0, 0); }},
|
||||
{1, 16, 1, 32, [](DlOpReceiver& r) { r.skew(0, 0); }},
|
||||
}},
|
||||
{"Transform2DAffine",
|
||||
{
|
||||
{1, 32, 1, 32,
|
||||
[](DlOpReceiver& r) { r.transform2DAffine(0, 1, 12, 1, 0, 33); }},
|
||||
// r.transform(identity) is ignored
|
||||
{0, 0, 0, 0,
|
||||
{1, 32, 1, 32,
|
||||
[](DlOpReceiver& r) { r.transform2DAffine(1, 0, 0, 0, 1, 0); }},
|
||||
}},
|
||||
{"TransformFullPerspective",
|
||||
@ -397,13 +397,13 @@ std::vector<DisplayListInvocationGroup> CreateAllTransformOps() {
|
||||
0, 0, 0, 12);
|
||||
}},
|
||||
// r.transform(2D affine) is reduced to 2x3
|
||||
{1, 32, 1, 32,
|
||||
{1, 72, 1, 72,
|
||||
[](DlOpReceiver& r) {
|
||||
r.transformFullPerspective(2, 1, 0, 4, 1, 3, 0, 5, 0, 0, 1, 0, 0,
|
||||
0, 0, 1);
|
||||
}},
|
||||
// r.transform(identity) is ignored
|
||||
{0, 0, 0, 0,
|
||||
{1, 72, 1, 72,
|
||||
[](DlOpReceiver& r) {
|
||||
r.transformFullPerspective(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0,
|
||||
0, 0, 1);
|
||||
@ -488,13 +488,11 @@ std::vector<DisplayListInvocationGroup> CreateAllClipOps() {
|
||||
[](DlOpReceiver& r) {
|
||||
r.clipPath(kTestPath1, DlCanvas::ClipOp::kDifference, false);
|
||||
}},
|
||||
// clipPath(rect) becomes clipRect
|
||||
{1, 24, 1, 24,
|
||||
[](DlOpReceiver& r) {
|
||||
r.clipPath(kTestPathRect, DlCanvas::ClipOp::kIntersect, true);
|
||||
}},
|
||||
// clipPath(oval) becomes clipRRect
|
||||
{1, 64, 1, 64,
|
||||
{1, 24, 1, 24,
|
||||
[](DlOpReceiver& r) {
|
||||
r.clipPath(kTestPathOval, DlCanvas::ClipOp::kIntersect, true);
|
||||
}},
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
#define FLUTTER_DISPLAY_LIST_TESTING_DL_TEST_SNIPPETS_H_
|
||||
|
||||
#include "flutter/display_list/display_list.h"
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
|
||||
#include "third_party/skia/include/core/SkCanvas.h"
|
||||
#include "third_party/skia/include/core/SkSurface.h"
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "flutter/display_list/dl_canvas_to_receiver.h"
|
||||
#include "flutter/display_list/geometry/dl_rtree.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
|
||||
@ -21,13 +22,13 @@
|
||||
|
||||
namespace flutter {
|
||||
|
||||
enum class BoundsAccumulatorType {
|
||||
kRect,
|
||||
kRTree,
|
||||
};
|
||||
|
||||
class BoundsAccumulator {
|
||||
public:
|
||||
enum class Type {
|
||||
kRect,
|
||||
kRTree,
|
||||
};
|
||||
|
||||
/// function definition for modifying the bounds of a rectangle
|
||||
/// during a restore operation. The function is used primarily
|
||||
/// to account for the bounds impact of an ImageFilter on a
|
||||
@ -48,6 +49,8 @@ class BoundsAccumulator {
|
||||
|
||||
virtual ~BoundsAccumulator() = default;
|
||||
|
||||
virtual Type type() const = 0;
|
||||
|
||||
virtual void accumulate(const SkRect& r, int index = 0) = 0;
|
||||
|
||||
/// Save aside the rects/bounds currently being accumulated and start
|
||||
@ -85,8 +88,6 @@ class BoundsAccumulator {
|
||||
virtual SkRect bounds() const = 0;
|
||||
|
||||
virtual sk_sp<DlRTree> rtree() const = 0;
|
||||
|
||||
virtual BoundsAccumulatorType type() const = 0;
|
||||
};
|
||||
|
||||
class RectBoundsAccumulator final : public virtual BoundsAccumulator {
|
||||
@ -108,9 +109,7 @@ class RectBoundsAccumulator final : public virtual BoundsAccumulator {
|
||||
return rect_.bounds();
|
||||
}
|
||||
|
||||
BoundsAccumulatorType type() const override {
|
||||
return BoundsAccumulatorType::kRect;
|
||||
}
|
||||
Type type() const override { return Type::kRect; }
|
||||
|
||||
sk_sp<DlRTree> rtree() const override { return nullptr; }
|
||||
|
||||
@ -153,9 +152,7 @@ class RTreeBoundsAccumulator final : public virtual BoundsAccumulator {
|
||||
|
||||
sk_sp<DlRTree> rtree() const override;
|
||||
|
||||
BoundsAccumulatorType type() const override {
|
||||
return BoundsAccumulatorType::kRTree;
|
||||
}
|
||||
Type type() const override { return Type::kRTree; }
|
||||
|
||||
private:
|
||||
std::vector<SkRect> rects_;
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
#include "flutter/display_list/utils/dl_matrix_clip_tracker.h"
|
||||
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
@ -100,22 +100,22 @@ class IgnoreDrawDispatchHelper : public virtual DlOpReceiver {
|
||||
uint32_t count,
|
||||
const SkPoint points[]) override {}
|
||||
void drawVertices(const DlVertices* vertices, DlBlendMode mode) override {}
|
||||
void drawImage(const sk_sp<DlImage> image,
|
||||
void drawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) override {}
|
||||
void drawImageRect(const sk_sp<DlImage> image,
|
||||
void drawImageRect(const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes,
|
||||
SrcRectConstraint constraint) override {}
|
||||
void drawImageNine(const sk_sp<DlImage> image,
|
||||
void drawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
bool render_with_attributes) override {}
|
||||
void drawAtlas(const sk_sp<DlImage> atlas,
|
||||
void drawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
@ -124,9 +124,9 @@ class IgnoreDrawDispatchHelper : public virtual DlOpReceiver {
|
||||
DlImageSampling sampling,
|
||||
const SkRect* cull_rect,
|
||||
bool render_with_attributes) override {}
|
||||
void drawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
void drawDisplayList(const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity) override {}
|
||||
void drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
void drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) override {}
|
||||
void drawShadow(const SkPath& path,
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/display_list/skia/dl_sk_canvas.h"
|
||||
#include "flutter/flow/surface_frame.h"
|
||||
#include "flutter/fml/memory/ref_counted.h"
|
||||
|
||||
@ -68,7 +68,6 @@ TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerCheckBoard) {
|
||||
DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
|
||||
}
|
||||
|
||||
reset_display_list();
|
||||
layer->Paint(checkerboard_context());
|
||||
{
|
||||
DisplayListBuilder expected_builder;
|
||||
@ -89,8 +88,8 @@ TEST_F(CheckerBoardLayerTest, ClipRectSaveLayerCheckBoard) {
|
||||
}
|
||||
expected_builder.Restore();
|
||||
}
|
||||
EXPECT_TRUE(
|
||||
DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
|
||||
EXPECT_TRUE(DisplayListsEQ_Verbose(checkerboard_display_list(),
|
||||
expected_builder.Build()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -145,7 +144,6 @@ TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerCheckBoard) {
|
||||
DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
|
||||
}
|
||||
|
||||
reset_display_list();
|
||||
layer->Paint(checkerboard_context());
|
||||
{
|
||||
DisplayListBuilder expected_builder;
|
||||
@ -166,8 +164,8 @@ TEST_F(CheckerBoardLayerTest, ClipPathSaveLayerCheckBoard) {
|
||||
}
|
||||
expected_builder.Restore();
|
||||
}
|
||||
EXPECT_TRUE(
|
||||
DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
|
||||
EXPECT_TRUE(DisplayListsEQ_Verbose(checkerboard_display_list(),
|
||||
expected_builder.Build()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,7 +219,6 @@ TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerCheckBoard) {
|
||||
DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
|
||||
}
|
||||
|
||||
reset_display_list();
|
||||
layer->Paint(checkerboard_context());
|
||||
{
|
||||
DisplayListBuilder expected_builder;
|
||||
@ -242,8 +239,8 @@ TEST_F(CheckerBoardLayerTest, ClipRRectSaveLayerCheckBoard) {
|
||||
}
|
||||
expected_builder.Restore();
|
||||
}
|
||||
EXPECT_TRUE(
|
||||
DisplayListsEQ_Verbose(display_list(), expected_builder.Build()));
|
||||
EXPECT_TRUE(DisplayListsEQ_Verbose(checkerboard_display_list(),
|
||||
expected_builder.Build()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/flow/layer_snapshot_store.h"
|
||||
#include "flutter/flow/layers/cacheable_layer.h"
|
||||
#include "flutter/flow/layers/offscreen_surface.h"
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
#include "flutter/flow/layers/display_list_layer.h"
|
||||
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/flow/layers/layer_tree.h"
|
||||
#include "flutter/flow/testing/diff_context_test.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
|
||||
@ -525,9 +525,11 @@ TEST_F(ImageFilterLayerTest, CacheImageFilterLayerSelf) {
|
||||
}
|
||||
|
||||
// frame 2.
|
||||
reset_display_list();
|
||||
layer->Preroll(preroll_context());
|
||||
layer->Paint(display_list_paint_context());
|
||||
// frame 3.
|
||||
reset_display_list();
|
||||
layer->Preroll(preroll_context());
|
||||
layer->Paint(display_list_paint_context());
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
#include "flutter/display_list/benchmarking/dl_complexity.h"
|
||||
#include "flutter/display_list/display_list.h"
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/display_list/testing/dl_test_snippets.h"
|
||||
#include "flutter/flow/layers/container_layer.h"
|
||||
#include "flutter/flow/layers/display_list_layer.h"
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
#include <optional>
|
||||
|
||||
#include "flutter/common/graphics/gl_context_switch.h"
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/display_list/skia/dl_sk_canvas.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/fml/time/time_point.h"
|
||||
|
||||
@ -5,7 +5,8 @@
|
||||
#include "diff_context_test.h"
|
||||
|
||||
#include <utility>
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
@ -72,11 +72,11 @@ class LayerTestBase : public CanvasTestBase<BaseT> {
|
||||
.raster_cache = nullptr,
|
||||
// clang-format on
|
||||
},
|
||||
display_list_builder_(kDlBounds),
|
||||
display_list_paint_context_{
|
||||
// clang-format off
|
||||
.state_stack = display_list_state_stack_,
|
||||
.canvas = &display_list_builder_,
|
||||
// canvas is set below by resetting the display_list
|
||||
.canvas = nullptr,
|
||||
.gr_context = nullptr,
|
||||
.view_embedder = nullptr,
|
||||
.raster_time = raster_time_,
|
||||
@ -88,7 +88,8 @@ class LayerTestBase : public CanvasTestBase<BaseT> {
|
||||
checkerboard_context_{
|
||||
// clang-format off
|
||||
.state_stack = checkerboard_state_stack_,
|
||||
.canvas = &display_list_builder_,
|
||||
// canvas is set below by resetting the display_list
|
||||
.canvas = nullptr,
|
||||
.gr_context = nullptr,
|
||||
.view_embedder = nullptr,
|
||||
.raster_time = raster_time_,
|
||||
@ -100,8 +101,8 @@ class LayerTestBase : public CanvasTestBase<BaseT> {
|
||||
use_null_raster_cache();
|
||||
preroll_state_stack_.set_preroll_delegate(kGiantRect, SkMatrix::I());
|
||||
paint_state_stack_.set_delegate(&TestT::mock_canvas());
|
||||
display_list_state_stack_.set_delegate(&display_list_builder_);
|
||||
checkerboard_state_stack_.set_delegate(&display_list_builder_);
|
||||
reset_display_list();
|
||||
reset_checkerboard_display_list();
|
||||
checkerboard_state_stack_.set_checkerboard_func(draw_checkerboard);
|
||||
checkerboard_paint_.setColor(checkerboard_color_);
|
||||
}
|
||||
@ -170,19 +171,44 @@ class LayerTestBase : public CanvasTestBase<BaseT> {
|
||||
PaintContext& checkerboard_context() { return checkerboard_context_; }
|
||||
LayerSnapshotStore& layer_snapshot_store() { return snapshot_store_; }
|
||||
|
||||
sk_sp<DisplayList> checkerboard_display_list() {
|
||||
if (checkerboard_display_list_ == nullptr) {
|
||||
if (checkerboard_builder_.get()) {
|
||||
checkerboard_state_stack_.clear_delegate();
|
||||
checkerboard_display_list_ = checkerboard_builder_->Build();
|
||||
checkerboard_builder_.reset();
|
||||
checkerboard_context_.canvas = nullptr;
|
||||
}
|
||||
}
|
||||
return checkerboard_display_list_;
|
||||
}
|
||||
|
||||
sk_sp<DisplayList> display_list() {
|
||||
if (display_list_ == nullptr) {
|
||||
display_list_ = display_list_builder_.Build();
|
||||
if (display_list_builder_.get()) {
|
||||
display_list_state_stack_.clear_delegate();
|
||||
display_list_ = display_list_builder_->Build();
|
||||
display_list_builder_.reset();
|
||||
display_list_paint_context_.canvas = nullptr;
|
||||
}
|
||||
}
|
||||
return display_list_;
|
||||
}
|
||||
|
||||
void reset_checkerboard_display_list() {
|
||||
checkerboard_display_list_ = nullptr;
|
||||
checkerboard_state_stack_.clear_delegate();
|
||||
checkerboard_builder_.reset(new DisplayListBuilder(kDlBounds));
|
||||
checkerboard_state_stack_.set_delegate(checkerboard_builder_.get());
|
||||
checkerboard_context_.canvas = checkerboard_builder_.get();
|
||||
}
|
||||
|
||||
void reset_display_list() {
|
||||
display_list_ = nullptr;
|
||||
// Build() will leave the builder in a state to start recording a new DL
|
||||
display_list_builder_.Build();
|
||||
// Make sure we are starting from a fresh state stack
|
||||
FML_DCHECK(display_list_state_stack_.is_empty());
|
||||
display_list_state_stack_.clear_delegate();
|
||||
display_list_builder_.reset(new DisplayListBuilder(kDlBounds));
|
||||
display_list_state_stack_.set_delegate(display_list_builder_.get());
|
||||
display_list_paint_context_.canvas = display_list_builder_.get();
|
||||
}
|
||||
|
||||
void enable_leaf_layer_tracing() {
|
||||
@ -220,6 +246,7 @@ class LayerTestBase : public CanvasTestBase<BaseT> {
|
||||
}
|
||||
|
||||
LayerStateStack preroll_state_stack_;
|
||||
LayerStateStack display_list_state_stack_;
|
||||
LayerStateStack paint_state_stack_;
|
||||
LayerStateStack checkerboard_state_stack_;
|
||||
FixedRefreshRateStopwatch raster_time_;
|
||||
@ -229,10 +256,11 @@ class LayerTestBase : public CanvasTestBase<BaseT> {
|
||||
std::unique_ptr<RasterCache> raster_cache_;
|
||||
PrerollContext preroll_context_;
|
||||
PaintContext paint_context_;
|
||||
DisplayListBuilder display_list_builder_;
|
||||
LayerStateStack display_list_state_stack_;
|
||||
std::unique_ptr<DisplayListBuilder> display_list_builder_;
|
||||
sk_sp<DisplayList> display_list_;
|
||||
PaintContext display_list_paint_context_;
|
||||
std::unique_ptr<DisplayListBuilder> checkerboard_builder_;
|
||||
sk_sp<DisplayList> checkerboard_display_list_;
|
||||
DlPaint checkerboard_paint_;
|
||||
PaintContext checkerboard_context_;
|
||||
LayerSnapshotStore snapshot_store_;
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
#include "flutter/flow/testing/mock_texture.h"
|
||||
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/testing/display_list_testing.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
|
||||
@ -972,7 +972,7 @@ void DlDispatcher::drawVertices(const flutter::DlVertices* vertices,
|
||||
}
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void DlDispatcher::drawImage(const sk_sp<flutter::DlImage> image,
|
||||
void DlDispatcher::drawImage(const sk_sp<flutter::DlImage>& image,
|
||||
const SkPoint point,
|
||||
flutter::DlImageSampling sampling,
|
||||
bool render_with_attributes) {
|
||||
@ -1001,7 +1001,7 @@ void DlDispatcher::drawImage(const sk_sp<flutter::DlImage> image,
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void DlDispatcher::drawImageRect(
|
||||
const sk_sp<flutter::DlImage> image,
|
||||
const sk_sp<flutter::DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
flutter::DlImageSampling sampling,
|
||||
@ -1017,7 +1017,7 @@ void DlDispatcher::drawImageRect(
|
||||
}
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void DlDispatcher::drawImageNine(const sk_sp<flutter::DlImage> image,
|
||||
void DlDispatcher::drawImageNine(const sk_sp<flutter::DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
flutter::DlFilterMode filter,
|
||||
@ -1031,7 +1031,7 @@ void DlDispatcher::drawImageNine(const sk_sp<flutter::DlImage> image,
|
||||
}
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void DlDispatcher::drawAtlas(const sk_sp<flutter::DlImage> atlas,
|
||||
void DlDispatcher::drawAtlas(const sk_sp<flutter::DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const flutter::DlColor colors[],
|
||||
@ -1050,7 +1050,7 @@ void DlDispatcher::drawAtlas(const sk_sp<flutter::DlImage> atlas,
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void DlDispatcher::drawDisplayList(
|
||||
const sk_sp<flutter::DisplayList> display_list,
|
||||
const sk_sp<flutter::DisplayList>& display_list,
|
||||
SkScalar opacity) {
|
||||
// Save all values that must remain untouched after the operation.
|
||||
Paint saved_paint = paint_;
|
||||
@ -1108,7 +1108,7 @@ void DlDispatcher::drawDisplayList(
|
||||
}
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void DlDispatcher::drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
void DlDispatcher::drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) {
|
||||
const auto text_frame = MakeTextFrameFromTextBlobSkia(blob);
|
||||
|
||||
@ -172,13 +172,13 @@ class DlDispatcher final : public flutter::DlOpReceiver {
|
||||
flutter::DlBlendMode dl_mode) override;
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void drawImage(const sk_sp<flutter::DlImage> image,
|
||||
void drawImage(const sk_sp<flutter::DlImage>& image,
|
||||
const SkPoint point,
|
||||
flutter::DlImageSampling sampling,
|
||||
bool render_with_attributes) override;
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void drawImageRect(const sk_sp<flutter::DlImage> image,
|
||||
void drawImageRect(const sk_sp<flutter::DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
flutter::DlImageSampling sampling,
|
||||
@ -186,14 +186,14 @@ class DlDispatcher final : public flutter::DlOpReceiver {
|
||||
SrcRectConstraint constraint) override;
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void drawImageNine(const sk_sp<flutter::DlImage> image,
|
||||
void drawImageNine(const sk_sp<flutter::DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
flutter::DlFilterMode filter,
|
||||
bool render_with_attributes) override;
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void drawAtlas(const sk_sp<flutter::DlImage> atlas,
|
||||
void drawAtlas(const sk_sp<flutter::DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const flutter::DlColor colors[],
|
||||
@ -204,11 +204,11 @@ class DlDispatcher final : public flutter::DlOpReceiver {
|
||||
bool render_with_attributes) override;
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void drawDisplayList(const sk_sp<flutter::DisplayList> display_list,
|
||||
void drawDisplayList(const sk_sp<flutter::DisplayList>& display_list,
|
||||
SkScalar opacity) override;
|
||||
|
||||
// |flutter::DlOpReceiver|
|
||||
void drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
void drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) override;
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "flutter/display_list/display_list.h"
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "impeller/playground/playground_test.h"
|
||||
#include "third_party/skia/include/core/SkFont.h"
|
||||
|
||||
@ -7,8 +7,8 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/display_list/dl_blend_mode.h"
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/dl_color.h"
|
||||
#include "flutter/display_list/dl_paint.h"
|
||||
#include "flutter/display_list/dl_tile_mode.h"
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/lib/ui/floating_point.h"
|
||||
#include "flutter/lib/ui/painting/image.h"
|
||||
#include "flutter/lib/ui/painting/image_filter.h"
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
|
||||
#include "flutter/lib/ui/painting/paint.h"
|
||||
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
#include "flutter/lib/ui/floating_point.h"
|
||||
#include "flutter/lib/ui/painting/color_filter.h"
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
#ifndef FLUTTER_LIB_UI_PAINTING_PICTURE_RECORDER_H_
|
||||
#define FLUTTER_LIB_UI_PAINTING_PICTURE_RECORDER_H_
|
||||
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/lib/ui/dart_wrapper.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
@ -81,13 +81,13 @@ void DlOpSpy::drawVertices(const DlVertices* vertices, DlBlendMode mode) {
|
||||
// transparent needs examine all the pixels in the image object, which is slow.
|
||||
// Drawing a completely transparent image is not a valid use case, thus, such
|
||||
// case is ignored.
|
||||
void DlOpSpy::drawImage(const sk_sp<DlImage> image,
|
||||
void DlOpSpy::drawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) {
|
||||
did_draw_ = true;
|
||||
}
|
||||
void DlOpSpy::drawImageRect(const sk_sp<DlImage> image,
|
||||
void DlOpSpy::drawImageRect(const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
@ -95,14 +95,14 @@ void DlOpSpy::drawImageRect(const sk_sp<DlImage> image,
|
||||
SrcRectConstraint constraint) {
|
||||
did_draw_ = true;
|
||||
}
|
||||
void DlOpSpy::drawImageNine(const sk_sp<DlImage> image,
|
||||
void DlOpSpy::drawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
bool render_with_attributes) {
|
||||
did_draw_ = true;
|
||||
}
|
||||
void DlOpSpy::drawAtlas(const sk_sp<DlImage> atlas,
|
||||
void DlOpSpy::drawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
@ -113,7 +113,7 @@ void DlOpSpy::drawAtlas(const sk_sp<DlImage> atlas,
|
||||
bool render_with_attributes) {
|
||||
did_draw_ = true;
|
||||
}
|
||||
void DlOpSpy::drawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
void DlOpSpy::drawDisplayList(const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity) {
|
||||
if (did_draw_ || opacity == 0) {
|
||||
return;
|
||||
@ -122,7 +122,7 @@ void DlOpSpy::drawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
display_list->Dispatch(receiver);
|
||||
did_draw_ |= receiver.did_draw();
|
||||
}
|
||||
void DlOpSpy::drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
void DlOpSpy::drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) {
|
||||
did_draw_ |= will_draw_;
|
||||
|
||||
@ -60,23 +60,23 @@ class DlOpSpy final : public virtual DlOpReceiver,
|
||||
uint32_t count,
|
||||
const SkPoint points[]) override;
|
||||
void drawVertices(const DlVertices* vertices, DlBlendMode mode) override;
|
||||
void drawImage(const sk_sp<DlImage> image,
|
||||
void drawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) override;
|
||||
void drawImageRect(
|
||||
const sk_sp<DlImage> image,
|
||||
const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes,
|
||||
SrcRectConstraint constraint = SrcRectConstraint::kFast) override;
|
||||
void drawImageNine(const sk_sp<DlImage> image,
|
||||
void drawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
bool render_with_attributes) override;
|
||||
void drawAtlas(const sk_sp<DlImage> atlas,
|
||||
void drawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
@ -85,9 +85,9 @@ class DlOpSpy final : public virtual DlOpReceiver,
|
||||
DlImageSampling sampling,
|
||||
const SkRect* cull_rect,
|
||||
bool render_with_attributes) override;
|
||||
void drawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
void drawDisplayList(const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity = SK_Scalar1) override;
|
||||
void drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
void drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) override;
|
||||
void drawShadow(const SkPath& path,
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "flutter/display_list/display_list.h"
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/shell/common/dl_op_spy.h"
|
||||
#include "flutter/testing/testing.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
#include "flutter/shell/platform/embedder/embedder_external_view.h"
|
||||
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "flutter/shell/common/dl_op_spy.h"
|
||||
|
||||
|
||||
@ -791,7 +791,7 @@ void DisplayListStreamDispatcher::drawVertices(const DlVertices* vertices,
|
||||
out_array("indices", vertices->index_count(), vertices->indices())
|
||||
<< "), " << mode << ");" << std::endl;
|
||||
}
|
||||
void DisplayListStreamDispatcher::drawImage(const sk_sp<DlImage> image,
|
||||
void DisplayListStreamDispatcher::drawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) {
|
||||
@ -801,7 +801,7 @@ void DisplayListStreamDispatcher::drawImage(const sk_sp<DlImage> image,
|
||||
<< "with attributes: " << render_with_attributes
|
||||
<< ");" << std::endl;
|
||||
}
|
||||
void DisplayListStreamDispatcher::drawImageRect(const sk_sp<DlImage> image,
|
||||
void DisplayListStreamDispatcher::drawImageRect(const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
@ -815,7 +815,7 @@ void DisplayListStreamDispatcher::drawImageRect(const sk_sp<DlImage> image,
|
||||
<< constraint
|
||||
<< ");" << std::endl;
|
||||
}
|
||||
void DisplayListStreamDispatcher::drawImageNine(const sk_sp<DlImage> image,
|
||||
void DisplayListStreamDispatcher::drawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
@ -827,7 +827,7 @@ void DisplayListStreamDispatcher::drawImageNine(const sk_sp<DlImage> image,
|
||||
<< "with attributes: " << render_with_attributes
|
||||
<< ");" << std::endl;
|
||||
}
|
||||
void DisplayListStreamDispatcher::drawAtlas(const sk_sp<DlImage> atlas,
|
||||
void DisplayListStreamDispatcher::drawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
@ -845,14 +845,14 @@ void DisplayListStreamDispatcher::drawAtlas(const sk_sp<DlImage> atlas,
|
||||
<< ");" << std::endl;
|
||||
}
|
||||
void DisplayListStreamDispatcher::drawDisplayList(
|
||||
const sk_sp<DisplayList> display_list, SkScalar opacity) {
|
||||
const sk_sp<DisplayList>& display_list, SkScalar opacity) {
|
||||
startl() << "drawDisplayList("
|
||||
<< "ID: " << display_list->unique_id() << ", "
|
||||
<< "bounds: " << display_list->bounds() << ", "
|
||||
<< "opacity: " << opacity
|
||||
<< ");" << std::endl;
|
||||
}
|
||||
void DisplayListStreamDispatcher::drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
void DisplayListStreamDispatcher::drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) {
|
||||
startl() << "drawTextBlob("
|
||||
|
||||
@ -115,22 +115,22 @@ class DisplayListStreamDispatcher final : public DlOpReceiver {
|
||||
uint32_t count,
|
||||
const SkPoint points[]) override;
|
||||
void drawVertices(const DlVertices* vertices, DlBlendMode mode) override;
|
||||
void drawImage(const sk_sp<DlImage> image,
|
||||
void drawImage(const sk_sp<DlImage>& image,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) override;
|
||||
void drawImageRect(const sk_sp<DlImage> image,
|
||||
void drawImageRect(const sk_sp<DlImage>& image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes,
|
||||
SrcRectConstraint constraint) override;
|
||||
void drawImageNine(const sk_sp<DlImage> image,
|
||||
void drawImageNine(const sk_sp<DlImage>& image,
|
||||
const SkIRect& center,
|
||||
const SkRect& dst,
|
||||
DlFilterMode filter,
|
||||
bool render_with_attributes) override;
|
||||
void drawAtlas(const sk_sp<DlImage> atlas,
|
||||
void drawAtlas(const sk_sp<DlImage>& atlas,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
@ -139,9 +139,9 @@ class DisplayListStreamDispatcher final : public DlOpReceiver {
|
||||
DlImageSampling sampling,
|
||||
const SkRect* cull_rect,
|
||||
bool render_with_attributes) override;
|
||||
void drawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
void drawDisplayList(const sk_sp<DisplayList>& display_list,
|
||||
SkScalar opacity) override;
|
||||
void drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
void drawTextBlob(const sk_sp<SkTextBlob>& blob,
|
||||
SkScalar x,
|
||||
SkScalar y) override;
|
||||
void drawShadow(const SkPath& path,
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
|
||||
[[maybe_unused]] static constexpr SkRect kEmptyRect = SkRect::MakeEmpty();
|
||||
|
||||
// Mock |SkCanvas|, useful for writing tests that use Skia but do not interact
|
||||
// with the GPU.
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
#ifndef LIB_TXT_SRC_PARAGRAPH_H_
|
||||
#define LIB_TXT_SRC_PARAGRAPH_H_
|
||||
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/display_list/display_list_builder.h"
|
||||
#include "line_metrics.h"
|
||||
#include "paragraph_style.h"
|
||||
#include "third_party/skia/include/core/SkRect.h"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user