未验证 提交 0b158a6b 编写于 作者: A amirh 提交者: GitHub

Engine support for arbitrary shape physical layers (#4488)

* Adjust PhysicalModelLayer to use an abstract shape, and provide concrete RRect and Path shape implementations

* add a pushPhysicalShape to scene_builder and compositing.dart
上级 e7a29477
......@@ -115,7 +115,23 @@ void DefaultLayerBuilder::PushPhysicalModel(const SkRRect& sk_rrect,
cullRect = SkRect::MakeEmpty();
}
auto layer = std::make_unique<flow::PhysicalModelLayer>();
layer->set_rrect(sk_rrect);
layer->set_shape(std::make_unique<PhysicalLayerRRect>(sk_rrect));
layer->set_elevation(elevation);
layer->set_color(color);
layer->set_device_pixel_ratio(device_pixel_ratio);
PushLayer(std::move(layer), cullRect);
}
void DefaultLayerBuilder::PushPhysicalModel(const SkPath& sk_path,
double elevation,
SkColor color,
SkScalar device_pixel_ratio) {
SkRect cullRect;
if (!cullRect.intersect(sk_path.getBounds(), cull_rects_.top())) {
cullRect = SkRect::MakeEmpty();
}
auto layer = std::make_unique<flow::PhysicalModelLayer>();
layer->set_shape(std::make_unique<PhysicalLayerPath>(sk_path));
layer->set_elevation(elevation);
layer->set_color(color);
layer->set_device_pixel_ratio(device_pixel_ratio);
......
......@@ -52,6 +52,12 @@ class DefaultLayerBuilder final : public LayerBuilder {
SkColor color,
SkScalar device_pixel_ratio) override;
// |flow::LayerBuilder|
void PushPhysicalModel(const SkPath& path,
double elevation,
SkColor color,
SkScalar device_pixel_ratio) override;
// |flow::LayerBuilder|
void PushPerformanceOverlay(uint64_t enabled_options,
const SkRect& rect) override;
......
......@@ -52,6 +52,11 @@ class LayerBuilder {
SkColor color,
SkScalar device_pixel_ratio) = 0;
virtual void PushPhysicalModel(const SkPath& path,
double elevation,
SkColor color,
SkScalar device_pixel_ratio) = 0;
virtual void PushPerformanceOverlay(uint64_t enabled_options,
const SkRect& rect) = 0;
......
......@@ -19,7 +19,7 @@ void PhysicalModelLayer::Preroll(PrerollContext* context,
PrerollChildren(context, matrix, &child_paint_bounds);
if (elevation_ == 0) {
set_paint_bounds(rrect_.getBounds());
set_paint_bounds(shape_->getBounds());
} else {
#if defined(OS_FUCHSIA)
// Let the system compositor draw all shadows for us.
......@@ -29,7 +29,7 @@ void PhysicalModelLayer::Preroll(PrerollContext* context,
// The margin is hardcoded to an arbitrary maximum for now because Skia
// doesn't provide a way to calculate it. We fill this whole region
// and clip children to it so we don't need to join the child paint bounds.
SkRect bounds(rrect_.getBounds());
SkRect bounds(shape_->getBounds());
bounds.outset(20.0, 20.0);
set_paint_bounds(bounds);
#endif // defined(OS_FUCHSIA)
......@@ -57,8 +57,7 @@ void PhysicalModelLayer::Paint(PaintContext& context) const {
TRACE_EVENT0("flutter", "PhysicalModelLayer::Paint");
FXL_DCHECK(needs_painting());
SkPath path;
path.addRRect(rrect_);
SkPath path = shape_->getPath();
if (elevation_ != 0) {
DrawShadow(&context.canvas, path, SK_ColorBLACK, elevation_,
......@@ -70,15 +69,15 @@ void PhysicalModelLayer::Paint(PaintContext& context) const {
context.canvas.drawPath(path, paint);
SkAutoCanvasRestore save(&context.canvas, false);
if (rrect_.isRect()) {
if (shape_->isRect()) {
context.canvas.save();
} else {
context.canvas.saveLayer(&rrect_.getBounds(), nullptr);
context.canvas.saveLayer(&shape_->getBounds(), nullptr);
}
context.canvas.clipRRect(rrect_, true);
shape_->clipCanvas(context.canvas);
PaintChildren(context);
if (context.checkerboard_offscreen_layers && !rrect_.isRect())
DrawCheckerboard(&context.canvas, rrect_.getBounds());
if (context.checkerboard_offscreen_layers && !shape_->isRect())
DrawCheckerboard(&context.canvas, shape_->getBounds());
}
void PhysicalModelLayer::DrawShadow(SkCanvas* canvas,
......@@ -98,4 +97,10 @@ void PhysicalModelLayer::DrawShadow(SkCanvas* canvas,
dpr * 800.0f, 0.039f, 0.25f, color, flags);
}
const SkPath PhysicalLayerRRect::getPath() const {
SkPath path;
path.addRRect(rrect_);
return path;
}
} // namespace flow
......@@ -9,12 +9,16 @@
namespace flow {
class PhysicalLayerShape;
class PhysicalModelLayer : public ContainerLayer {
public:
PhysicalModelLayer();
~PhysicalModelLayer() override;
void set_rrect(const SkRRect& rrect) { rrect_ = rrect; }
void set_shape(std::unique_ptr<PhysicalLayerShape> shape) {
shape_ = std::move(shape);
}
void set_elevation(float elevation) { elevation_ = elevation; }
void set_color(SkColor color) { color_ = color; }
void set_device_pixel_ratio(SkScalar dpr) { device_pixel_ratio_ = dpr; }
......@@ -35,12 +39,92 @@ class PhysicalModelLayer : public ContainerLayer {
#endif // defined(OS_FUCHSIA)
private:
SkRRect rrect_;
std::unique_ptr<PhysicalLayerShape> shape_;
float elevation_;
SkColor color_;
SkScalar device_pixel_ratio_;
};
// Common interface for the shape operations needed by PhysicalModelLayer.
//
// Once Scenic supports specifying physical layers with paths we can get rid
// of this class and the subclasses, and have a single implementation of
// PhysicalModelLayer that holds an SkPath.
// TODO(amirh): remove this once Scenic supports arbitrary shaped layers.
class PhysicalLayerShape {
public:
virtual const SkRect& getBounds() const = 0;
virtual SkPath getPath() const = 0;
virtual void clipCanvas(SkCanvas& canvas) const = 0;
virtual bool isRect() const = 0;
#if defined(OS_FUCHSIA)
virtual const SkRRect& getFrameRRect() const = 0;
#endif // defined(OS_FUCHSIA)
};
class PhysicalLayerRRect final : public PhysicalLayerShape {
public:
PhysicalLayerRRect(const SkRRect& rrect) { rrect_ = rrect; }
// |flow::PhysicalLayerShape|
const SkRect& getBounds() const override { return rrect_.getBounds(); }
// |flow::PhysicalLayerShape|
SkPath getPath() const override;
// |flow::PhysicalLayerShape|
void clipCanvas(SkCanvas& canvas) const override {
canvas.clipRRect(rrect_, true);
}
// |flow::PhysicalLayerShape|
bool isRect() const override { return rrect_.isRect(); }
#if defined(OS_FUCHSIA)
// |flow::PhysicalLayerShape|
const SkRRect& getFrameRRect() const override { return rrect_; }
#endif // defined(OS_FUCHSIA)
private:
SkRRect rrect_;
};
class PhysicalLayerPath final : public PhysicalLayerShape {
public:
PhysicalLayerPath(const SkPath& path) {
path_ = path;
#if defined(OS_FUCHSIA)
frameRRect_ = SkRRect::MakeRect(path.getBounds());
#endif // defined(OS_FUCHSIA)
}
// |flow::PhysicalLayerShape|
const SkRect& getBounds() const override { return path_.getBounds(); }
// |flow::PhysicalLayerShape|
SkPath getPath() const override { return path_; }
// |flow::PhysicalLayerShape|
void clipCanvas(SkCanvas& canvas) const override {
canvas.clipPath(path_, true);
}
// |flow::PhysicalLayerShape|
bool isRect() const override { return false; }
#if defined(OS_FUCHSIA)
// Scenic does not currently support compositing arbitrary shaped layers,
// so we just use the path's bounding rectangle.
// |flow::PhysicalLayerShape|
const SkRRect& getFrameRRect() const override { return frameRRect_; }
#endif // defined(OS_FUCHSIA)
private:
SkPath path_;
#if defined(OS_FUCHSIA)
SkRRect frameRRect_;
#endif // defined(OS_FUCHSIA)
};
} // namespace flow
#endif // FLUTTER_FLOW_LAYERS_PHYSICAL_MODEL_LAYER_H_
......@@ -127,7 +127,8 @@ class SceneBuilder extends NativeFieldWrapperClass2 {
double maskRectBottom,
int blendMode) native "SceneBuilder_pushShaderMask";
/// Pushes a physical model operation onto the operation stack.
/// Pushes a physical model operation for a rounded rectangle onto the
/// operation stack.
///
/// Rasterization will be clipped to the given shape.
///
......@@ -139,6 +140,18 @@ class SceneBuilder extends NativeFieldWrapperClass2 {
double elevation,
int color) native "SceneBuilder_pushPhysicalModel";
/// Pushes a physical model operation for an arbitrary shape onto the
/// operation stack.
///
/// Rasterization will be clipped to the given shape.
///
/// See [pop] for details about the operation stack.
void pushPhysicalShape({ Path path, double elevation, Color color }) {
_pushPhysicalShape(path, elevation, color.value);
}
void _pushPhysicalShape(Path path, double elevation, int color) native
"SceneBuilder_pushPhysicalShape";
/// Ends the effect of the most recently pushed operation.
///
/// Internally the scene builder maintains a stack of operations. Each of the
......
......@@ -33,6 +33,7 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, SceneBuilder);
V(SceneBuilder, pushBackdropFilter) \
V(SceneBuilder, pushShaderMask) \
V(SceneBuilder, pushPhysicalModel) \
V(SceneBuilder, pushPhysicalShape) \
V(SceneBuilder, pop) \
V(SceneBuilder, addPicture) \
V(SceneBuilder, addTexture) \
......@@ -110,6 +111,16 @@ void SceneBuilder::pushPhysicalModel(const RRect& rrect,
UIDartState::Current()->window()->viewport_metrics().device_pixel_ratio);
}
void SceneBuilder::pushPhysicalShape(const CanvasPath* path,
double elevation,
int color) {
layer_builder_->PushPhysicalModel(
path->path(), //
elevation, //
static_cast<SkColor>(color), //
UIDartState::Current()->window()->viewport_metrics().device_pixel_ratio);
}
void SceneBuilder::pop() {
layer_builder_->Pop();
}
......
......@@ -48,6 +48,7 @@ class SceneBuilder : public fxl::RefCountedThreadSafe<SceneBuilder>,
double maskRectBottom,
int blendMode);
void pushPhysicalModel(const RRect& rrect, double elevation, int color);
void pushPhysicalShape(const CanvasPath* path, double elevation, int color);
void pop();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册