blob: 406ee96015bc9f1d6681f82dbfc1399d280dc7a7 [file] [log] [blame]
// 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_canvas_recorder.h"
#include "flutter/display_list/display_list_blend_mode.h"
#include "flutter/display_list/display_list_builder.h"
#include "flutter/display_list/display_list_image_filter.h"
namespace flutter {
#define CHECK_DISPOSE(ret) \
do { \
if (!builder_) { \
FML_DCHECK(builder_) \
<< "Calling method on DisplayListCanvasRecorder after Build()"; \
return ret; \
} \
} while (0)
DisplayListCanvasRecorder::DisplayListCanvasRecorder(const SkRect& bounds)
: SkCanvasVirtualEnforcer(bounds.width(), bounds.height()),
builder_(sk_make_sp<DisplayListBuilder>(bounds)) {}
sk_sp<DisplayList> DisplayListCanvasRecorder::Build() {
CHECK_DISPOSE(nullptr);
sk_sp<DisplayList> display_list = builder_->Build();
builder_.reset();
return display_list;
}
// clang-format off
void DisplayListCanvasRecorder::didConcat44(const SkM44& m44) {
CHECK_DISPOSE();
builder_->transform(m44);
}
// clang-format on
void DisplayListCanvasRecorder::didSetM44(const SkM44& matrix) {
CHECK_DISPOSE();
builder_->transformReset();
builder_->transform(matrix);
}
void DisplayListCanvasRecorder::didTranslate(SkScalar tx, SkScalar ty) {
CHECK_DISPOSE();
builder_->translate(tx, ty);
}
void DisplayListCanvasRecorder::didScale(SkScalar sx, SkScalar sy) {
CHECK_DISPOSE();
builder_->scale(sx, sy);
}
void DisplayListCanvasRecorder::onClipRect(const SkRect& rect,
SkClipOp clip_op,
ClipEdgeStyle edge_style) {
CHECK_DISPOSE();
builder_->clipRect(rect, clip_op,
edge_style == ClipEdgeStyle::kSoft_ClipEdgeStyle);
}
void DisplayListCanvasRecorder::onClipRRect(const SkRRect& rrect,
SkClipOp clip_op,
ClipEdgeStyle edge_style) {
CHECK_DISPOSE();
builder_->clipRRect(rrect, clip_op,
edge_style == ClipEdgeStyle::kSoft_ClipEdgeStyle);
}
void DisplayListCanvasRecorder::onClipPath(const SkPath& path,
SkClipOp clip_op,
ClipEdgeStyle edge_style) {
CHECK_DISPOSE();
builder_->clipPath(path, clip_op,
edge_style == ClipEdgeStyle::kSoft_ClipEdgeStyle);
}
void DisplayListCanvasRecorder::willSave() {
CHECK_DISPOSE();
builder_->save();
}
SkCanvas::SaveLayerStrategy DisplayListCanvasRecorder::getSaveLayerStrategy(
const SaveLayerRec& rec) {
CHECK_DISPOSE(SaveLayerStrategy::kNoLayer_SaveLayerStrategy);
std::shared_ptr<DlImageFilter> backdrop = DlImageFilter::From(rec.fBackdrop);
if (rec.fPaint) {
builder_->setAttributesFromPaint(*rec.fPaint, kSaveLayerWithPaintFlags);
builder_->saveLayer(rec.fBounds, SaveLayerOptions::kWithAttributes,
backdrop.get());
} else {
builder_->saveLayer(rec.fBounds, SaveLayerOptions::kNoAttributes,
backdrop.get());
}
return SaveLayerStrategy::kNoLayer_SaveLayerStrategy;
}
void DisplayListCanvasRecorder::didRestore() {
CHECK_DISPOSE();
builder_->restore();
}
void DisplayListCanvasRecorder::onDrawPaint(const SkPaint& paint) {
CHECK_DISPOSE();
builder_->setAttributesFromPaint(paint, kDrawPaintFlags);
builder_->drawPaint();
}
void DisplayListCanvasRecorder::onDrawRect(const SkRect& rect,
const SkPaint& paint) {
CHECK_DISPOSE();
builder_->setAttributesFromPaint(paint, kDrawRectFlags);
builder_->drawRect(rect);
}
void DisplayListCanvasRecorder::onDrawRRect(const SkRRect& rrect,
const SkPaint& paint) {
CHECK_DISPOSE();
builder_->setAttributesFromPaint(paint, kDrawRRectFlags);
builder_->drawRRect(rrect);
}
void DisplayListCanvasRecorder::onDrawDRRect(const SkRRect& outer,
const SkRRect& inner,
const SkPaint& paint) {
CHECK_DISPOSE();
builder_->setAttributesFromPaint(paint, kDrawDRRectFlags);
builder_->drawDRRect(outer, inner);
}
void DisplayListCanvasRecorder::onDrawOval(const SkRect& rect,
const SkPaint& paint) {
CHECK_DISPOSE();
builder_->setAttributesFromPaint(paint, kDrawOvalFlags);
builder_->drawOval(rect);
}
void DisplayListCanvasRecorder::onDrawArc(const SkRect& rect,
SkScalar startAngle,
SkScalar sweepAngle,
bool useCenter,
const SkPaint& paint) {
CHECK_DISPOSE();
builder_->setAttributesFromPaint(paint,
useCenter //
? kDrawArcWithCenterFlags
: kDrawArcNoCenterFlags);
builder_->drawArc(rect, startAngle, sweepAngle, useCenter);
}
void DisplayListCanvasRecorder::onDrawPath(const SkPath& path,
const SkPaint& paint) {
CHECK_DISPOSE();
builder_->setAttributesFromPaint(paint, kDrawPathFlags);
builder_->drawPath(path);
}
void DisplayListCanvasRecorder::onDrawPoints(SkCanvas::PointMode mode,
size_t count,
const SkPoint pts[],
const SkPaint& paint) {
CHECK_DISPOSE();
switch (mode) {
case SkCanvas::kPoints_PointMode:
builder_->setAttributesFromPaint(paint, kDrawPointsAsPointsFlags);
break;
case SkCanvas::kLines_PointMode:
builder_->setAttributesFromPaint(paint, kDrawPointsAsLinesFlags);
break;
case SkCanvas::kPolygon_PointMode:
builder_->setAttributesFromPaint(paint, kDrawPointsAsPolygonFlags);
break;
}
if (mode == SkCanvas::PointMode::kLines_PointMode && count == 2) {
builder_->drawLine(pts[0], pts[1]);
} else {
uint32_t count32 = static_cast<uint32_t>(count);
// TODO(flar): depending on the mode we could break it down into
// multiple calls to drawPoints, but how much do we really want
// to support more than a couple billion points?
FML_DCHECK(count32 == count);
builder_->drawPoints(mode, count32, pts);
}
}
void DisplayListCanvasRecorder::onDrawVerticesObject(const SkVertices* vertices,
SkBlendMode mode,
const SkPaint& paint) {
CHECK_DISPOSE();
builder_->setAttributesFromPaint(paint, kDrawVerticesFlags);
builder_->drawSkVertices(sk_ref_sp(vertices), mode);
}
void DisplayListCanvasRecorder::onDrawImage2(const SkImage* image,
SkScalar dx,
SkScalar dy,
const SkSamplingOptions& sampling,
const SkPaint* paint) {
CHECK_DISPOSE();
if (paint != nullptr) {
builder_->setAttributesFromPaint(*paint, kDrawImageWithPaintFlags);
}
builder_->drawImage(DlImage::Make(image), SkPoint::Make(dx, dy),
ToDl(sampling), paint != nullptr);
}
void DisplayListCanvasRecorder::onDrawImageRect2(
const SkImage* image,
const SkRect& src,
const SkRect& dst,
const SkSamplingOptions& sampling,
const SkPaint* paint,
SrcRectConstraint constraint) {
CHECK_DISPOSE();
if (paint != nullptr) {
builder_->setAttributesFromPaint(*paint, kDrawImageRectWithPaintFlags);
}
builder_->drawImageRect(DlImage::Make(image), src, dst, ToDl(sampling),
paint != nullptr, constraint);
}
void DisplayListCanvasRecorder::onDrawImageLattice2(const SkImage* image,
const Lattice& lattice,
const SkRect& dst,
SkFilterMode filter,
const SkPaint* paint) {
CHECK_DISPOSE();
if (paint != nullptr) {
// SkCanvas will always construct a paint,
// though it is a default paint most of the time
SkPaint default_paint;
if (*paint == default_paint) {
paint = nullptr;
} else {
builder_->setAttributesFromPaint(*paint, kDrawImageLatticeWithPaintFlags);
}
}
builder_->drawImageLattice(DlImage::Make(image), lattice, dst, ToDl(filter),
paint != nullptr);
}
void DisplayListCanvasRecorder::onDrawAtlas2(const SkImage* image,
const SkRSXform xform[],
const SkRect src[],
const SkColor colors[],
int count,
SkBlendMode mode,
const SkSamplingOptions& sampling,
const SkRect* cull,
const SkPaint* paint) {
CHECK_DISPOSE();
if (paint != nullptr) {
builder_->setAttributesFromPaint(*paint, kDrawAtlasWithPaintFlags);
}
const DlColor* dl_colors = reinterpret_cast<const DlColor*>(colors);
builder_->drawAtlas(DlImage::Make(image), xform, src, dl_colors, count,
ToDl(mode), ToDl(sampling), cull, paint != nullptr);
}
void DisplayListCanvasRecorder::onDrawTextBlob(const SkTextBlob* blob,
SkScalar x,
SkScalar y,
const SkPaint& paint) {
CHECK_DISPOSE();
builder_->setAttributesFromPaint(paint, kDrawTextBlobFlags);
builder_->drawTextBlob(sk_ref_sp(blob), x, y);
}
void DisplayListCanvasRecorder::onDrawPicture(const SkPicture* picture,
const SkMatrix* matrix,
const SkPaint* paint) {
CHECK_DISPOSE();
if (paint != nullptr) {
builder_->setAttributesFromPaint(*paint, kDrawPictureWithPaintFlags);
}
builder_->drawPicture(sk_ref_sp(picture), matrix, paint != nullptr);
}
void DisplayListCanvasRecorder::onDrawShadowRec(const SkPath& path,
const SkDrawShadowRec& rec) {
CHECK_DISPOSE();
// Skia does not expose the SkDrawShadowRec structure in a public
// header file so we cannot record this operation.
// See: https://bugs.chromium.org/p/skia/issues/detail?id=12125
FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::"
<< __FUNCTION__;
}
void DisplayListCanvasRecorder::onDrawBehind(const SkPaint&) {
CHECK_DISPOSE();
FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::"
<< __FUNCTION__;
}
void DisplayListCanvasRecorder::onDrawRegion(const SkRegion& region,
const SkPaint& paint) {
CHECK_DISPOSE();
FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::"
<< __FUNCTION__;
}
void DisplayListCanvasRecorder::onDrawPatch(const SkPoint cubics[12],
const SkColor colors[4],
const SkPoint texCoords[4],
SkBlendMode mode,
const SkPaint& paint) {
CHECK_DISPOSE();
FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::"
<< __FUNCTION__;
}
void DisplayListCanvasRecorder::onDrawEdgeAAQuad(const SkRect& rect,
const SkPoint clip[4],
SkCanvas::QuadAAFlags aaFlags,
const SkColor4f& color,
SkBlendMode mode) {
CHECK_DISPOSE();
FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::"
<< __FUNCTION__;
}
void DisplayListCanvasRecorder::onDrawAnnotation(const SkRect& rect,
const char key[],
SkData* value) {
CHECK_DISPOSE();
FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::"
<< __FUNCTION__;
}
void DisplayListCanvasRecorder::onDrawDrawable(SkDrawable* drawable,
const SkMatrix* matrix) {
CHECK_DISPOSE();
FML_DLOG(ERROR) << "Unimplemented DisplayListCanvasRecorder::"
<< __FUNCTION__;
}
} // namespace flutter