Put WebViews in a HW layer, if the clip is a non-rect. This CL reuses logic implemented by ag/705975. This used to be the way GL WebViews were drawn in Android M. Implement complex clip detection at recording time, which was not previously supported by the canvas. Vulkan WebViews using GL interop are already drawn in a layer, but this CL will be useful when WebView supports new Vulkan interop. Test: WebView CTS pass for Vulkan and GL Bug: 115613038 Change-Id: I9b02c6f4de8efd504a7507633f3d849004215a16
973 lines
36 KiB
C++
973 lines
36 KiB
C++
/*
|
|
* Copyright (C) 2018 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "RecordingCanvas.h"
|
|
|
|
#include "VectorDrawable.h"
|
|
|
|
#include "SkAndroidFrameworkUtils.h"
|
|
#include "SkCanvas.h"
|
|
#include "SkData.h"
|
|
#include "SkDrawShadowInfo.h"
|
|
#include "SkImage.h"
|
|
#include "SkImageFilter.h"
|
|
#include "SkLatticeIter.h"
|
|
#include "SkMath.h"
|
|
#include "SkPicture.h"
|
|
#include "SkRSXform.h"
|
|
#include "SkRegion.h"
|
|
#include "SkTextBlob.h"
|
|
#include "SkVertices.h"
|
|
|
|
#include <experimental/type_traits>
|
|
|
|
namespace android {
|
|
namespace uirenderer {
|
|
|
|
#ifndef SKLITEDL_PAGE
|
|
#define SKLITEDL_PAGE 4096
|
|
#endif
|
|
|
|
// A stand-in for an optional SkRect which was not set, e.g. bounds for a saveLayer().
|
|
static const SkRect kUnset = {SK_ScalarInfinity, 0, 0, 0};
|
|
static const SkRect* maybe_unset(const SkRect& r) {
|
|
return r.left() == SK_ScalarInfinity ? nullptr : &r;
|
|
}
|
|
|
|
// copy_v(dst, src,n, src,n, ...) copies an arbitrary number of typed srcs into dst.
|
|
static void copy_v(void* dst) {}
|
|
|
|
template <typename S, typename... Rest>
|
|
static void copy_v(void* dst, const S* src, int n, Rest&&... rest) {
|
|
SkASSERTF(((uintptr_t)dst & (alignof(S) - 1)) == 0,
|
|
"Expected %p to be aligned for at least %zu bytes.", dst, alignof(S));
|
|
sk_careful_memcpy(dst, src, n * sizeof(S));
|
|
copy_v(SkTAddOffset<void>(dst, n * sizeof(S)), std::forward<Rest>(rest)...);
|
|
}
|
|
|
|
// Helper for getting back at arrays which have been copy_v'd together after an Op.
|
|
template <typename D, typename T>
|
|
static const D* pod(const T* op, size_t offset = 0) {
|
|
return SkTAddOffset<const D>(op + 1, offset);
|
|
}
|
|
|
|
namespace {
|
|
|
|
#define X(T) T,
|
|
enum class Type : uint8_t {
|
|
#include "DisplayListOps.in"
|
|
};
|
|
#undef X
|
|
|
|
struct Op {
|
|
uint32_t type : 8;
|
|
uint32_t skip : 24;
|
|
};
|
|
static_assert(sizeof(Op) == 4, "");
|
|
|
|
struct Flush final : Op {
|
|
static const auto kType = Type::Flush;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->flush(); }
|
|
};
|
|
|
|
struct Save final : Op {
|
|
static const auto kType = Type::Save;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->save(); }
|
|
};
|
|
struct Restore final : Op {
|
|
static const auto kType = Type::Restore;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->restore(); }
|
|
};
|
|
struct SaveLayer final : Op {
|
|
static const auto kType = Type::SaveLayer;
|
|
SaveLayer(const SkRect* bounds, const SkPaint* paint, const SkImageFilter* backdrop,
|
|
const SkImage* clipMask, const SkMatrix* clipMatrix, SkCanvas::SaveLayerFlags flags) {
|
|
if (bounds) {
|
|
this->bounds = *bounds;
|
|
}
|
|
if (paint) {
|
|
this->paint = *paint;
|
|
}
|
|
this->backdrop = sk_ref_sp(backdrop);
|
|
this->clipMask = sk_ref_sp(clipMask);
|
|
this->clipMatrix = clipMatrix ? *clipMatrix : SkMatrix::I();
|
|
this->flags = flags;
|
|
}
|
|
SkRect bounds = kUnset;
|
|
SkPaint paint;
|
|
sk_sp<const SkImageFilter> backdrop;
|
|
sk_sp<const SkImage> clipMask;
|
|
SkMatrix clipMatrix;
|
|
SkCanvas::SaveLayerFlags flags;
|
|
void draw(SkCanvas* c, const SkMatrix&) const {
|
|
c->saveLayer({maybe_unset(bounds), &paint, backdrop.get(), clipMask.get(),
|
|
clipMatrix.isIdentity() ? nullptr : &clipMatrix, flags});
|
|
}
|
|
};
|
|
struct SaveBehind final : Op {
|
|
static const auto kType = Type::SaveBehind;
|
|
SaveBehind(const SkRect* subset) {
|
|
if (subset) { this->subset = *subset; }
|
|
}
|
|
SkRect subset = kUnset;
|
|
void draw(SkCanvas* c, const SkMatrix&) const {
|
|
SkAndroidFrameworkUtils::SaveBehind(c, &subset);
|
|
}
|
|
};
|
|
|
|
struct Concat final : Op {
|
|
static const auto kType = Type::Concat;
|
|
Concat(const SkMatrix& matrix) : matrix(matrix) {}
|
|
SkMatrix matrix;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->concat(matrix); }
|
|
};
|
|
struct SetMatrix final : Op {
|
|
static const auto kType = Type::SetMatrix;
|
|
SetMatrix(const SkMatrix& matrix) : matrix(matrix) {}
|
|
SkMatrix matrix;
|
|
void draw(SkCanvas* c, const SkMatrix& original) const {
|
|
c->setMatrix(SkMatrix::Concat(original, matrix));
|
|
}
|
|
};
|
|
struct Translate final : Op {
|
|
static const auto kType = Type::Translate;
|
|
Translate(SkScalar dx, SkScalar dy) : dx(dx), dy(dy) {}
|
|
SkScalar dx, dy;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->translate(dx, dy); }
|
|
};
|
|
|
|
struct ClipPath final : Op {
|
|
static const auto kType = Type::ClipPath;
|
|
ClipPath(const SkPath& path, SkClipOp op, bool aa) : path(path), op(op), aa(aa) {}
|
|
SkPath path;
|
|
SkClipOp op;
|
|
bool aa;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->clipPath(path, op, aa); }
|
|
};
|
|
struct ClipRect final : Op {
|
|
static const auto kType = Type::ClipRect;
|
|
ClipRect(const SkRect& rect, SkClipOp op, bool aa) : rect(rect), op(op), aa(aa) {}
|
|
SkRect rect;
|
|
SkClipOp op;
|
|
bool aa;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->clipRect(rect, op, aa); }
|
|
};
|
|
struct ClipRRect final : Op {
|
|
static const auto kType = Type::ClipRRect;
|
|
ClipRRect(const SkRRect& rrect, SkClipOp op, bool aa) : rrect(rrect), op(op), aa(aa) {}
|
|
SkRRect rrect;
|
|
SkClipOp op;
|
|
bool aa;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->clipRRect(rrect, op, aa); }
|
|
};
|
|
struct ClipRegion final : Op {
|
|
static const auto kType = Type::ClipRegion;
|
|
ClipRegion(const SkRegion& region, SkClipOp op) : region(region), op(op) {}
|
|
SkRegion region;
|
|
SkClipOp op;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->clipRegion(region, op); }
|
|
};
|
|
|
|
struct DrawPaint final : Op {
|
|
static const auto kType = Type::DrawPaint;
|
|
DrawPaint(const SkPaint& paint) : paint(paint) {}
|
|
SkPaint paint;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->drawPaint(paint); }
|
|
};
|
|
struct DrawPath final : Op {
|
|
static const auto kType = Type::DrawPath;
|
|
DrawPath(const SkPath& path, const SkPaint& paint) : path(path), paint(paint) {}
|
|
SkPath path;
|
|
SkPaint paint;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->drawPath(path, paint); }
|
|
};
|
|
struct DrawRect final : Op {
|
|
static const auto kType = Type::DrawRect;
|
|
DrawRect(const SkRect& rect, const SkPaint& paint) : rect(rect), paint(paint) {}
|
|
SkRect rect;
|
|
SkPaint paint;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->drawRect(rect, paint); }
|
|
};
|
|
struct DrawRegion final : Op {
|
|
static const auto kType = Type::DrawRegion;
|
|
DrawRegion(const SkRegion& region, const SkPaint& paint) : region(region), paint(paint) {}
|
|
SkRegion region;
|
|
SkPaint paint;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->drawRegion(region, paint); }
|
|
};
|
|
struct DrawOval final : Op {
|
|
static const auto kType = Type::DrawOval;
|
|
DrawOval(const SkRect& oval, const SkPaint& paint) : oval(oval), paint(paint) {}
|
|
SkRect oval;
|
|
SkPaint paint;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->drawOval(oval, paint); }
|
|
};
|
|
struct DrawArc final : Op {
|
|
static const auto kType = Type::DrawArc;
|
|
DrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
|
|
const SkPaint& paint)
|
|
: oval(oval)
|
|
, startAngle(startAngle)
|
|
, sweepAngle(sweepAngle)
|
|
, useCenter(useCenter)
|
|
, paint(paint) {}
|
|
SkRect oval;
|
|
SkScalar startAngle;
|
|
SkScalar sweepAngle;
|
|
bool useCenter;
|
|
SkPaint paint;
|
|
void draw(SkCanvas* c, const SkMatrix&) const {
|
|
c->drawArc(oval, startAngle, sweepAngle, useCenter, paint);
|
|
}
|
|
};
|
|
struct DrawRRect final : Op {
|
|
static const auto kType = Type::DrawRRect;
|
|
DrawRRect(const SkRRect& rrect, const SkPaint& paint) : rrect(rrect), paint(paint) {}
|
|
SkRRect rrect;
|
|
SkPaint paint;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->drawRRect(rrect, paint); }
|
|
};
|
|
struct DrawDRRect final : Op {
|
|
static const auto kType = Type::DrawDRRect;
|
|
DrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint)
|
|
: outer(outer), inner(inner), paint(paint) {}
|
|
SkRRect outer, inner;
|
|
SkPaint paint;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->drawDRRect(outer, inner, paint); }
|
|
};
|
|
|
|
struct DrawAnnotation final : Op {
|
|
static const auto kType = Type::DrawAnnotation;
|
|
DrawAnnotation(const SkRect& rect, SkData* value) : rect(rect), value(sk_ref_sp(value)) {}
|
|
SkRect rect;
|
|
sk_sp<SkData> value;
|
|
void draw(SkCanvas* c, const SkMatrix&) const {
|
|
c->drawAnnotation(rect, pod<char>(this), value.get());
|
|
}
|
|
};
|
|
struct DrawDrawable final : Op {
|
|
static const auto kType = Type::DrawDrawable;
|
|
DrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) : drawable(sk_ref_sp(drawable)) {
|
|
if (matrix) {
|
|
this->matrix = *matrix;
|
|
}
|
|
}
|
|
sk_sp<SkDrawable> drawable;
|
|
SkMatrix matrix = SkMatrix::I();
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->drawDrawable(drawable.get(), &matrix); }
|
|
};
|
|
struct DrawPicture final : Op {
|
|
static const auto kType = Type::DrawPicture;
|
|
DrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint)
|
|
: picture(sk_ref_sp(picture)) {
|
|
if (matrix) {
|
|
this->matrix = *matrix;
|
|
}
|
|
if (paint) {
|
|
this->paint = *paint;
|
|
has_paint = true;
|
|
}
|
|
}
|
|
sk_sp<const SkPicture> picture;
|
|
SkMatrix matrix = SkMatrix::I();
|
|
SkPaint paint;
|
|
bool has_paint = false; // TODO: why is a default paint not the same?
|
|
void draw(SkCanvas* c, const SkMatrix&) const {
|
|
c->drawPicture(picture.get(), &matrix, has_paint ? &paint : nullptr);
|
|
}
|
|
};
|
|
|
|
struct DrawImage final : Op {
|
|
static const auto kType = Type::DrawImage;
|
|
DrawImage(sk_sp<const SkImage>&& image, SkScalar x, SkScalar y, const SkPaint* paint,
|
|
BitmapPalette palette)
|
|
: image(std::move(image)), x(x), y(y), palette(palette) {
|
|
if (paint) {
|
|
this->paint = *paint;
|
|
}
|
|
}
|
|
sk_sp<const SkImage> image;
|
|
SkScalar x, y;
|
|
SkPaint paint;
|
|
BitmapPalette palette;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->drawImage(image.get(), x, y, &paint); }
|
|
};
|
|
struct DrawImageNine final : Op {
|
|
static const auto kType = Type::DrawImageNine;
|
|
DrawImageNine(sk_sp<const SkImage>&& image, const SkIRect& center, const SkRect& dst,
|
|
const SkPaint* paint)
|
|
: image(std::move(image)), center(center), dst(dst) {
|
|
if (paint) {
|
|
this->paint = *paint;
|
|
}
|
|
}
|
|
sk_sp<const SkImage> image;
|
|
SkIRect center;
|
|
SkRect dst;
|
|
SkPaint paint;
|
|
void draw(SkCanvas* c, const SkMatrix&) const {
|
|
c->drawImageNine(image.get(), center, dst, &paint);
|
|
}
|
|
};
|
|
struct DrawImageRect final : Op {
|
|
static const auto kType = Type::DrawImageRect;
|
|
DrawImageRect(sk_sp<const SkImage>&& image, const SkRect* src, const SkRect& dst,
|
|
const SkPaint* paint, SkCanvas::SrcRectConstraint constraint,
|
|
BitmapPalette palette)
|
|
: image(std::move(image)), dst(dst), constraint(constraint), palette(palette) {
|
|
this->src = src ? *src : SkRect::MakeIWH(this->image->width(), this->image->height());
|
|
if (paint) {
|
|
this->paint = *paint;
|
|
}
|
|
}
|
|
sk_sp<const SkImage> image;
|
|
SkRect src, dst;
|
|
SkPaint paint;
|
|
SkCanvas::SrcRectConstraint constraint;
|
|
BitmapPalette palette;
|
|
void draw(SkCanvas* c, const SkMatrix&) const {
|
|
c->drawImageRect(image.get(), src, dst, &paint, constraint);
|
|
}
|
|
};
|
|
struct DrawImageLattice final : Op {
|
|
static const auto kType = Type::DrawImageLattice;
|
|
DrawImageLattice(sk_sp<const SkImage>&& image, int xs, int ys, int fs, const SkIRect& src,
|
|
const SkRect& dst, const SkPaint* paint, BitmapPalette palette)
|
|
: image(std::move(image))
|
|
, xs(xs)
|
|
, ys(ys)
|
|
, fs(fs)
|
|
, src(src)
|
|
, dst(dst)
|
|
, palette(palette) {
|
|
if (paint) {
|
|
this->paint = *paint;
|
|
}
|
|
}
|
|
sk_sp<const SkImage> image;
|
|
int xs, ys, fs;
|
|
SkIRect src;
|
|
SkRect dst;
|
|
SkPaint paint;
|
|
BitmapPalette palette;
|
|
void draw(SkCanvas* c, const SkMatrix&) const {
|
|
auto xdivs = pod<int>(this, 0), ydivs = pod<int>(this, xs * sizeof(int));
|
|
auto colors = (0 == fs) ? nullptr : pod<SkColor>(this, (xs + ys) * sizeof(int));
|
|
auto flags =
|
|
(0 == fs) ? nullptr : pod<SkCanvas::Lattice::RectType>(
|
|
this, (xs + ys) * sizeof(int) + fs * sizeof(SkColor));
|
|
c->drawImageLattice(image.get(), {xdivs, ydivs, flags, xs, ys, &src, colors}, dst, &paint);
|
|
}
|
|
};
|
|
|
|
struct DrawTextBlob final : Op {
|
|
static const auto kType = Type::DrawTextBlob;
|
|
DrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint)
|
|
: blob(sk_ref_sp(blob)), x(x), y(y), paint(paint) {}
|
|
sk_sp<const SkTextBlob> blob;
|
|
SkScalar x, y;
|
|
SkPaint paint;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->drawTextBlob(blob.get(), x, y, paint); }
|
|
};
|
|
|
|
struct DrawPatch final : Op {
|
|
static const auto kType = Type::DrawPatch;
|
|
DrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texs[4],
|
|
SkBlendMode bmode, const SkPaint& paint)
|
|
: xfermode(bmode), paint(paint) {
|
|
copy_v(this->cubics, cubics, 12);
|
|
if (colors) {
|
|
copy_v(this->colors, colors, 4);
|
|
has_colors = true;
|
|
}
|
|
if (texs) {
|
|
copy_v(this->texs, texs, 4);
|
|
has_texs = true;
|
|
}
|
|
}
|
|
SkPoint cubics[12];
|
|
SkColor colors[4];
|
|
SkPoint texs[4];
|
|
SkBlendMode xfermode;
|
|
SkPaint paint;
|
|
bool has_colors = false;
|
|
bool has_texs = false;
|
|
void draw(SkCanvas* c, const SkMatrix&) const {
|
|
c->drawPatch(cubics, has_colors ? colors : nullptr, has_texs ? texs : nullptr, xfermode,
|
|
paint);
|
|
}
|
|
};
|
|
struct DrawPoints final : Op {
|
|
static const auto kType = Type::DrawPoints;
|
|
DrawPoints(SkCanvas::PointMode mode, size_t count, const SkPaint& paint)
|
|
: mode(mode), count(count), paint(paint) {}
|
|
SkCanvas::PointMode mode;
|
|
size_t count;
|
|
SkPaint paint;
|
|
void draw(SkCanvas* c, const SkMatrix&) const {
|
|
c->drawPoints(mode, count, pod<SkPoint>(this), paint);
|
|
}
|
|
};
|
|
struct DrawVertices final : Op {
|
|
static const auto kType = Type::DrawVertices;
|
|
DrawVertices(const SkVertices* v, int bc, SkBlendMode m, const SkPaint& p)
|
|
: vertices(sk_ref_sp(const_cast<SkVertices*>(v))), boneCount(bc), mode(m), paint(p) {}
|
|
sk_sp<SkVertices> vertices;
|
|
int boneCount;
|
|
SkBlendMode mode;
|
|
SkPaint paint;
|
|
void draw(SkCanvas* c, const SkMatrix&) const {
|
|
c->drawVertices(vertices, pod<SkVertices::Bone>(this), boneCount, mode, paint);
|
|
}
|
|
};
|
|
struct DrawAtlas final : Op {
|
|
static const auto kType = Type::DrawAtlas;
|
|
DrawAtlas(const SkImage* atlas, int count, SkBlendMode xfermode, const SkRect* cull,
|
|
const SkPaint* paint, bool has_colors)
|
|
: atlas(sk_ref_sp(atlas)), count(count), xfermode(xfermode), has_colors(has_colors) {
|
|
if (cull) {
|
|
this->cull = *cull;
|
|
}
|
|
if (paint) {
|
|
this->paint = *paint;
|
|
}
|
|
}
|
|
sk_sp<const SkImage> atlas;
|
|
int count;
|
|
SkBlendMode xfermode;
|
|
SkRect cull = kUnset;
|
|
SkPaint paint;
|
|
bool has_colors;
|
|
void draw(SkCanvas* c, const SkMatrix&) const {
|
|
auto xforms = pod<SkRSXform>(this, 0);
|
|
auto texs = pod<SkRect>(this, count * sizeof(SkRSXform));
|
|
auto colors = has_colors ? pod<SkColor>(this, count * (sizeof(SkRSXform) + sizeof(SkRect)))
|
|
: nullptr;
|
|
c->drawAtlas(atlas.get(), xforms, texs, colors, count, xfermode, maybe_unset(cull), &paint);
|
|
}
|
|
};
|
|
struct DrawShadowRec final : Op {
|
|
static const auto kType = Type::DrawShadowRec;
|
|
DrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) : fPath(path), fRec(rec) {}
|
|
SkPath fPath;
|
|
SkDrawShadowRec fRec;
|
|
void draw(SkCanvas* c, const SkMatrix&) const { c->private_draw_shadow_rec(fPath, fRec); }
|
|
};
|
|
|
|
struct DrawVectorDrawable final : Op {
|
|
static const auto kType = Type::DrawVectorDrawable;
|
|
DrawVectorDrawable(VectorDrawableRoot* tree)
|
|
: mRoot(tree)
|
|
, mBounds(tree->stagingProperties().getBounds())
|
|
, palette(tree->computePalette()) {
|
|
// Recording, so use staging properties
|
|
tree->getPaintFor(&paint, tree->stagingProperties());
|
|
}
|
|
|
|
void draw(SkCanvas* canvas, const SkMatrix&) const { mRoot->draw(canvas, mBounds, paint); }
|
|
|
|
sp<VectorDrawableRoot> mRoot;
|
|
SkRect mBounds;
|
|
SkPaint paint;
|
|
BitmapPalette palette;
|
|
};
|
|
}
|
|
|
|
template <typename T, typename... Args>
|
|
void* DisplayListData::push(size_t pod, Args&&... args) {
|
|
size_t skip = SkAlignPtr(sizeof(T) + pod);
|
|
SkASSERT(skip < (1 << 24));
|
|
if (fUsed + skip > fReserved) {
|
|
static_assert(SkIsPow2(SKLITEDL_PAGE), "This math needs updating for non-pow2.");
|
|
// Next greater multiple of SKLITEDL_PAGE.
|
|
fReserved = (fUsed + skip + SKLITEDL_PAGE) & ~(SKLITEDL_PAGE - 1);
|
|
fBytes.realloc(fReserved);
|
|
}
|
|
SkASSERT(fUsed + skip <= fReserved);
|
|
auto op = (T*)(fBytes.get() + fUsed);
|
|
fUsed += skip;
|
|
new (op) T{std::forward<Args>(args)...};
|
|
op->type = (uint32_t)T::kType;
|
|
op->skip = skip;
|
|
return op + 1;
|
|
}
|
|
|
|
template <typename Fn, typename... Args>
|
|
inline void DisplayListData::map(const Fn fns[], Args... args) const {
|
|
auto end = fBytes.get() + fUsed;
|
|
for (const uint8_t* ptr = fBytes.get(); ptr < end;) {
|
|
auto op = (const Op*)ptr;
|
|
auto type = op->type;
|
|
auto skip = op->skip;
|
|
if (auto fn = fns[type]) { // We replace no-op functions with nullptrs
|
|
fn(op, args...); // to avoid the overhead of a pointless call.
|
|
}
|
|
ptr += skip;
|
|
}
|
|
}
|
|
|
|
void DisplayListData::flush() {
|
|
this->push<Flush>(0);
|
|
}
|
|
|
|
void DisplayListData::save() {
|
|
this->push<Save>(0);
|
|
}
|
|
void DisplayListData::restore() {
|
|
this->push<Restore>(0);
|
|
}
|
|
void DisplayListData::saveLayer(const SkRect* bounds, const SkPaint* paint,
|
|
const SkImageFilter* backdrop, const SkImage* clipMask,
|
|
const SkMatrix* clipMatrix, SkCanvas::SaveLayerFlags flags) {
|
|
this->push<SaveLayer>(0, bounds, paint, backdrop, clipMask, clipMatrix, flags);
|
|
}
|
|
|
|
void DisplayListData::saveBehind(const SkRect* subset) {
|
|
this->push<SaveBehind>(0, subset);
|
|
}
|
|
|
|
void DisplayListData::concat(const SkMatrix& matrix) {
|
|
this->push<Concat>(0, matrix);
|
|
}
|
|
void DisplayListData::setMatrix(const SkMatrix& matrix) {
|
|
this->push<SetMatrix>(0, matrix);
|
|
}
|
|
void DisplayListData::translate(SkScalar dx, SkScalar dy) {
|
|
this->push<Translate>(0, dx, dy);
|
|
}
|
|
|
|
void DisplayListData::clipPath(const SkPath& path, SkClipOp op, bool aa) {
|
|
this->push<ClipPath>(0, path, op, aa);
|
|
}
|
|
void DisplayListData::clipRect(const SkRect& rect, SkClipOp op, bool aa) {
|
|
this->push<ClipRect>(0, rect, op, aa);
|
|
}
|
|
void DisplayListData::clipRRect(const SkRRect& rrect, SkClipOp op, bool aa) {
|
|
this->push<ClipRRect>(0, rrect, op, aa);
|
|
}
|
|
void DisplayListData::clipRegion(const SkRegion& region, SkClipOp op) {
|
|
this->push<ClipRegion>(0, region, op);
|
|
}
|
|
|
|
void DisplayListData::drawPaint(const SkPaint& paint) {
|
|
this->push<DrawPaint>(0, paint);
|
|
}
|
|
void DisplayListData::drawPath(const SkPath& path, const SkPaint& paint) {
|
|
this->push<DrawPath>(0, path, paint);
|
|
}
|
|
void DisplayListData::drawRect(const SkRect& rect, const SkPaint& paint) {
|
|
this->push<DrawRect>(0, rect, paint);
|
|
}
|
|
void DisplayListData::drawRegion(const SkRegion& region, const SkPaint& paint) {
|
|
this->push<DrawRegion>(0, region, paint);
|
|
}
|
|
void DisplayListData::drawOval(const SkRect& oval, const SkPaint& paint) {
|
|
this->push<DrawOval>(0, oval, paint);
|
|
}
|
|
void DisplayListData::drawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
|
|
bool useCenter, const SkPaint& paint) {
|
|
this->push<DrawArc>(0, oval, startAngle, sweepAngle, useCenter, paint);
|
|
}
|
|
void DisplayListData::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
|
|
this->push<DrawRRect>(0, rrect, paint);
|
|
}
|
|
void DisplayListData::drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) {
|
|
this->push<DrawDRRect>(0, outer, inner, paint);
|
|
}
|
|
|
|
void DisplayListData::drawAnnotation(const SkRect& rect, const char* key, SkData* value) {
|
|
size_t bytes = strlen(key) + 1;
|
|
void* pod = this->push<DrawAnnotation>(bytes, rect, value);
|
|
copy_v(pod, key, bytes);
|
|
}
|
|
void DisplayListData::drawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
|
|
this->push<DrawDrawable>(0, drawable, matrix);
|
|
}
|
|
void DisplayListData::drawPicture(const SkPicture* picture, const SkMatrix* matrix,
|
|
const SkPaint* paint) {
|
|
this->push<DrawPicture>(0, picture, matrix, paint);
|
|
}
|
|
void DisplayListData::drawImage(sk_sp<const SkImage> image, SkScalar x, SkScalar y,
|
|
const SkPaint* paint, BitmapPalette palette) {
|
|
this->push<DrawImage>(0, std::move(image), x, y, paint, palette);
|
|
}
|
|
void DisplayListData::drawImageNine(sk_sp<const SkImage> image, const SkIRect& center,
|
|
const SkRect& dst, const SkPaint* paint) {
|
|
this->push<DrawImageNine>(0, std::move(image), center, dst, paint);
|
|
}
|
|
void DisplayListData::drawImageRect(sk_sp<const SkImage> image, const SkRect* src,
|
|
const SkRect& dst, const SkPaint* paint,
|
|
SkCanvas::SrcRectConstraint constraint, BitmapPalette palette) {
|
|
this->push<DrawImageRect>(0, std::move(image), src, dst, paint, constraint, palette);
|
|
}
|
|
void DisplayListData::drawImageLattice(sk_sp<const SkImage> image, const SkCanvas::Lattice& lattice,
|
|
const SkRect& dst, const SkPaint* paint,
|
|
BitmapPalette palette) {
|
|
int xs = lattice.fXCount, ys = lattice.fYCount;
|
|
int fs = lattice.fRectTypes ? (xs + 1) * (ys + 1) : 0;
|
|
size_t bytes = (xs + ys) * sizeof(int) + fs * sizeof(SkCanvas::Lattice::RectType) +
|
|
fs * sizeof(SkColor);
|
|
SkASSERT(lattice.fBounds);
|
|
void* pod = this->push<DrawImageLattice>(bytes, std::move(image), xs, ys, fs, *lattice.fBounds,
|
|
dst, paint, palette);
|
|
copy_v(pod, lattice.fXDivs, xs, lattice.fYDivs, ys, lattice.fColors, fs, lattice.fRectTypes,
|
|
fs);
|
|
}
|
|
|
|
void DisplayListData::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
|
|
const SkPaint& paint) {
|
|
this->push<DrawTextBlob>(0, blob, x, y, paint);
|
|
mHasText = true;
|
|
}
|
|
|
|
void DisplayListData::drawPatch(const SkPoint points[12], const SkColor colors[4],
|
|
const SkPoint texs[4], SkBlendMode bmode, const SkPaint& paint) {
|
|
this->push<DrawPatch>(0, points, colors, texs, bmode, paint);
|
|
}
|
|
void DisplayListData::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint points[],
|
|
const SkPaint& paint) {
|
|
void* pod = this->push<DrawPoints>(count * sizeof(SkPoint), mode, count, paint);
|
|
copy_v(pod, points, count);
|
|
}
|
|
void DisplayListData::drawVertices(const SkVertices* vertices, const SkVertices::Bone bones[],
|
|
int boneCount, SkBlendMode mode, const SkPaint& paint) {
|
|
void* pod = this->push<DrawVertices>(boneCount * sizeof(SkVertices::Bone), vertices, boneCount,
|
|
mode, paint);
|
|
copy_v(pod, bones, boneCount);
|
|
}
|
|
void DisplayListData::drawAtlas(const SkImage* atlas, const SkRSXform xforms[], const SkRect texs[],
|
|
const SkColor colors[], int count, SkBlendMode xfermode,
|
|
const SkRect* cull, const SkPaint* paint) {
|
|
size_t bytes = count * (sizeof(SkRSXform) + sizeof(SkRect));
|
|
if (colors) {
|
|
bytes += count * sizeof(SkColor);
|
|
}
|
|
void* pod =
|
|
this->push<DrawAtlas>(bytes, atlas, count, xfermode, cull, paint, colors != nullptr);
|
|
copy_v(pod, xforms, count, texs, count, colors, colors ? count : 0);
|
|
}
|
|
void DisplayListData::drawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
|
|
this->push<DrawShadowRec>(0, path, rec);
|
|
}
|
|
void DisplayListData::drawVectorDrawable(VectorDrawableRoot* tree) {
|
|
this->push<DrawVectorDrawable>(0, tree);
|
|
}
|
|
|
|
typedef void (*draw_fn)(const void*, SkCanvas*, const SkMatrix&);
|
|
typedef void (*void_fn)(const void*);
|
|
typedef void (*color_transform_fn)(const void*, ColorTransform);
|
|
|
|
// All ops implement draw().
|
|
#define X(T) \
|
|
[](const void* op, SkCanvas* c, const SkMatrix& original) { \
|
|
((const T*)op)->draw(c, original); \
|
|
},
|
|
static const draw_fn draw_fns[] = {
|
|
#include "DisplayListOps.in"
|
|
};
|
|
#undef X
|
|
|
|
// Most state ops (matrix, clip, save, restore) have a trivial destructor.
|
|
#define X(T) \
|
|
!std::is_trivially_destructible<T>::value ? [](const void* op) { ((const T*)op)->~T(); } \
|
|
: (void_fn) nullptr,
|
|
|
|
static const void_fn dtor_fns[] = {
|
|
#include "DisplayListOps.in"
|
|
};
|
|
#undef X
|
|
|
|
void DisplayListData::draw(SkCanvas* canvas) const {
|
|
SkAutoCanvasRestore acr(canvas, false);
|
|
this->map(draw_fns, canvas, canvas->getTotalMatrix());
|
|
}
|
|
|
|
DisplayListData::~DisplayListData() {
|
|
this->reset();
|
|
}
|
|
|
|
void DisplayListData::reset() {
|
|
this->map(dtor_fns);
|
|
|
|
// Leave fBytes and fReserved alone.
|
|
fUsed = 0;
|
|
}
|
|
|
|
template <class T>
|
|
using has_paint_helper = decltype(std::declval<T>().paint);
|
|
|
|
template <class T>
|
|
constexpr bool has_paint = std::experimental::is_detected_v<has_paint_helper, T>;
|
|
|
|
template <class T>
|
|
using has_palette_helper = decltype(std::declval<T>().palette);
|
|
|
|
template <class T>
|
|
constexpr bool has_palette = std::experimental::is_detected_v<has_palette_helper, T>;
|
|
|
|
template <class T>
|
|
constexpr color_transform_fn colorTransformForOp() {
|
|
if
|
|
constexpr(has_paint<T> && has_palette<T>) {
|
|
// It's a bitmap
|
|
return [](const void* opRaw, ColorTransform transform) {
|
|
// TODO: We should be const. Or not. Or just use a different map
|
|
// Unclear, but this is the quick fix
|
|
const T* op = reinterpret_cast<const T*>(opRaw);
|
|
transformPaint(transform, const_cast<SkPaint*>(&(op->paint)), op->palette);
|
|
};
|
|
}
|
|
else if
|
|
constexpr(has_paint<T>) {
|
|
return [](const void* opRaw, ColorTransform transform) {
|
|
// TODO: We should be const. Or not. Or just use a different map
|
|
// Unclear, but this is the quick fix
|
|
const T* op = reinterpret_cast<const T*>(opRaw);
|
|
transformPaint(transform, const_cast<SkPaint*>(&(op->paint)));
|
|
};
|
|
}
|
|
else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
#define X(T) colorTransformForOp<T>(),
|
|
static const color_transform_fn color_transform_fns[] = {
|
|
#include "DisplayListOps.in"
|
|
};
|
|
#undef X
|
|
|
|
void DisplayListData::applyColorTransform(ColorTransform transform) {
|
|
this->map(color_transform_fns, transform);
|
|
}
|
|
|
|
RecordingCanvas::RecordingCanvas() : INHERITED(1, 1), fDL(nullptr) {}
|
|
|
|
void RecordingCanvas::reset(DisplayListData* dl, const SkIRect& bounds) {
|
|
this->resetCanvas(bounds.right(), bounds.bottom());
|
|
fDL = dl;
|
|
mClipMayBeComplex = false;
|
|
mSaveCount = mComplexSaveCount = 0;
|
|
}
|
|
|
|
sk_sp<SkSurface> RecordingCanvas::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) {
|
|
return nullptr;
|
|
}
|
|
|
|
void RecordingCanvas::onFlush() {
|
|
fDL->flush();
|
|
}
|
|
|
|
void RecordingCanvas::willSave() {
|
|
mSaveCount++;
|
|
fDL->save();
|
|
}
|
|
SkCanvas::SaveLayerStrategy RecordingCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
|
|
fDL->saveLayer(rec.fBounds, rec.fPaint, rec.fBackdrop, rec.fClipMask, rec.fClipMatrix,
|
|
rec.fSaveLayerFlags);
|
|
return SkCanvas::kNoLayer_SaveLayerStrategy;
|
|
}
|
|
void RecordingCanvas::willRestore() {
|
|
mSaveCount--;
|
|
if (mSaveCount < mComplexSaveCount) {
|
|
mClipMayBeComplex = false;
|
|
mComplexSaveCount = 0;
|
|
}
|
|
fDL->restore();
|
|
}
|
|
|
|
bool RecordingCanvas::onDoSaveBehind(const SkRect* subset) {
|
|
fDL->saveBehind(subset);
|
|
return false;
|
|
}
|
|
|
|
void RecordingCanvas::didConcat(const SkMatrix& matrix) {
|
|
fDL->concat(matrix);
|
|
}
|
|
void RecordingCanvas::didSetMatrix(const SkMatrix& matrix) {
|
|
fDL->setMatrix(matrix);
|
|
}
|
|
void RecordingCanvas::didTranslate(SkScalar dx, SkScalar dy) {
|
|
fDL->translate(dx, dy);
|
|
}
|
|
|
|
void RecordingCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle style) {
|
|
fDL->clipRect(rect, op, style == kSoft_ClipEdgeStyle);
|
|
if (!getTotalMatrix().isScaleTranslate()) {
|
|
setClipMayBeComplex();
|
|
}
|
|
this->INHERITED::onClipRect(rect, op, style);
|
|
}
|
|
void RecordingCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle style) {
|
|
if (rrect.getType() > SkRRect::kRect_Type || !getTotalMatrix().isScaleTranslate()) {
|
|
setClipMayBeComplex();
|
|
}
|
|
fDL->clipRRect(rrect, op, style == kSoft_ClipEdgeStyle);
|
|
this->INHERITED::onClipRRect(rrect, op, style);
|
|
}
|
|
void RecordingCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle style) {
|
|
setClipMayBeComplex();
|
|
fDL->clipPath(path, op, style == kSoft_ClipEdgeStyle);
|
|
this->INHERITED::onClipPath(path, op, style);
|
|
}
|
|
void RecordingCanvas::onClipRegion(const SkRegion& region, SkClipOp op) {
|
|
if (region.isComplex() || !getTotalMatrix().isScaleTranslate()) {
|
|
setClipMayBeComplex();
|
|
}
|
|
fDL->clipRegion(region, op);
|
|
this->INHERITED::onClipRegion(region, op);
|
|
}
|
|
|
|
void RecordingCanvas::onDrawPaint(const SkPaint& paint) {
|
|
fDL->drawPaint(paint);
|
|
}
|
|
void RecordingCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
|
|
fDL->drawPath(path, paint);
|
|
}
|
|
void RecordingCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
|
|
fDL->drawRect(rect, paint);
|
|
}
|
|
void RecordingCanvas::onDrawRegion(const SkRegion& region, const SkPaint& paint) {
|
|
fDL->drawRegion(region, paint);
|
|
}
|
|
void RecordingCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
|
|
fDL->drawOval(oval, paint);
|
|
}
|
|
void RecordingCanvas::onDrawArc(const SkRect& oval, SkScalar startAngle, SkScalar sweepAngle,
|
|
bool useCenter, const SkPaint& paint) {
|
|
fDL->drawArc(oval, startAngle, sweepAngle, useCenter, paint);
|
|
}
|
|
void RecordingCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
|
|
fDL->drawRRect(rrect, paint);
|
|
}
|
|
void RecordingCanvas::onDrawDRRect(const SkRRect& out, const SkRRect& in, const SkPaint& paint) {
|
|
fDL->drawDRRect(out, in, paint);
|
|
}
|
|
|
|
void RecordingCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
|
|
fDL->drawDrawable(drawable, matrix);
|
|
}
|
|
void RecordingCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
|
|
const SkPaint* paint) {
|
|
fDL->drawPicture(picture, matrix, paint);
|
|
}
|
|
void RecordingCanvas::onDrawAnnotation(const SkRect& rect, const char key[], SkData* val) {
|
|
fDL->drawAnnotation(rect, key, val);
|
|
}
|
|
|
|
void RecordingCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
|
|
const SkPaint& paint) {
|
|
fDL->drawTextBlob(blob, x, y, paint);
|
|
}
|
|
|
|
void RecordingCanvas::onDrawBitmap(const SkBitmap& bm, SkScalar x, SkScalar y,
|
|
const SkPaint* paint) {
|
|
fDL->drawImage(SkImage::MakeFromBitmap(bm), x, y, paint, BitmapPalette::Unknown);
|
|
}
|
|
void RecordingCanvas::onDrawBitmapNine(const SkBitmap& bm, const SkIRect& center, const SkRect& dst,
|
|
const SkPaint* paint) {
|
|
fDL->drawImageNine(SkImage::MakeFromBitmap(bm), center, dst, paint);
|
|
}
|
|
void RecordingCanvas::onDrawBitmapRect(const SkBitmap& bm, const SkRect* src, const SkRect& dst,
|
|
const SkPaint* paint, SrcRectConstraint constraint) {
|
|
fDL->drawImageRect(SkImage::MakeFromBitmap(bm), src, dst, paint, constraint,
|
|
BitmapPalette::Unknown);
|
|
}
|
|
void RecordingCanvas::onDrawBitmapLattice(const SkBitmap& bm, const SkCanvas::Lattice& lattice,
|
|
const SkRect& dst, const SkPaint* paint) {
|
|
fDL->drawImageLattice(SkImage::MakeFromBitmap(bm), lattice, dst, paint, BitmapPalette::Unknown);
|
|
}
|
|
|
|
void RecordingCanvas::drawImage(const sk_sp<SkImage>& image, SkScalar x, SkScalar y,
|
|
const SkPaint* paint, BitmapPalette palette) {
|
|
fDL->drawImage(image, x, y, paint, palette);
|
|
}
|
|
|
|
void RecordingCanvas::drawImageRect(const sk_sp<SkImage>& image, const SkRect& src,
|
|
const SkRect& dst, const SkPaint* paint,
|
|
SrcRectConstraint constraint, BitmapPalette palette) {
|
|
fDL->drawImageRect(image, &src, dst, paint, constraint, palette);
|
|
}
|
|
|
|
void RecordingCanvas::drawImageLattice(const sk_sp<SkImage>& image, const Lattice& lattice,
|
|
const SkRect& dst, const SkPaint* paint,
|
|
BitmapPalette palette) {
|
|
if (!image || dst.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
SkIRect bounds;
|
|
Lattice latticePlusBounds = lattice;
|
|
if (!latticePlusBounds.fBounds) {
|
|
bounds = SkIRect::MakeWH(image->width(), image->height());
|
|
latticePlusBounds.fBounds = &bounds;
|
|
}
|
|
|
|
if (SkLatticeIter::Valid(image->width(), image->height(), latticePlusBounds)) {
|
|
fDL->drawImageLattice(image, latticePlusBounds, dst, paint, palette);
|
|
} else {
|
|
fDL->drawImageRect(image, nullptr, dst, paint, SrcRectConstraint::kFast_SrcRectConstraint,
|
|
palette);
|
|
}
|
|
}
|
|
|
|
void RecordingCanvas::onDrawImage(const SkImage* img, SkScalar x, SkScalar y,
|
|
const SkPaint* paint) {
|
|
fDL->drawImage(sk_ref_sp(img), x, y, paint, BitmapPalette::Unknown);
|
|
}
|
|
void RecordingCanvas::onDrawImageNine(const SkImage* img, const SkIRect& center, const SkRect& dst,
|
|
const SkPaint* paint) {
|
|
fDL->drawImageNine(sk_ref_sp(img), center, dst, paint);
|
|
}
|
|
void RecordingCanvas::onDrawImageRect(const SkImage* img, const SkRect* src, const SkRect& dst,
|
|
const SkPaint* paint, SrcRectConstraint constraint) {
|
|
fDL->drawImageRect(sk_ref_sp(img), src, dst, paint, constraint, BitmapPalette::Unknown);
|
|
}
|
|
void RecordingCanvas::onDrawImageLattice(const SkImage* img, const SkCanvas::Lattice& lattice,
|
|
const SkRect& dst, const SkPaint* paint) {
|
|
fDL->drawImageLattice(sk_ref_sp(img), lattice, dst, paint, BitmapPalette::Unknown);
|
|
}
|
|
|
|
void RecordingCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
|
|
const SkPoint texCoords[4], SkBlendMode bmode,
|
|
const SkPaint& paint) {
|
|
fDL->drawPatch(cubics, colors, texCoords, bmode, paint);
|
|
}
|
|
void RecordingCanvas::onDrawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[],
|
|
const SkPaint& paint) {
|
|
fDL->drawPoints(mode, count, pts, paint);
|
|
}
|
|
void RecordingCanvas::onDrawVerticesObject(const SkVertices* vertices,
|
|
const SkVertices::Bone bones[], int boneCount,
|
|
SkBlendMode mode, const SkPaint& paint) {
|
|
fDL->drawVertices(vertices, bones, boneCount, mode, paint);
|
|
}
|
|
void RecordingCanvas::onDrawAtlas(const SkImage* atlas, const SkRSXform xforms[],
|
|
const SkRect texs[], const SkColor colors[], int count,
|
|
SkBlendMode bmode, const SkRect* cull, const SkPaint* paint) {
|
|
fDL->drawAtlas(atlas, xforms, texs, colors, count, bmode, cull, paint);
|
|
}
|
|
void RecordingCanvas::onDrawShadowRec(const SkPath& path, const SkDrawShadowRec& rec) {
|
|
fDL->drawShadowRec(path, rec);
|
|
}
|
|
|
|
void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
|
|
fDL->drawVectorDrawable(tree);
|
|
}
|
|
|
|
} // namespace uirenderer
|
|
} // namespace android
|