[embedder] embedder external view adopt DisplayListEmbedderViewSlice (flutter/engine#40578)
[embedder] embedder external view adopt DisplayListEmbedderViewSlice
This commit is contained in:
@@ -207,6 +207,7 @@
|
||||
../../../flutter/shell/common/animator_unittests.cc
|
||||
../../../flutter/shell/common/canvas_spy_unittests.cc
|
||||
../../../flutter/shell/common/context_options_unittests.cc
|
||||
../../../flutter/shell/common/dl_op_spy_unittests.cc
|
||||
../../../flutter/shell/common/engine_unittests.cc
|
||||
../../../flutter/shell/common/fixtures
|
||||
../../../flutter/shell/common/input_events_unittests.cc
|
||||
|
||||
@@ -2113,6 +2113,8 @@ ORIGIN: ../../../flutter/shell/common/display.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/common/display.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/common/display_manager.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/common/display_manager.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/common/dl_op_spy.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/common/dl_op_spy.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/common/engine.cc + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/common/engine.h + ../../../flutter/LICENSE
|
||||
ORIGIN: ../../../flutter/shell/common/pipeline.cc + ../../../flutter/LICENSE
|
||||
@@ -4701,6 +4703,8 @@ FILE: ../../../flutter/shell/common/display.cc
|
||||
FILE: ../../../flutter/shell/common/display.h
|
||||
FILE: ../../../flutter/shell/common/display_manager.cc
|
||||
FILE: ../../../flutter/shell/common/display_manager.h
|
||||
FILE: ../../../flutter/shell/common/dl_op_spy.cc
|
||||
FILE: ../../../flutter/shell/common/dl_op_spy.h
|
||||
FILE: ../../../flutter/shell/common/engine.cc
|
||||
FILE: ../../../flutter/shell/common/engine.h
|
||||
FILE: ../../../flutter/shell/common/pipeline.cc
|
||||
|
||||
@@ -9,8 +9,7 @@ namespace flutter {
|
||||
|
||||
/// A enum define the blend mode.
|
||||
/// Blends are operators that take in two colors (source, destination) and
|
||||
/// return a new color. Blends are operators that take in two colors (source,
|
||||
/// destination) and return a new color. Many of these operate the same on all 4
|
||||
/// return a new color. Many of these operate the same on all 4
|
||||
/// components: red, green, blue, alpha. For these, we just document what
|
||||
/// happens to one component, rather than naming each one separately. Different
|
||||
/// color types might have different representations for color components:
|
||||
|
||||
@@ -30,6 +30,18 @@ void DisplayListEmbedderViewSlice::render_into(DlCanvas* canvas) {
|
||||
canvas->DrawDisplayList(display_list_);
|
||||
}
|
||||
|
||||
void DisplayListEmbedderViewSlice::dispatch(DlOpReceiver& receiver) {
|
||||
display_list_->Dispatch(receiver);
|
||||
}
|
||||
|
||||
bool DisplayListEmbedderViewSlice::is_empty() {
|
||||
return display_list_->bounds().isEmpty();
|
||||
}
|
||||
|
||||
bool DisplayListEmbedderViewSlice::recording_ended() {
|
||||
return builder_ == nullptr;
|
||||
}
|
||||
|
||||
void ExternalViewEmbedder::SubmitFrame(GrDirectContext* context,
|
||||
std::unique_ptr<SurfaceFrame> frame) {
|
||||
frame->Submit();
|
||||
|
||||
@@ -352,6 +352,9 @@ class DisplayListEmbedderViewSlice : public EmbedderViewSlice {
|
||||
std::list<SkRect> searchNonOverlappingDrawnRects(
|
||||
const SkRect& query) const override;
|
||||
void render_into(DlCanvas* canvas) override;
|
||||
void dispatch(DlOpReceiver& receiver);
|
||||
bool is_empty();
|
||||
bool recording_ended();
|
||||
|
||||
private:
|
||||
std::unique_ptr<DisplayListBuilder> builder_;
|
||||
|
||||
@@ -77,6 +77,8 @@ source_set("common") {
|
||||
"display.h",
|
||||
"display_manager.cc",
|
||||
"display_manager.h",
|
||||
"dl_op_spy.cc",
|
||||
"dl_op_spy.h",
|
||||
"engine.cc",
|
||||
"engine.h",
|
||||
"pipeline.cc",
|
||||
@@ -287,6 +289,7 @@ if (enable_unittests) {
|
||||
"animator_unittests.cc",
|
||||
"canvas_spy_unittests.cc",
|
||||
"context_options_unittests.cc",
|
||||
"dl_op_spy_unittests.cc",
|
||||
"engine_unittests.cc",
|
||||
"input_events_unittests.cc",
|
||||
"persistent_cache_unittests.cc",
|
||||
|
||||
138
engine/src/flutter/shell/common/dl_op_spy.cc
Normal file
138
engine/src/flutter/shell/common/dl_op_spy.cc
Normal file
@@ -0,0 +1,138 @@
|
||||
// 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/shell/common/dl_op_spy.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
bool DlOpSpy::did_draw() {
|
||||
return did_draw_;
|
||||
}
|
||||
|
||||
void DlOpSpy::setColor(DlColor color) {
|
||||
if (color.isTransparent()) {
|
||||
will_draw_ = false;
|
||||
} else {
|
||||
will_draw_ = true;
|
||||
}
|
||||
}
|
||||
void DlOpSpy::setColorSource(const DlColorSource* source) {
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
const DlColorColorSource* color_source = source->asColor();
|
||||
if (color_source && color_source->color().isTransparent()) {
|
||||
will_draw_ = false;
|
||||
return;
|
||||
}
|
||||
will_draw_ = true;
|
||||
}
|
||||
void DlOpSpy::save() {}
|
||||
void DlOpSpy::saveLayer(const SkRect* bounds,
|
||||
const SaveLayerOptions options,
|
||||
const DlImageFilter* backdrop) {}
|
||||
void DlOpSpy::restore() {}
|
||||
void DlOpSpy::drawColor(DlColor color, DlBlendMode mode) {
|
||||
did_draw_ |= !color.isTransparent();
|
||||
}
|
||||
void DlOpSpy::drawPaint() {
|
||||
did_draw_ |= will_draw_;
|
||||
}
|
||||
// TODO(cyanglaz): check whether the shape (line, rect, oval, etc) needs to be
|
||||
// evaluated. https://github.com/flutter/flutter/issues/123803
|
||||
void DlOpSpy::drawLine(const SkPoint& p0, const SkPoint& p1) {
|
||||
did_draw_ |= will_draw_;
|
||||
}
|
||||
void DlOpSpy::drawRect(const SkRect& rect) {
|
||||
did_draw_ |= will_draw_;
|
||||
}
|
||||
void DlOpSpy::drawOval(const SkRect& bounds) {
|
||||
did_draw_ |= will_draw_;
|
||||
}
|
||||
void DlOpSpy::drawCircle(const SkPoint& center, SkScalar radius) {
|
||||
did_draw_ |= will_draw_;
|
||||
}
|
||||
void DlOpSpy::drawRRect(const SkRRect& rrect) {
|
||||
did_draw_ |= will_draw_;
|
||||
}
|
||||
void DlOpSpy::drawDRRect(const SkRRect& outer, const SkRRect& inner) {
|
||||
did_draw_ |= will_draw_;
|
||||
}
|
||||
void DlOpSpy::drawPath(const SkPath& path) {
|
||||
did_draw_ |= will_draw_;
|
||||
}
|
||||
void DlOpSpy::drawArc(const SkRect& oval_bounds,
|
||||
SkScalar start_degrees,
|
||||
SkScalar sweep_degrees,
|
||||
bool use_center) {
|
||||
did_draw_ |= will_draw_;
|
||||
}
|
||||
void DlOpSpy::drawPoints(PointMode mode,
|
||||
uint32_t count,
|
||||
const SkPoint points[]) {
|
||||
did_draw_ |= will_draw_;
|
||||
}
|
||||
void DlOpSpy::drawVertices(const DlVertices* vertices, DlBlendMode mode) {
|
||||
did_draw_ |= will_draw_;
|
||||
}
|
||||
// In theory, below drawImage methods can produce a transparent screen when a
|
||||
// transparent image is provided. The operation of determine whether an image is
|
||||
// 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,
|
||||
const SkPoint point,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes) {
|
||||
did_draw_ = true;
|
||||
}
|
||||
void DlOpSpy::drawImageRect(const sk_sp<DlImage> image,
|
||||
const SkRect& src,
|
||||
const SkRect& dst,
|
||||
DlImageSampling sampling,
|
||||
bool render_with_attributes,
|
||||
SrcRectConstraint constraint) {
|
||||
did_draw_ = true;
|
||||
}
|
||||
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,
|
||||
const SkRSXform xform[],
|
||||
const SkRect tex[],
|
||||
const DlColor colors[],
|
||||
int count,
|
||||
DlBlendMode mode,
|
||||
DlImageSampling sampling,
|
||||
const SkRect* cull_rect,
|
||||
bool render_with_attributes) {
|
||||
did_draw_ = true;
|
||||
}
|
||||
void DlOpSpy::drawDisplayList(const sk_sp<DisplayList> display_list,
|
||||
SkScalar opacity) {
|
||||
if (did_draw_ || opacity == 0) {
|
||||
return;
|
||||
}
|
||||
DlOpSpy receiver;
|
||||
display_list->Dispatch(receiver);
|
||||
did_draw_ |= receiver.did_draw();
|
||||
}
|
||||
void DlOpSpy::drawTextBlob(const sk_sp<SkTextBlob> blob,
|
||||
SkScalar x,
|
||||
SkScalar y) {
|
||||
did_draw_ |= will_draw_;
|
||||
}
|
||||
void DlOpSpy::drawShadow(const SkPath& path,
|
||||
const DlColor color,
|
||||
const SkScalar elevation,
|
||||
bool transparent_occluder,
|
||||
SkScalar dpr) {
|
||||
did_draw_ |= !color.isTransparent();
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
109
engine/src/flutter/shell/common/dl_op_spy.h
Normal file
109
engine/src/flutter/shell/common/dl_op_spy.h
Normal file
@@ -0,0 +1,109 @@
|
||||
// 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_SPY_H_
|
||||
#define FLUTTER_DISPLAY_LIST_DL_OP_SPY_H_
|
||||
|
||||
#include "flutter/display_list/dl_op_receiver.h"
|
||||
#include "flutter/display_list/utils/dl_receiver_utils.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Receives to drawing commands of a DisplayListBuilder.
|
||||
///
|
||||
/// This is used to determine whether any non-transparent pixels will be drawn
|
||||
/// on the canvas.
|
||||
/// All the drawImage operations are considered drawing non-transparent pixels.
|
||||
///
|
||||
/// To use this class, dispatch the operations from DisplayList to a concrete
|
||||
/// DlOpSpy object, and check the result of `did_draw` method.
|
||||
///
|
||||
/// ```
|
||||
/// DlOpSpy dl_op_spy;
|
||||
/// display_list.Dispatch(dl_op_spy);
|
||||
/// bool did_draw = dl_op_spy.did_draw()
|
||||
/// ```
|
||||
///
|
||||
class DlOpSpy final : public virtual DlOpReceiver,
|
||||
private IgnoreAttributeDispatchHelper,
|
||||
private IgnoreClipDispatchHelper,
|
||||
private IgnoreTransformDispatchHelper {
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/// @brief Returns true if any non transparent content has been drawn.
|
||||
bool did_draw();
|
||||
|
||||
private:
|
||||
void setColor(DlColor color) override;
|
||||
void setColorSource(const DlColorSource* source) override;
|
||||
void save() override;
|
||||
void saveLayer(const SkRect* bounds,
|
||||
const SaveLayerOptions options,
|
||||
const DlImageFilter* backdrop) override;
|
||||
void restore() override;
|
||||
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;
|
||||
|
||||
// Indicates if the attributes are set to values that will modify the
|
||||
// destination. For now, the test only checks if there is a non-transparent
|
||||
// color set.
|
||||
bool will_draw_ = true;
|
||||
|
||||
bool did_draw_ = false;
|
||||
};
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
#endif // FLUTTER_DISPLAY_LIST_DL_OP_SPY_H_
|
||||
524
engine/src/flutter/shell/common/dl_op_spy_unittests.cc
Normal file
524
engine/src/flutter/shell/common/dl_op_spy_unittests.cc
Normal file
@@ -0,0 +1,524 @@
|
||||
// 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.h"
|
||||
#include "flutter/display_list/dl_builder.h"
|
||||
#include "flutter/shell/common/dl_op_spy.h"
|
||||
#include "flutter/testing/testing.h"
|
||||
#include "third_party/skia/include/core/SkBitmap.h"
|
||||
|
||||
namespace flutter {
|
||||
namespace testing {
|
||||
|
||||
TEST(DlOpSpy, DidDrawIsFalseByDefault) {
|
||||
DlOpSpy dl_op_spy;
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, SetColor) {
|
||||
{ // No Color set.
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
builder.DrawRect(SkRect::MakeWH(5, 5), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // Set transparent color.
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
builder.DrawRect(SkRect::MakeWH(5, 5), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // Set black color.
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
builder.DrawRect(SkRect::MakeWH(5, 5), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, SetColorSource) {
|
||||
{ // Set null source
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
paint.setColorSource(nullptr);
|
||||
builder.DrawRect(SkRect::MakeWH(5, 5), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // Set transparent color.
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
auto color = DlColor::kTransparent();
|
||||
DlColorColorSource color_source_transparent(color);
|
||||
paint.setColorSource(color_source_transparent.shared());
|
||||
builder.DrawRect(SkRect::MakeWH(5, 5), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // Set black color.
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
auto color = DlColor::kBlack();
|
||||
DlColorColorSource color_source_transparent(color);
|
||||
paint.setColorSource(color_source_transparent.shared());
|
||||
builder.DrawRect(SkRect::MakeWH(5, 5), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, DrawColor) {
|
||||
{ // Black color source.
|
||||
DisplayListBuilder builder;
|
||||
auto color = DlColor::kBlack();
|
||||
builder.DrawColor(color, DlBlendMode::kSrc);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // Transparent color source.
|
||||
DisplayListBuilder builder;
|
||||
auto color = DlColor::kTransparent();
|
||||
builder.DrawColor(color, DlBlendMode::kSrc);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, DrawPaint) {
|
||||
{ // Transparent color in paint.
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
builder.DrawPaint(paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // black color in paint.
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
builder.DrawPaint(paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, DrawLine) {
|
||||
{ // black
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
builder.DrawLine(SkPoint::Make(0, 1), SkPoint::Make(1, 2), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // transparent
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
builder.DrawLine(SkPoint::Make(0, 1), SkPoint::Make(1, 2), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, DrawRect) {
|
||||
{ // black
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
builder.DrawRect(SkRect::MakeWH(5, 5), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // transparent
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
builder.DrawRect(SkRect::MakeWH(5, 5), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, drawOval) {
|
||||
{ // black
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
builder.DrawOval(SkRect::MakeWH(5, 5), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // transparent
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
builder.DrawOval(SkRect::MakeWH(5, 5), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, drawCircle) {
|
||||
{ // black
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
builder.DrawCircle(SkPoint::Make(5, 5), 1.0, paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // transparent
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
builder.DrawCircle(SkPoint::Make(5, 5), 1.0, paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, drawRRect) {
|
||||
{ // black
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
builder.DrawRRect(SkRRect::MakeRect(SkRect::MakeWH(5, 5)), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // transparent
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
builder.DrawRRect(SkRRect::MakeRect(SkRect::MakeWH(5, 5)), paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, drawPath) {
|
||||
{ // black
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
builder.DrawPath(SkPath::Line(SkPoint::Make(0, 1), SkPoint::Make(1, 1)),
|
||||
paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // transparent
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
builder.DrawPath(SkPath::Line(SkPoint::Make(0, 1), SkPoint::Make(1, 1)),
|
||||
paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, drawArc) {
|
||||
{ // black
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
builder.DrawArc(SkRect::MakeWH(5, 5), 0, 1, true, paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // transparent
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
builder.DrawArc(SkRect::MakeWH(5, 5), 0, 1, true, paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, drawPoints) {
|
||||
{ // black
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
const SkPoint points[] = {SkPoint::Make(5, 4)};
|
||||
builder.DrawPoints(DlCanvas::PointMode::kPoints, 1, points, paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // transparent
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
const SkPoint points[] = {SkPoint::Make(5, 4)};
|
||||
builder.DrawPoints(DlCanvas::PointMode::kPoints, 1, points, paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, drawVertices) {
|
||||
{ // black
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
const SkPoint vertices[] = {SkPoint::Make(5, 5)};
|
||||
const SkPoint texture_coordinates[] = {SkPoint::Make(5, 5)};
|
||||
const DlColor colors[] = {DlColor::kBlack()};
|
||||
auto dl_vertices = DlVertices::Make(DlVertexMode::kTriangles, 1, vertices,
|
||||
texture_coordinates, colors, 0);
|
||||
builder.DrawVertices(dl_vertices.get(), DlBlendMode::kSrc, paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // transparent
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
const SkPoint vertices[] = {SkPoint::Make(5, 5)};
|
||||
const SkPoint texture_coordinates[] = {SkPoint::Make(5, 5)};
|
||||
const DlColor colors[] = {DlColor::kBlack()};
|
||||
auto dl_vertices = DlVertices::Make(DlVertexMode::kTriangles, 1, vertices,
|
||||
texture_coordinates, colors, 0);
|
||||
builder.DrawVertices(dl_vertices.get(), DlBlendMode::kSrc, paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, Images) {
|
||||
{ // DrawImage
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
SkImageInfo info =
|
||||
SkImageInfo::Make(50, 50, SkColorType::kRGBA_8888_SkColorType,
|
||||
SkAlphaType::kPremul_SkAlphaType);
|
||||
SkBitmap bitmap;
|
||||
bitmap.allocPixels(info, 0);
|
||||
auto sk_image = SkImage::MakeFromBitmap(bitmap);
|
||||
builder.DrawImage(DlImage::Make(sk_image), SkPoint::Make(5, 5),
|
||||
DlImageSampling::kLinear);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // DrawImageRect
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
SkImageInfo info =
|
||||
SkImageInfo::Make(50, 50, SkColorType::kRGBA_8888_SkColorType,
|
||||
SkAlphaType::kPremul_SkAlphaType);
|
||||
SkBitmap bitmap;
|
||||
bitmap.allocPixels(info, 0);
|
||||
auto sk_image = SkImage::MakeFromBitmap(bitmap);
|
||||
builder.DrawImageRect(DlImage::Make(sk_image), SkRect::MakeWH(5, 5),
|
||||
SkRect::MakeWH(5, 5), DlImageSampling::kLinear);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // DrawImageNine
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
SkImageInfo info =
|
||||
SkImageInfo::Make(50, 50, SkColorType::kRGBA_8888_SkColorType,
|
||||
SkAlphaType::kPremul_SkAlphaType);
|
||||
SkBitmap bitmap;
|
||||
bitmap.allocPixels(info, 0);
|
||||
auto sk_image = SkImage::MakeFromBitmap(bitmap);
|
||||
builder.DrawImageNine(DlImage::Make(sk_image), SkIRect::MakeWH(5, 5),
|
||||
SkRect::MakeWH(5, 5), DlFilterMode::kLinear);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // DrawAtlas
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
SkImageInfo info =
|
||||
SkImageInfo::Make(50, 50, SkColorType::kRGBA_8888_SkColorType,
|
||||
SkAlphaType::kPremul_SkAlphaType);
|
||||
SkBitmap bitmap;
|
||||
bitmap.allocPixels(info, 0);
|
||||
auto sk_image = SkImage::MakeFromBitmap(bitmap);
|
||||
const SkRSXform xform[] = {};
|
||||
const SkRect tex[] = {};
|
||||
const DlColor colors[] = {};
|
||||
SkRect cull_rect = SkRect::MakeWH(5, 5);
|
||||
builder.DrawAtlas(DlImage::Make(sk_image), xform, tex, colors, 0,
|
||||
DlBlendMode::kSrc, DlImageSampling::kLinear, &cull_rect);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, drawDisplayList) {
|
||||
{ // Recursive Transparent DisplayList
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
builder.DrawPaint(paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
|
||||
DisplayListBuilder builder_parent;
|
||||
DlPaint paint_parent(DlColor::kTransparent());
|
||||
builder_parent.DrawPaint(paint_parent);
|
||||
builder_parent.DrawDisplayList(dl, 1);
|
||||
sk_sp<DisplayList> dl2 = builder_parent.Build();
|
||||
|
||||
DlOpSpy dl_op_spy;
|
||||
dl2->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // Sub non-transparent DisplayList,
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
builder.DrawPaint(paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
|
||||
DisplayListBuilder builder_parent;
|
||||
DlPaint paint_parent(DlColor::kTransparent());
|
||||
builder_parent.DrawPaint(paint_parent);
|
||||
builder_parent.DrawDisplayList(dl, 1);
|
||||
sk_sp<DisplayList> dl2 = builder_parent.Build();
|
||||
|
||||
DlOpSpy dl_op_spy;
|
||||
dl2->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
|
||||
{ // Sub non-transparent DisplayList, 0 opacity
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
builder.DrawPaint(paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
|
||||
DisplayListBuilder builder_parent;
|
||||
DlPaint paint_parent(DlColor::kTransparent());
|
||||
builder_parent.DrawPaint(paint_parent);
|
||||
builder_parent.DrawDisplayList(dl, 0);
|
||||
sk_sp<DisplayList> dl2 = builder_parent.Build();
|
||||
|
||||
DlOpSpy dl_op_spy;
|
||||
dl2->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
|
||||
{ // Parent non-transparent DisplayList
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
builder.DrawPaint(paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
|
||||
DisplayListBuilder builder_parent;
|
||||
DlPaint paint_parent(DlColor::kBlack());
|
||||
builder_parent.DrawPaint(paint_parent);
|
||||
builder_parent.DrawDisplayList(dl, 0);
|
||||
sk_sp<DisplayList> dl2 = builder_parent.Build();
|
||||
|
||||
DlOpSpy dl_op_spy;
|
||||
dl2->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, drawTextBlob) {
|
||||
{ // Non-transparent color.
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kBlack());
|
||||
std::string string = "xx";
|
||||
SkFont font;
|
||||
auto text_blob = SkTextBlob::MakeFromString(string.c_str(), font);
|
||||
builder.DrawTextBlob(text_blob, 1, 1, paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // transparent color.
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint(DlColor::kTransparent());
|
||||
std::string string = "xx";
|
||||
SkFont font;
|
||||
auto text_blob = SkTextBlob::MakeFromString(string.c_str(), font);
|
||||
builder.DrawTextBlob(text_blob, 1, 1, paint);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DlOpSpy, drawShadow) {
|
||||
{ // valid shadow
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
DlColor color = DlColor::kBlack();
|
||||
SkPath path = SkPath::Line(SkPoint::Make(0, 1), SkPoint::Make(1, 1));
|
||||
builder.DrawShadow(path, color, 1, false, 1);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_TRUE(dl_op_spy.did_draw());
|
||||
}
|
||||
{ // transparent color
|
||||
DisplayListBuilder builder;
|
||||
DlPaint paint;
|
||||
DlColor color = DlColor::kTransparent();
|
||||
SkPath path = SkPath::Line(SkPoint::Make(0, 1), SkPoint::Make(1, 1));
|
||||
builder.DrawShadow(path, color, 1, false, 1);
|
||||
sk_sp<DisplayList> dl = builder.Build();
|
||||
DlOpSpy dl_op_spy;
|
||||
dl->Dispatch(dl_op_spy);
|
||||
ASSERT_FALSE(dl_op_spy.did_draw());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
} // namespace flutter
|
||||
@@ -198,6 +198,7 @@ test_fixtures("fixtures") {
|
||||
"fixtures/compositor_software.png",
|
||||
"fixtures/compositor_with_platform_layer_on_bottom.png",
|
||||
"fixtures/compositor_with_root_layer_only.png",
|
||||
"fixtures/compositor_platform_layer_with_no_overlay.png",
|
||||
"fixtures/dpr_noxform.png",
|
||||
"fixtures/dpr_xform.png",
|
||||
"fixtures/gradient.png",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include "flutter/shell/platform/embedder/embedder_external_view.h"
|
||||
#include "flutter/fml/trace_event.h"
|
||||
#include "flutter/shell/common/canvas_spy.h"
|
||||
#include "flutter/shell/common/dl_op_spy.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
@@ -30,10 +30,8 @@ EmbedderExternalView::EmbedderExternalView(
|
||||
surface_transformation_(surface_transformation),
|
||||
view_identifier_(view_identifier),
|
||||
embedded_view_params_(std::move(params)),
|
||||
recorder_(std::make_unique<SkPictureRecorder>()),
|
||||
canvas_spy_(std::make_unique<CanvasSpy>(
|
||||
recorder_->beginRecording(frame_size.width(), frame_size.height()))) {
|
||||
}
|
||||
slice_(std::make_unique<DisplayListEmbedderViewSlice>(
|
||||
SkRect::Make(frame_size))) {}
|
||||
|
||||
EmbedderExternalView::~EmbedderExternalView() = default;
|
||||
|
||||
@@ -43,7 +41,7 @@ EmbedderExternalView::CreateRenderTargetDescriptor() const {
|
||||
}
|
||||
|
||||
DlCanvas* EmbedderExternalView::GetCanvas() {
|
||||
return canvas_spy_->GetSpyingCanvas();
|
||||
return slice_->canvas();
|
||||
}
|
||||
|
||||
SkISize EmbedderExternalView::GetRenderSurfaceSize() const {
|
||||
@@ -58,8 +56,15 @@ bool EmbedderExternalView::HasPlatformView() const {
|
||||
return view_identifier_.platform_view_id.has_value();
|
||||
}
|
||||
|
||||
bool EmbedderExternalView::HasEngineRenderedContents() const {
|
||||
return canvas_spy_->DidDrawIntoCanvas();
|
||||
bool EmbedderExternalView::HasEngineRenderedContents() {
|
||||
if (has_engine_rendered_contents_.has_value()) {
|
||||
return has_engine_rendered_contents_.value();
|
||||
}
|
||||
TryEndRecording();
|
||||
DlOpSpy dl_op_spy;
|
||||
slice_->dispatch(dl_op_spy);
|
||||
has_engine_rendered_contents_ = dl_op_spy.did_draw() && !slice_->is_empty();
|
||||
return has_engine_rendered_contents_.value();
|
||||
}
|
||||
|
||||
EmbedderExternalView::ViewIdentifier EmbedderExternalView::GetViewIdentifier()
|
||||
@@ -73,16 +78,11 @@ const EmbeddedViewParams* EmbedderExternalView::GetEmbeddedViewParams() const {
|
||||
|
||||
bool EmbedderExternalView::Render(const EmbedderRenderTarget& render_target) {
|
||||
TRACE_EVENT0("flutter", "EmbedderExternalView::Render");
|
||||
|
||||
TryEndRecording();
|
||||
FML_DCHECK(HasEngineRenderedContents())
|
||||
<< "Unnecessarily asked to render into a render target when there was "
|
||||
"nothing to render.";
|
||||
|
||||
auto picture = recorder_->finishRecordingAsPicture();
|
||||
if (!picture) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto surface = render_target.GetRenderSurface();
|
||||
if (!surface) {
|
||||
return false;
|
||||
@@ -95,13 +95,22 @@ bool EmbedderExternalView::Render(const EmbedderRenderTarget& render_target) {
|
||||
if (!canvas) {
|
||||
return false;
|
||||
}
|
||||
|
||||
canvas->setMatrix(surface_transformation_);
|
||||
canvas->clear(SK_ColorTRANSPARENT);
|
||||
canvas->drawPicture(picture);
|
||||
canvas->flush();
|
||||
DlSkCanvasAdapter dl_canvas(canvas);
|
||||
int restore_count = dl_canvas.GetSaveCount();
|
||||
dl_canvas.SetTransform(surface_transformation_);
|
||||
dl_canvas.Clear(DlColor::kTransparent());
|
||||
slice_->render_into(&dl_canvas);
|
||||
dl_canvas.RestoreToCount(restore_count);
|
||||
dl_canvas.Flush();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EmbedderExternalView::TryEndRecording() const {
|
||||
if (slice_->recording_ended()) {
|
||||
return;
|
||||
}
|
||||
slice_->end_recording();
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
#include "flutter/flow/embedded_views.h"
|
||||
#include "flutter/fml/hash_combine.h"
|
||||
#include "flutter/fml/macros.h"
|
||||
#include "flutter/shell/common/canvas_spy.h"
|
||||
#include "flutter/shell/platform/embedder/embedder_render_target.h"
|
||||
#include "third_party/skia/include/core/SkPictureRecorder.h"
|
||||
|
||||
namespace flutter {
|
||||
|
||||
@@ -97,7 +95,7 @@ class EmbedderExternalView {
|
||||
|
||||
bool HasPlatformView() const;
|
||||
|
||||
bool HasEngineRenderedContents() const;
|
||||
bool HasEngineRenderedContents();
|
||||
|
||||
ViewIdentifier GetViewIdentifier() const;
|
||||
|
||||
@@ -112,12 +110,16 @@ class EmbedderExternalView {
|
||||
bool Render(const EmbedderRenderTarget& render_target);
|
||||
|
||||
private:
|
||||
// End the recording of the slice.
|
||||
// Noop if the slice's recording has already ended.
|
||||
void TryEndRecording() const;
|
||||
|
||||
const SkISize render_surface_size_;
|
||||
const SkMatrix surface_transformation_;
|
||||
ViewIdentifier view_identifier_;
|
||||
std::unique_ptr<EmbeddedViewParams> embedded_view_params_;
|
||||
std::unique_ptr<SkPictureRecorder> recorder_;
|
||||
std::unique_ptr<CanvasSpy> canvas_spy_;
|
||||
std::unique_ptr<DisplayListEmbedderViewSlice> slice_;
|
||||
std::optional<bool> has_engine_rendered_contents_;
|
||||
|
||||
FML_DISALLOW_COPY_AND_ASSIGN(EmbedderExternalView);
|
||||
};
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.3 KiB |
@@ -455,6 +455,73 @@ void can_composite_platform_views_with_known_scene() {
|
||||
PlatformDispatcher.instance.scheduleFrame();
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
void can_composite_platform_views_transparent_overlay() {
|
||||
PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
|
||||
Color red = Color.fromARGB(127, 255, 0, 0);
|
||||
Color blue = Color.fromARGB(127, 0, 0, 255);
|
||||
Color transparent = Color(0xFFFFFF);
|
||||
|
||||
Size size = Size(50.0, 150.0);
|
||||
|
||||
SceneBuilder builder = SceneBuilder();
|
||||
builder.pushOffset(0.0, 0.0);
|
||||
|
||||
// 10 (Index 0)
|
||||
builder.addPicture(
|
||||
Offset(10.0, 10.0), CreateColoredBox(red, size)); // red - flutter
|
||||
|
||||
builder.pushOffset(20.0, 20.0);
|
||||
// 20 (Index 1)
|
||||
builder.addPlatformView(1,
|
||||
width: size.width, height: size.height); // green - platform
|
||||
builder.pop();
|
||||
|
||||
// 30 (Index 2)
|
||||
builder.addPicture(
|
||||
Offset(30.0, 30.0), CreateColoredBox(transparent, size)); // transparent picture, no layer should be created.
|
||||
|
||||
builder.pop();
|
||||
|
||||
PlatformDispatcher.instance.views.first.render(builder.build());
|
||||
|
||||
signalNativeTest(); // Signal 2
|
||||
};
|
||||
signalNativeTest(); // Signal 1
|
||||
PlatformDispatcher.instance.scheduleFrame();
|
||||
}
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
void can_composite_platform_views_no_overlay() {
|
||||
PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
|
||||
Color red = Color.fromARGB(127, 255, 0, 0);
|
||||
Color blue = Color.fromARGB(127, 0, 0, 255);
|
||||
|
||||
Size size = Size(50.0, 150.0);
|
||||
|
||||
SceneBuilder builder = SceneBuilder();
|
||||
builder.pushOffset(0.0, 0.0);
|
||||
|
||||
// 10 (Index 0)
|
||||
builder.addPicture(
|
||||
Offset(10.0, 10.0), CreateColoredBox(red, size)); // red - flutter
|
||||
|
||||
builder.pushOffset(20.0, 20.0);
|
||||
// 20 (Index 1)
|
||||
builder.addPlatformView(1,
|
||||
width: size.width, height: size.height); // green - platform
|
||||
builder.pop();
|
||||
builder.pop();
|
||||
|
||||
PlatformDispatcher.instance.views.first.render(builder.build());
|
||||
|
||||
signalNativeTest(); // Signal 2
|
||||
};
|
||||
signalNativeTest(); // Signal 1
|
||||
PlatformDispatcher.instance.scheduleFrame();
|
||||
}
|
||||
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
void can_composite_platform_views_with_root_layer_only() {
|
||||
PlatformDispatcher.instance.onBeginFrame = (Duration duration) {
|
||||
|
||||
@@ -817,6 +817,250 @@ TEST_F(EmbedderTest,
|
||||
ASSERT_EQ(context.GetSurfacePresentCount(), 0u);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Test the layer structure and pixels rendered when using a custom software
|
||||
/// compositor, with a transparent overlay
|
||||
///
|
||||
TEST_F(EmbedderTest, NoLayerCreatedForTransparentOverlayOnTopOfPlatformLayer) {
|
||||
auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
|
||||
|
||||
EmbedderConfigBuilder builder(context);
|
||||
builder.SetSoftwareRendererConfig(SkISize::Make(800, 600));
|
||||
builder.SetCompositor();
|
||||
builder.SetDartEntrypoint("can_composite_platform_views_transparent_overlay");
|
||||
|
||||
builder.SetRenderTargetType(
|
||||
EmbedderTestBackingStoreProducer::RenderTargetType::kSoftwareBuffer);
|
||||
|
||||
fml::CountDownLatch latch(4);
|
||||
|
||||
auto scene_image = context.GetNextSceneImage();
|
||||
|
||||
context.GetCompositor().SetNextPresentCallback(
|
||||
[&](const FlutterLayer** layers, size_t layers_count) {
|
||||
ASSERT_EQ(layers_count, 2u);
|
||||
|
||||
// Layer Root
|
||||
{
|
||||
FlutterBackingStore backing_store = *layers[0]->backing_store;
|
||||
backing_store.type = kFlutterBackingStoreTypeSoftware;
|
||||
backing_store.did_update = true;
|
||||
backing_store.software.height = 600;
|
||||
|
||||
FlutterLayer layer = {};
|
||||
layer.struct_size = sizeof(layer);
|
||||
layer.type = kFlutterLayerContentTypeBackingStore;
|
||||
layer.backing_store = &backing_store;
|
||||
layer.size = FlutterSizeMake(800.0, 600.0);
|
||||
layer.offset = FlutterPointMake(0.0, 0.0);
|
||||
|
||||
ASSERT_EQ(*layers[0], layer);
|
||||
}
|
||||
|
||||
// Layer 1
|
||||
{
|
||||
FlutterPlatformView platform_view = *layers[1]->platform_view;
|
||||
platform_view.struct_size = sizeof(platform_view);
|
||||
platform_view.identifier = 1;
|
||||
|
||||
FlutterLayer layer = {};
|
||||
layer.struct_size = sizeof(layer);
|
||||
layer.type = kFlutterLayerContentTypePlatformView;
|
||||
layer.platform_view = &platform_view;
|
||||
layer.size = FlutterSizeMake(50.0, 150.0);
|
||||
layer.offset = FlutterPointMake(20.0, 20.0);
|
||||
|
||||
ASSERT_EQ(*layers[1], layer);
|
||||
}
|
||||
|
||||
latch.CountDown();
|
||||
});
|
||||
|
||||
context.GetCompositor().SetPlatformViewRendererCallback(
|
||||
[&](const FlutterLayer& layer, GrDirectContext*
|
||||
/* don't use because software compositor */) -> sk_sp<SkImage> {
|
||||
auto surface = CreateRenderSurface(
|
||||
layer, nullptr /* null because software compositor */);
|
||||
auto canvas = surface->getCanvas();
|
||||
FML_CHECK(canvas != nullptr);
|
||||
|
||||
switch (layer.platform_view->identifier) {
|
||||
case 1: {
|
||||
SkPaint paint;
|
||||
// See dart test for total order.
|
||||
paint.setColor(SK_ColorGREEN);
|
||||
paint.setAlpha(127);
|
||||
const auto& rect =
|
||||
SkRect::MakeWH(layer.size.width, layer.size.height);
|
||||
canvas->drawRect(rect, paint);
|
||||
latch.CountDown();
|
||||
} break;
|
||||
default:
|
||||
// Asked to render an unknown platform view.
|
||||
FML_CHECK(false)
|
||||
<< "Test was asked to composite an unknown platform view.";
|
||||
}
|
||||
|
||||
return surface->makeImageSnapshot();
|
||||
});
|
||||
|
||||
context.AddNativeCallback(
|
||||
"SignalNativeTest",
|
||||
CREATE_NATIVE_ENTRY(
|
||||
[&latch](Dart_NativeArguments args) { latch.CountDown(); }));
|
||||
|
||||
auto engine = builder.LaunchEngine();
|
||||
|
||||
// Send a window metrics events so frames may be scheduled.
|
||||
FlutterWindowMetricsEvent event = {};
|
||||
event.struct_size = sizeof(event);
|
||||
event.width = 800;
|
||||
event.height = 600;
|
||||
event.pixel_ratio = 1.0;
|
||||
event.physical_view_inset_top = 0.0;
|
||||
event.physical_view_inset_right = 0.0;
|
||||
event.physical_view_inset_bottom = 0.0;
|
||||
event.physical_view_inset_left = 0.0;
|
||||
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
|
||||
kSuccess);
|
||||
ASSERT_TRUE(engine.is_valid());
|
||||
|
||||
latch.Wait();
|
||||
|
||||
// TODO(https://github.com/flutter/flutter/issues/53784): enable this on all
|
||||
// platforms.
|
||||
#if !defined(FML_OS_LINUX)
|
||||
GTEST_SKIP() << "Skipping golden tests on non-Linux OSes";
|
||||
#endif // FML_OS_LINUX
|
||||
ASSERT_TRUE(ImageMatchesFixture(
|
||||
"compositor_platform_layer_with_no_overlay.png", scene_image));
|
||||
|
||||
// There should no present calls on the root surface.
|
||||
ASSERT_EQ(context.GetSurfacePresentCount(), 0u);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Test the layer structure and pixels rendered when using a custom software
|
||||
/// compositor, with a no overlay
|
||||
///
|
||||
TEST_F(EmbedderTest, NoLayerCreatedForNoOverlayOnTopOfPlatformLayer) {
|
||||
auto& context = GetEmbedderContext(EmbedderTestContextType::kSoftwareContext);
|
||||
|
||||
EmbedderConfigBuilder builder(context);
|
||||
builder.SetSoftwareRendererConfig(SkISize::Make(800, 600));
|
||||
builder.SetCompositor();
|
||||
builder.SetDartEntrypoint("can_composite_platform_views_no_overlay");
|
||||
|
||||
builder.SetRenderTargetType(
|
||||
EmbedderTestBackingStoreProducer::RenderTargetType::kSoftwareBuffer);
|
||||
|
||||
fml::CountDownLatch latch(4);
|
||||
|
||||
auto scene_image = context.GetNextSceneImage();
|
||||
|
||||
context.GetCompositor().SetNextPresentCallback(
|
||||
[&](const FlutterLayer** layers, size_t layers_count) {
|
||||
ASSERT_EQ(layers_count, 2u);
|
||||
|
||||
// Layer Root
|
||||
{
|
||||
FlutterBackingStore backing_store = *layers[0]->backing_store;
|
||||
backing_store.type = kFlutterBackingStoreTypeSoftware;
|
||||
backing_store.did_update = true;
|
||||
backing_store.software.height = 600;
|
||||
|
||||
FlutterLayer layer = {};
|
||||
layer.struct_size = sizeof(layer);
|
||||
layer.type = kFlutterLayerContentTypeBackingStore;
|
||||
layer.backing_store = &backing_store;
|
||||
layer.size = FlutterSizeMake(800.0, 600.0);
|
||||
layer.offset = FlutterPointMake(0.0, 0.0);
|
||||
|
||||
ASSERT_EQ(*layers[0], layer);
|
||||
}
|
||||
|
||||
// Layer 1
|
||||
{
|
||||
FlutterPlatformView platform_view = *layers[1]->platform_view;
|
||||
platform_view.struct_size = sizeof(platform_view);
|
||||
platform_view.identifier = 1;
|
||||
|
||||
FlutterLayer layer = {};
|
||||
layer.struct_size = sizeof(layer);
|
||||
layer.type = kFlutterLayerContentTypePlatformView;
|
||||
layer.platform_view = &platform_view;
|
||||
layer.size = FlutterSizeMake(50.0, 150.0);
|
||||
layer.offset = FlutterPointMake(20.0, 20.0);
|
||||
|
||||
ASSERT_EQ(*layers[1], layer);
|
||||
}
|
||||
|
||||
latch.CountDown();
|
||||
});
|
||||
|
||||
context.GetCompositor().SetPlatformViewRendererCallback(
|
||||
[&](const FlutterLayer& layer, GrDirectContext*
|
||||
/* don't use because software compositor */) -> sk_sp<SkImage> {
|
||||
auto surface = CreateRenderSurface(
|
||||
layer, nullptr /* null because software compositor */);
|
||||
auto canvas = surface->getCanvas();
|
||||
FML_CHECK(canvas != nullptr);
|
||||
|
||||
switch (layer.platform_view->identifier) {
|
||||
case 1: {
|
||||
SkPaint paint;
|
||||
// See dart test for total order.
|
||||
paint.setColor(SK_ColorGREEN);
|
||||
paint.setAlpha(127);
|
||||
const auto& rect =
|
||||
SkRect::MakeWH(layer.size.width, layer.size.height);
|
||||
canvas->drawRect(rect, paint);
|
||||
latch.CountDown();
|
||||
} break;
|
||||
default:
|
||||
// Asked to render an unknown platform view.
|
||||
FML_CHECK(false)
|
||||
<< "Test was asked to composite an unknown platform view.";
|
||||
}
|
||||
|
||||
return surface->makeImageSnapshot();
|
||||
});
|
||||
|
||||
context.AddNativeCallback(
|
||||
"SignalNativeTest",
|
||||
CREATE_NATIVE_ENTRY(
|
||||
[&latch](Dart_NativeArguments args) { latch.CountDown(); }));
|
||||
|
||||
auto engine = builder.LaunchEngine();
|
||||
|
||||
// Send a window metrics events so frames may be scheduled.
|
||||
FlutterWindowMetricsEvent event = {};
|
||||
event.struct_size = sizeof(event);
|
||||
event.width = 800;
|
||||
event.height = 600;
|
||||
event.pixel_ratio = 1.0;
|
||||
event.physical_view_inset_top = 0.0;
|
||||
event.physical_view_inset_right = 0.0;
|
||||
event.physical_view_inset_bottom = 0.0;
|
||||
event.physical_view_inset_left = 0.0;
|
||||
ASSERT_EQ(FlutterEngineSendWindowMetricsEvent(engine.get(), &event),
|
||||
kSuccess);
|
||||
ASSERT_TRUE(engine.is_valid());
|
||||
|
||||
latch.Wait();
|
||||
|
||||
// TODO(https://github.com/flutter/flutter/issues/53784): enable this on all
|
||||
// platforms.
|
||||
#if !defined(FML_OS_LINUX)
|
||||
GTEST_SKIP() << "Skipping golden tests on non-Linux OSes";
|
||||
#endif // FML_OS_LINUX
|
||||
ASSERT_TRUE(ImageMatchesFixture(
|
||||
"compositor_platform_layer_with_no_overlay.png", scene_image));
|
||||
|
||||
// There should no present calls on the root surface.
|
||||
ASSERT_EQ(context.GetSurfacePresentCount(), 0u);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
/// Test that an engine can be initialized but not run.
|
||||
///
|
||||
|
||||
@@ -164,6 +164,8 @@ class FlatlandExternalViewEmbedder final
|
||||
|
||||
std::optional<flutter::EmbeddedViewParams> embedded_view_params;
|
||||
std::unique_ptr<SkPictureRecorder> recorder;
|
||||
// TODO(cyanglaz: use DlOpSpy instead.
|
||||
// https://github.com/flutter/flutter/issues/123805
|
||||
std::unique_ptr<flutter::CanvasSpy> canvas_spy;
|
||||
SkISize surface_size;
|
||||
sk_sp<SkPicture> picture;
|
||||
|
||||
@@ -156,6 +156,8 @@ class GfxExternalViewEmbedder final : public flutter::ExternalViewEmbedder {
|
||||
|
||||
std::optional<flutter::EmbeddedViewParams> embedded_view_params;
|
||||
std::unique_ptr<SkPictureRecorder> recorder;
|
||||
// TODO(cyanglaz: use DlOpSpy instead.
|
||||
// https://github.com/flutter/flutter/issues/123805
|
||||
std::unique_ptr<flutter::CanvasSpy> canvas_spy;
|
||||
SkISize surface_size;
|
||||
sk_sp<SkPicture> picture;
|
||||
|
||||
Reference in New Issue
Block a user