diff options
-rw-r--r-- | libs/hwui/Android.bp | 1 | ||||
-rw-r--r-- | libs/hwui/CanvasTransform.cpp | 75 | ||||
-rw-r--r-- | libs/hwui/CanvasTransform.h | 4 | ||||
-rw-r--r-- | libs/hwui/DisplayListOps.in | 52 | ||||
-rw-r--r-- | libs/hwui/RecordingCanvas.cpp | 934 | ||||
-rw-r--r-- | libs/hwui/RecordingCanvas.h | 203 | ||||
-rw-r--r-- | libs/hwui/RenderNode.cpp | 14 | ||||
-rw-r--r-- | libs/hwui/RenderNode.h | 8 | ||||
-rw-r--r-- | libs/hwui/hwui/Bitmap.cpp | 41 | ||||
-rw-r--r-- | libs/hwui/hwui/Bitmap.h | 3 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaDisplayList.h | 7 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp | 10 | ||||
-rw-r--r-- | libs/hwui/pipeline/skia/SkiaRecordingCanvas.h | 5 | ||||
-rw-r--r-- | libs/hwui/tests/unit/RenderNodeDrawableTests.cpp | 6 | ||||
-rw-r--r-- | libs/hwui/tests/unit/SkiaDisplayListTests.cpp | 50 | ||||
-rw-r--r-- | libs/hwui/tests/unit/SkiaPipelineTests.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp | 1 | ||||
-rw-r--r-- | libs/hwui/utils/LinearAllocator.cpp | 10 | ||||
-rw-r--r-- | libs/hwui/utils/Macros.h | 9 | ||||
-rw-r--r-- | libs/hwui/utils/TypeLogic.h | 40 |
20 files changed, 1349 insertions, 125 deletions
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp index 62ab7900737e..b7ffb5d9dc2e 100644 --- a/libs/hwui/Android.bp +++ b/libs/hwui/Android.bp @@ -223,6 +223,7 @@ cc_defaults { "Properties.cpp", "PropertyValuesAnimatorSet.cpp", "PropertyValuesHolder.cpp", + "RecordingCanvas.cpp", "RenderNode.cpp", "RenderProperties.cpp", "ResourceCache.cpp", diff --git a/libs/hwui/CanvasTransform.cpp b/libs/hwui/CanvasTransform.cpp index 1b15dbd526cc..adcdc18ab418 100644 --- a/libs/hwui/CanvasTransform.cpp +++ b/libs/hwui/CanvasTransform.cpp @@ -15,16 +15,20 @@ */ #include "CanvasTransform.h" -#include "utils/Color.h" #include "Properties.h" +#include "utils/Color.h" -#include <ui/ColorSpace.h> #include <SkColorFilter.h> +#include <SkGradientShader.h> #include <SkPaint.h> +#include <SkShader.h> +#include <ui/ColorSpace.h> #include <algorithm> #include <cmath> +#include <log/log.h> + namespace android::uirenderer { static SkColor makeLight(SkColor color) { @@ -66,6 +70,32 @@ static void applyColorTransform(ColorTransform transform, SkPaint& paint) { SkColor newColor = transformColor(transform, paint.getColor()); paint.setColor(newColor); + if (paint.getShader()) { + SkShader::GradientInfo info; + std::array<SkColor, 10> _colorStorage; + std::array<SkScalar, _colorStorage.size()> _offsetStorage; + info.fColorCount = _colorStorage.size(); + info.fColors = _colorStorage.data(); + info.fColorOffsets = _offsetStorage.data(); + SkShader::GradientType type = paint.getShader()->asAGradient(&info); + ALOGW_IF(type, "Found gradient of type = %d", type); + + if (info.fColorCount <= 10) { + switch (type) { + case SkShader::kLinear_GradientType: + for (int i = 0; i < info.fColorCount; i++) { + info.fColors[i] = transformColor(transform, info.fColors[i]); + } + paint.setShader(SkGradientShader::MakeLinear(info.fPoint, info.fColors, + info.fColorOffsets, info.fColorCount, + info.fTileMode, info.fGradientFlags, nullptr)); + break; + default:break; + } + + } + } + if (paint.getColorFilter()) { SkBlendMode mode; SkColor color; @@ -77,43 +107,10 @@ static void applyColorTransform(ColorTransform transform, SkPaint& paint) { } } -class ColorFilterCanvas : public SkPaintFilterCanvas { -public: - ColorFilterCanvas(ColorTransform transform, SkCanvas* canvas) - : SkPaintFilterCanvas(canvas), mTransform(transform) {} - - bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type type) const override { - if (*paint) { - applyColorTransform(mTransform, *(paint->writable())); - } - return true; - } - -private: - ColorTransform mTransform; -}; - -std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, ColorTransform transform) { - switch (transform) { - case ColorTransform::Light: - return std::make_unique<ColorFilterCanvas>(ColorTransform::Light, inCanvas); - case ColorTransform::Dark: - return std::make_unique<ColorFilterCanvas>(ColorTransform::Dark, inCanvas); - default: - return nullptr; - } -} - -std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, UsageHint usageHint) { - if (Properties::forceDarkMode) { - switch (usageHint) { - case UsageHint::Unknown: - return makeTransformCanvas(inCanvas, ColorTransform::Light); - case UsageHint::Background: - return makeTransformCanvas(inCanvas, ColorTransform::Dark); - } - } - return nullptr; +bool transformPaint(ColorTransform transform, SkPaint* paint) { + // TODO + applyColorTransform(transform, *paint); + return true; } }; // namespace android::uirenderer
\ No newline at end of file diff --git a/libs/hwui/CanvasTransform.h b/libs/hwui/CanvasTransform.h index f71fdfaf3fba..32d9a0594879 100644 --- a/libs/hwui/CanvasTransform.h +++ b/libs/hwui/CanvasTransform.h @@ -34,7 +34,7 @@ enum class ColorTransform { Dark, }; -std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, ColorTransform transform); -std::unique_ptr<SkCanvas> makeTransformCanvas(SkCanvas* inCanvas, UsageHint usageHint); +// True if the paint was modified, false otherwise +bool transformPaint(ColorTransform transform, SkPaint* paint); } // namespace android::uirenderer;
\ No newline at end of file diff --git a/libs/hwui/DisplayListOps.in b/libs/hwui/DisplayListOps.in new file mode 100644 index 000000000000..f61c1562c6a7 --- /dev/null +++ b/libs/hwui/DisplayListOps.in @@ -0,0 +1,52 @@ +/* + * 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. + */ + +X(Flush) +X(Save) +X(Restore) +X(SaveLayer) +X(Concat) +X(SetMatrix) +X(Translate) +X(ClipPath) +X(ClipRect) +X(ClipRRect) +X(ClipRegion) +X(DrawPaint) +X(DrawPath) +X(DrawRect) +X(DrawRegion) +X(DrawOval) +X(DrawArc) +X(DrawRRect) +X(DrawDRRect) +X(DrawAnnotation) +X(DrawDrawable) +X(DrawPicture) +X(DrawImage) +X(DrawImageNine) +X(DrawImageRect) +X(DrawImageLattice) +X(DrawText) +X(DrawPosText) +X(DrawPosTextH) +X(DrawTextRSXform) +X(DrawTextBlob) +X(DrawPatch) +X(DrawPoints) +X(DrawVertices) +X(DrawAtlas) +X(DrawShadowRec)
\ No newline at end of file diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp new file mode 100644 index 000000000000..57befc6fa9d7 --- /dev/null +++ b/libs/hwui/RecordingCanvas.cpp @@ -0,0 +1,934 @@ +/* + * 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 "SkCanvas.h" +#include "SkData.h" +#include "SkDrawShadowInfo.h" +#include "SkImage.h" +#include "SkImageFilter.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 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) + : image(std::move(image)), x(x), y(y) { + if (paint) { + this->paint = *paint; + } + } + sk_sp<const SkImage> image; + SkScalar x, y; + SkPaint paint; + 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) + : image(std::move(image)), dst(dst), constraint(constraint) { + this->src = src ? *src : SkRect::MakeIWH(image->width(), image->height()); + if (paint) { + this->paint = *paint; + } + } + sk_sp<const SkImage> image; + SkRect src, dst; + SkPaint paint; + SkCanvas::SrcRectConstraint constraint; + 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) + : image(std::move(image)), xs(xs), ys(ys), fs(fs), src(src), dst(dst) { + if (paint) { + this->paint = *paint; + } + } + sk_sp<const SkImage> image; + int xs, ys, fs; + SkIRect src; + SkRect dst; + SkPaint paint; + 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 DrawText final : Op { + static const auto kType = Type::DrawText; + DrawText(size_t bytes, SkScalar x, SkScalar y, const SkPaint& paint) + : bytes(bytes), x(x), y(y), paint(paint) {} + size_t bytes; + SkScalar x, y; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { + c->drawText(pod<void>(this), bytes, x, y, paint); + } +}; +struct DrawPosText final : Op { + static const auto kType = Type::DrawPosText; + DrawPosText(size_t bytes, const SkPaint& paint, int n) : bytes(bytes), paint(paint), n(n) {} + size_t bytes; + SkPaint paint; + int n; + void draw(SkCanvas* c, const SkMatrix&) const { + auto points = pod<SkPoint>(this); + auto text = pod<void>(this, n * sizeof(SkPoint)); + c->drawPosText(text, bytes, points, paint); + } +}; +struct DrawPosTextH final : Op { + static const auto kType = Type::DrawPosTextH; + DrawPosTextH(size_t bytes, SkScalar y, const SkPaint& paint, int n) + : bytes(bytes), y(y), paint(paint), n(n) {} + size_t bytes; + SkScalar y; + SkPaint paint; + int n; + void draw(SkCanvas* c, const SkMatrix&) const { + auto xs = pod<SkScalar>(this); + auto text = pod<void>(this, n * sizeof(SkScalar)); + c->drawPosTextH(text, bytes, xs, y, paint); + } +}; +struct DrawTextRSXform final : Op { + static const auto kType = Type::DrawTextRSXform; + DrawTextRSXform(size_t bytes, int xforms, const SkRect* cull, const SkPaint& paint) + : bytes(bytes), xforms(xforms), paint(paint) { + if (cull) { + this->cull = *cull; + } + } + size_t bytes; + int xforms; + SkRect cull = kUnset; + SkPaint paint; + void draw(SkCanvas* c, const SkMatrix&) const { + // For alignment, the SkRSXforms are first in the pod section, followed by the text. + c->drawTextRSXform(pod<void>(this, xforms * sizeof(SkRSXform)), bytes, pod<SkRSXform>(this), + maybe_unset(cull), 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); } +}; +} + +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::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) { + this->push<DrawImage>(0, std::move(image), x, y, paint); +} +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) { + this->push<DrawImageRect>(0, std::move(image), src, dst, paint, constraint); +} +void DisplayListData::drawImageLattice(sk_sp<const SkImage> image, const SkCanvas::Lattice& lattice, + const SkRect& dst, const SkPaint* paint) { + 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); + copy_v(pod, lattice.fXDivs, xs, lattice.fYDivs, ys, lattice.fColors, fs, lattice.fRectTypes, + fs); +} + +void DisplayListData::drawText(const void* text, size_t bytes, SkScalar x, SkScalar y, + const SkPaint& paint) { + void* pod = this->push<DrawText>(bytes, bytes, x, y, paint); + copy_v(pod, (const char*)text, bytes); +} +void DisplayListData::drawPosText(const void* text, size_t bytes, const SkPoint pos[], + const SkPaint& paint) { + int n = paint.countText(text, bytes); + void* pod = this->push<DrawPosText>(n * sizeof(SkPoint) + bytes, bytes, paint, n); + copy_v(pod, pos, n, (const char*)text, bytes); +} +void DisplayListData::drawPosTextH(const void* text, size_t bytes, const SkScalar xs[], SkScalar y, + const SkPaint& paint) { + int n = paint.countText(text, bytes); + void* pod = this->push<DrawPosTextH>(n * sizeof(SkScalar) + bytes, bytes, y, paint, n); + copy_v(pod, xs, n, (const char*)text, bytes); +} +void DisplayListData::drawTextRSXform(const void* text, size_t bytes, const SkRSXform xforms[], + const SkRect* cull, const SkPaint& paint) { + int n = paint.countText(text, bytes); + void* pod = this->push<DrawTextRSXform>(bytes + n * sizeof(SkRSXform), bytes, n, cull, paint); + copy_v(pod, xforms, n, (const char*)text, bytes); +} +void DisplayListData::drawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, + const SkPaint& paint) { + this->push<DrawTextBlob>(0, blob, x, y, paint); +} + +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); +} + +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_t = decltype(std::declval<T>().paint); + +template <class T> +constexpr color_transform_fn colorTransformForOp() { + if + constexpr(std::experimental::is_detected_v<has_paint_t, T>) { + return [](const void* op, ColorTransform transform) { + // TODO: We should be const. Or not. Or just use a different map + // Unclear, but this is the quick fix + transformPaint(transform, + const_cast<SkPaint*>(&(reinterpret_cast<const T*>(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; +} + +sk_sp<SkSurface> RecordingCanvas::onNewSurface(const SkImageInfo&, const SkSurfaceProps&) { + return nullptr; +} + +void RecordingCanvas::onFlush() { + fDL->flush(); +} + +void RecordingCanvas::willSave() { + 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() { + fDL->restore(); +} + +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); + this->INHERITED::onClipRect(rect, op, style); +} +void RecordingCanvas::onClipRRect(const SkRRect& rrect, SkClipOp op, ClipEdgeStyle style) { + fDL->clipRRect(rrect, op, style == kSoft_ClipEdgeStyle); + this->INHERITED::onClipRRect(rrect, op, style); +} +void RecordingCanvas::onClipPath(const SkPath& path, SkClipOp op, ClipEdgeStyle style) { + fDL->clipPath(path, op, style == kSoft_ClipEdgeStyle); + this->INHERITED::onClipPath(path, op, style); +} +void RecordingCanvas::onClipRegion(const SkRegion& region, SkClipOp op) { + 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::onDrawText(const void* text, size_t bytes, SkScalar x, SkScalar y, + const SkPaint& paint) { + fDL->drawText(text, bytes, x, y, paint); +} +void RecordingCanvas::onDrawPosText(const void* text, size_t bytes, const SkPoint pos[], + const SkPaint& paint) { + fDL->drawPosText(text, bytes, pos, paint); +} +void RecordingCanvas::onDrawPosTextH(const void* text, size_t bytes, const SkScalar xs[], + SkScalar y, const SkPaint& paint) { + fDL->drawPosTextH(text, bytes, xs, y, paint); +} +void RecordingCanvas::onDrawTextRSXform(const void* text, size_t bytes, const SkRSXform xform[], + const SkRect* cull, const SkPaint& paint) { + fDL->drawTextRSXform(text, bytes, xform, cull, paint); +} +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); +} +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); +} +void RecordingCanvas::onDrawBitmapLattice(const SkBitmap& bm, const SkCanvas::Lattice& lattice, + const SkRect& dst, const SkPaint* paint) { + fDL->drawImageLattice(SkImage::MakeFromBitmap(bm), lattice, dst, paint); +} + +void RecordingCanvas::onDrawImage(const SkImage* img, SkScalar x, SkScalar y, + const SkPaint* paint) { + fDL->drawImage(sk_ref_sp(img), x, y, paint); +} +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); +} +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); +} + +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); +} + +}; // namespace uirenderer +}; // namespace android diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h new file mode 100644 index 000000000000..32ce1d333448 --- /dev/null +++ b/libs/hwui/RecordingCanvas.h @@ -0,0 +1,203 @@ +/* + * 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. + */ + +#pragma once + +#include "CanvasTransform.h" +#include "hwui/Canvas.h" +#include "utils/Macros.h" +#include "utils/TypeLogic.h" + +#include "SkCanvas.h" +#include "SkCanvasVirtualEnforcer.h" +#include "SkDrawable.h" +#include "SkNoDrawCanvas.h" +#include "SkPaint.h" +#include "SkPath.h" +#include "SkRect.h" +#include "SkTDArray.h" +#include "SkTemplates.h" + +#include <vector> + +namespace android { +namespace uirenderer { + +enum class DisplayListOpType : uint8_t { +#define X(T) T, +#include "DisplayListOps.in" +#undef X +}; + +struct DisplayListOp { + const uint8_t type : 8; + const uint32_t skip : 24; +}; + +static_assert(sizeof(DisplayListOp) == 4); + +class RecordingCanvas; + +class DisplayListData final { +public: + ~DisplayListData(); + + void draw(SkCanvas* canvas) const; + + void reset(); + bool empty() const { return fUsed == 0; } + + void applyColorTransform(ColorTransform transform); + +private: + friend class RecordingCanvas; + + void flush(); + + void save(); + void saveLayer(const SkRect*, const SkPaint*, const SkImageFilter*, const SkImage*, + const SkMatrix*, SkCanvas::SaveLayerFlags); + void restore(); + + void concat(const SkMatrix&); + void setMatrix(const SkMatrix&); + void translate(SkScalar, SkScalar); + void translateZ(SkScalar); + + void clipPath(const SkPath&, SkClipOp, bool aa); + void clipRect(const SkRect&, SkClipOp, bool aa); + void clipRRect(const SkRRect&, SkClipOp, bool aa); + void clipRegion(const SkRegion&, SkClipOp); + + void drawPaint(const SkPaint&); + void drawPath(const SkPath&, const SkPaint&); + void drawRect(const SkRect&, const SkPaint&); + void drawRegion(const SkRegion&, const SkPaint&); + void drawOval(const SkRect&, const SkPaint&); + void drawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&); + void drawRRect(const SkRRect&, const SkPaint&); + void drawDRRect(const SkRRect&, const SkRRect&, const SkPaint&); + + void drawAnnotation(const SkRect&, const char*, SkData*); + void drawDrawable(SkDrawable*, const SkMatrix*); + void drawPicture(const SkPicture*, const SkMatrix*, const SkPaint*); + + void drawText(const void*, size_t, SkScalar, SkScalar, const SkPaint&); + void drawPosText(const void*, size_t, const SkPoint[], const SkPaint&); + void drawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&); + void drawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, const SkPaint&); + void drawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&); + + void drawImage(sk_sp<const SkImage>, SkScalar, SkScalar, const SkPaint*); + void drawImageNine(sk_sp<const SkImage>, const SkIRect&, const SkRect&, const SkPaint*); + void drawImageRect(sk_sp<const SkImage>, const SkRect*, const SkRect&, const SkPaint*, + SkCanvas::SrcRectConstraint); + void drawImageLattice(sk_sp<const SkImage>, const SkCanvas::Lattice&, const SkRect&, + const SkPaint*); + + void drawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, + const SkPaint&); + void drawPoints(SkCanvas::PointMode, size_t, const SkPoint[], const SkPaint&); + void drawVertices(const SkVertices*, const SkVertices::Bone bones[], int boneCount, SkBlendMode, + const SkPaint&); + void drawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, + SkBlendMode, const SkRect*, const SkPaint*); + void drawShadowRec(const SkPath&, const SkDrawShadowRec&); + + template <typename T, typename... Args> + void* push(size_t, Args&&...); + + template <typename Fn, typename... Args> + void map(const Fn[], Args...) const; + + SkAutoTMalloc<uint8_t> fBytes; + size_t fUsed = 0; + size_t fReserved = 0; +}; + +class RecordingCanvas final : public SkCanvasVirtualEnforcer<SkNoDrawCanvas> { +public: + RecordingCanvas(); + void reset(DisplayListData*, const SkIRect& bounds); + + sk_sp<SkSurface> onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override; + + void willSave() override; + SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override; + void willRestore() override; + + void onFlush() override; + + void didConcat(const SkMatrix&) override; + void didSetMatrix(const SkMatrix&) override; + void didTranslate(SkScalar, SkScalar) override; + + void onClipRect(const SkRect&, SkClipOp, ClipEdgeStyle) override; + void onClipRRect(const SkRRect&, SkClipOp, ClipEdgeStyle) override; + void onClipPath(const SkPath&, SkClipOp, ClipEdgeStyle) override; + void onClipRegion(const SkRegion&, SkClipOp) override; + + void onDrawPaint(const SkPaint&) override; + void onDrawPath(const SkPath&, const SkPaint&) override; + void onDrawRect(const SkRect&, const SkPaint&) override; + void onDrawRegion(const SkRegion&, const SkPaint&) override; + void onDrawOval(const SkRect&, const SkPaint&) override; + void onDrawArc(const SkRect&, SkScalar, SkScalar, bool, const SkPaint&) override; + void onDrawRRect(const SkRRect&, const SkPaint&) override; + void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override; + + void onDrawDrawable(SkDrawable*, const SkMatrix*) override; + void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override; + void onDrawAnnotation(const SkRect&, const char[], SkData*) override; + + void onDrawText(const void*, size_t, SkScalar x, SkScalar y, const SkPaint&) override; + void onDrawPosText(const void*, size_t, const SkPoint[], const SkPaint&) override; + void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override; + + void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*, + const SkPaint&) override; + void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override; + + void onDrawBitmap(const SkBitmap&, SkScalar, SkScalar, const SkPaint*) override; + void onDrawBitmapLattice(const SkBitmap&, const Lattice&, const SkRect&, + const SkPaint*) override; + void onDrawBitmapNine(const SkBitmap&, const SkIRect&, const SkRect&, const SkPaint*) override; + void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*, + SrcRectConstraint) override; + + void onDrawImage(const SkImage*, SkScalar, SkScalar, const SkPaint*) override; + void onDrawImageLattice(const SkImage*, const Lattice&, const SkRect&, const SkPaint*) override; + void onDrawImageNine(const SkImage*, const SkIRect&, const SkRect&, const SkPaint*) override; + void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*, + SrcRectConstraint) override; + + void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkBlendMode, + const SkPaint&) override; + void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override; + void onDrawVerticesObject(const SkVertices*, const SkVertices::Bone bones[], int boneCount, + SkBlendMode, const SkPaint&) override; + void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int, + SkBlendMode, const SkRect*, const SkPaint*) override; + void onDrawShadowRec(const SkPath&, const SkDrawShadowRec&) override; + +private: + typedef SkCanvasVirtualEnforcer<SkNoDrawCanvas> INHERITED; + + DisplayListData* fDL; +}; + +}; // namespace uirenderer +}; // namespace android
\ No newline at end of file diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index a2e1f6041b62..d5afb2011429 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -272,6 +272,20 @@ void RenderNode::syncDisplayList(TreeObserver& observer, TreeInfo* info) { mStagingDisplayList = nullptr; if (mDisplayList) { mDisplayList->syncContents(); + if (CC_UNLIKELY(Properties::forceDarkMode)) { + auto usage = usageHint(); + if (usage == UsageHint::Unknown) { + if (mDisplayList->mChildNodes.size() > 1) { + usage = UsageHint::Background; + } else if (mDisplayList->mChildNodes.size() == 1 && + mDisplayList->mChildNodes.front().getRenderNode()->usageHint() != + UsageHint::Background) { + usage = UsageHint::Background; + } + } + mDisplayList->mDisplayList.applyColorTransform( + usage == UsageHint::Background ? ColorTransform::Dark : ColorTransform::Light); + } } } diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h index 8393288d2ffd..83b0c2278151 100644 --- a/libs/hwui/RenderNode.h +++ b/libs/hwui/RenderNode.h @@ -209,13 +209,9 @@ public: void output(std::ostream& output, uint32_t level); - void setUsageHint(UsageHint usageHint) { - mUsageHint = usageHint; - } + void setUsageHint(UsageHint usageHint) { mUsageHint = usageHint; } - UsageHint usageHint() const { - return mUsageHint; - } + UsageHint usageHint() const { return mUsageHint; } private: void computeOrderingImpl(RenderNodeOp* opState, diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp index e7d12de44c0c..3939696692d2 100644 --- a/libs/hwui/hwui/Bitmap.cpp +++ b/libs/hwui/hwui/Bitmap.cpp @@ -34,8 +34,8 @@ #include <SkImagePriv.h> #include <SkToSRGBColorFilter.h> -#include <limits> #include <SkHighContrastFilter.h> +#include <limits> namespace android { @@ -333,17 +333,17 @@ sk_sp<SkImage> Bitmap::makeImage(sk_sp<SkColorFilter>* outputColorFilter) { // TODO: Move this to the canvas (or other?) layer where we have the target lightness // mode and can selectively do the right thing. - if (palette() != BitmapPalette::Unknown && uirenderer::Properties::forceDarkMode) { - SkHighContrastConfig config; - config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness; - *outputColorFilter = SkHighContrastFilter::Make(config)->makeComposed(*outputColorFilter); - } + // if (palette() != BitmapPalette::Unknown && uirenderer::Properties::forceDarkMode) { + // SkHighContrastConfig config; + // config.fInvertStyle = SkHighContrastConfig::InvertStyle::kInvertLightness; + // *outputColorFilter = + // SkHighContrastFilter::Make(config)->makeComposed(*outputColorFilter); + // } return image; } class MinMaxAverage { public: - void add(float sample) { if (mCount == 0) { mMin = sample; @@ -356,21 +356,13 @@ public: mCount++; } - float average() { - return mTotal / mCount; - } + float average() { return mTotal / mCount; } - float min() { - return mMin; - } + float min() { return mMin; } - float max() { - return mMax; - } + float max() { return mMax; } - float delta() { - return mMax - mMin; - } + float delta() { return mMax - mMin; } private: float mMin = 0.0f; @@ -413,14 +405,15 @@ BitmapPalette Bitmap::computePalette(const SkImageInfo& info, const void* addr, // TODO: Tune the coverage threshold if (sampledCount < 5) { ALOGV("Not enough samples, only found %d for image sized %dx%d, format = %d, alpha = %d", - sampledCount, info.width(), info.height(), (int) info.colorType(), (int) info.alphaType()); + sampledCount, info.width(), info.height(), (int)info.colorType(), + (int)info.alphaType()); return BitmapPalette::Unknown; } - ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = %f]", - sampledCount, - hue.min(), hue.max(), hue.average(), - saturation.min(), saturation.max(), saturation.average()); + ALOGV("samples = %d, hue [min = %f, max = %f, avg = %f]; saturation [min = %f, max = %f, avg = " + "%f]", + sampledCount, hue.min(), hue.max(), hue.average(), saturation.min(), saturation.max(), + saturation.average()); if (hue.delta() <= 20 && saturation.delta() <= .1f) { if (value.average() >= .5f) { diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h index d2680429a1e9..170335da7d7c 100644 --- a/libs/hwui/hwui/Bitmap.h +++ b/libs/hwui/hwui/Bitmap.h @@ -69,7 +69,8 @@ public: Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info, size_t rowBytes); Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes); - Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, BitmapPalette palette = BitmapPalette::Unknown); + Bitmap(GraphicBuffer* buffer, const SkImageInfo& info, + BitmapPalette palette = BitmapPalette::Unknown); int rowBytesAsPixels() const { return rowBytes() >> mInfo.shiftPerPixel(); } diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h index 6eff5895a620..4f30f98e147d 100644 --- a/libs/hwui/pipeline/skia/SkiaDisplayList.h +++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h @@ -18,12 +18,11 @@ #include "hwui/AnimatedImageDrawable.h" #include "GLFunctorDrawable.h" +#include "RecordingCanvas.h" #include "RenderNodeDrawable.h" #include "TreeInfo.h" #include "utils/LinearAllocator.h" -#include <SkLiteDL.h> -#include <SkLiteRecorder.h> #include <deque> namespace android { @@ -140,7 +139,7 @@ public: */ inline bool containsProjectionReceiver() const { return mProjectionReceiver; } - void attachRecorder(SkLiteRecorder* recorder, const SkIRect& bounds) { + void attachRecorder(RecordingCanvas* recorder, const SkIRect& bounds) { recorder->reset(&mDisplayList, bounds); } @@ -160,7 +159,7 @@ public: std::vector<SkImage*> mMutableImages; std::vector<VectorDrawableRoot*> mVectorDrawables; std::vector<AnimatedImageDrawable*> mAnimatedImages; - SkLiteDL mDisplayList; + DisplayListData mDisplayList; // mProjectionReceiver points to a child node (stored in mChildNodes) that is as a projection // receiver. It is set at record time and used at both prepare and draw tree traversals to diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp index b9748afc6cb4..83d7e6a361bc 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp @@ -45,21 +45,13 @@ void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, in } mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height)); - SkCanvas* canvas = &mRecorder; - if (renderNode) { - mWrappedCanvas = makeTransformCanvas(&mRecorder, renderNode->usageHint()); - if (mWrappedCanvas) { - canvas = mWrappedCanvas.get(); - } - } - SkiaCanvas::reset(canvas); + SkiaCanvas::reset(&mRecorder); } uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() { // close any existing chunks if necessary insertReorderBarrier(false); mRecorder.restoreToCount(1); - mWrappedCanvas = nullptr; return mDisplayList.release(); } diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h index 50d84d6cf101..988728dfe23e 100644 --- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h +++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h @@ -15,7 +15,7 @@ */ #pragma once -#include <SkLiteRecorder.h> +#include "RecordingCanvas.h" #include "ReorderBarrierDrawables.h" #include "SkiaCanvas.h" #include "SkiaDisplayList.h" @@ -76,9 +76,8 @@ public: uirenderer::GlFunctorLifecycleListener* listener) override; private: - SkLiteRecorder mRecorder; + RecordingCanvas mRecorder; std::unique_ptr<SkiaDisplayList> mDisplayList; - std::unique_ptr<SkCanvas> mWrappedCanvas; StartReorderBarrierDrawable* mCurrentBarrier; /** diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp index eb67e6cf33b6..48bc8e4df155 100644 --- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp @@ -18,13 +18,13 @@ #include <gtest/gtest.h> #include <SkClipStack.h> -#include <SkLiteRecorder.h> #include <SkSurface_Base.h> #include <string.h> #include "AnimationContext.h" #include "DamageAccumulator.h" #include "FatalTestCanvas.h" #include "IContextFactory.h" +#include "RecordingCanvas.h" #include "SkiaCanvas.h" #include "pipeline/skia/SkiaDisplayList.h" #include "pipeline/skia/SkiaOpenGLPipeline.h" @@ -44,8 +44,8 @@ TEST(RenderNodeDrawable, create) { canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver); }); - SkLiteDL skLiteDL; - SkLiteRecorder canvas; + DisplayListData skLiteDL; + RecordingCanvas canvas; canvas.reset(&skLiteDL, SkIRect::MakeWH(1, 1)); canvas.translate(100, 100); RenderNodeDrawable drawable(rootNode.get(), &canvas); diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp index 88d6dcf990a5..6c398eea895f 100644 --- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp +++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp @@ -36,32 +36,36 @@ TEST(SkiaDisplayList, create) { } TEST(SkiaDisplayList, reset) { - SkiaDisplayList skiaDL; + std::unique_ptr<SkiaDisplayList> skiaDL; + { + SkiaRecordingCanvas canvas{nullptr, 1, 1}; + canvas.drawColor(0, SkBlendMode::kSrc); + skiaDL.reset(canvas.finishRecording()); + } SkCanvas dummyCanvas; RenderNodeDrawable drawable(nullptr, &dummyCanvas); - skiaDL.mChildNodes.emplace_back(nullptr, &dummyCanvas); - skiaDL.mChildFunctors.emplace_back(nullptr, nullptr, &dummyCanvas); - skiaDL.mMutableImages.push_back(nullptr); - skiaDL.mVectorDrawables.push_back(nullptr); - skiaDL.mDisplayList.drawAnnotation(SkRect::MakeWH(200, 200), "testAnnotation", nullptr); - skiaDL.mProjectionReceiver = &drawable; - - ASSERT_FALSE(skiaDL.mChildNodes.empty()); - ASSERT_FALSE(skiaDL.mChildFunctors.empty()); - ASSERT_FALSE(skiaDL.mMutableImages.empty()); - ASSERT_FALSE(skiaDL.mVectorDrawables.empty()); - ASSERT_FALSE(skiaDL.isEmpty()); - ASSERT_TRUE(skiaDL.mProjectionReceiver); - - skiaDL.reset(); - - ASSERT_TRUE(skiaDL.mChildNodes.empty()); - ASSERT_TRUE(skiaDL.mChildFunctors.empty()); - ASSERT_TRUE(skiaDL.mMutableImages.empty()); - ASSERT_TRUE(skiaDL.mVectorDrawables.empty()); - ASSERT_TRUE(skiaDL.isEmpty()); - ASSERT_FALSE(skiaDL.mProjectionReceiver); + skiaDL->mChildNodes.emplace_back(nullptr, &dummyCanvas); + skiaDL->mChildFunctors.emplace_back(nullptr, nullptr, &dummyCanvas); + skiaDL->mMutableImages.push_back(nullptr); + skiaDL->mVectorDrawables.push_back(nullptr); + skiaDL->mProjectionReceiver = &drawable; + + ASSERT_FALSE(skiaDL->mChildNodes.empty()); + ASSERT_FALSE(skiaDL->mChildFunctors.empty()); + ASSERT_FALSE(skiaDL->mMutableImages.empty()); + ASSERT_FALSE(skiaDL->mVectorDrawables.empty()); + ASSERT_FALSE(skiaDL->isEmpty()); + ASSERT_TRUE(skiaDL->mProjectionReceiver); + + skiaDL->reset(); + + ASSERT_TRUE(skiaDL->mChildNodes.empty()); + ASSERT_TRUE(skiaDL->mChildFunctors.empty()); + ASSERT_TRUE(skiaDL->mMutableImages.empty()); + ASSERT_TRUE(skiaDL->mVectorDrawables.empty()); + ASSERT_TRUE(skiaDL->isEmpty()); + ASSERT_FALSE(skiaDL->mProjectionReceiver); } TEST(SkiaDisplayList, reuseDisplayList) { diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp index 26b6000a91e6..a9124d90f9a5 100644 --- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp +++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp @@ -18,7 +18,6 @@ #include <gtest/gtest.h> #include <SkClipStack.h> -#include <SkLiteRecorder.h> #include <SkSurface_Base.h> #include <string.h> #include "AnimationContext.h" diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp index ad5fdacc8594..479c462bd1a6 100644 --- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp +++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp @@ -18,7 +18,6 @@ #include <gtest/gtest.h> #include <SkClipStack.h> -#include <SkLiteRecorder.h> #include <SkSurface_Base.h> #include <string.h> #include "AnimationContext.h" diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp index 5a59de8b922a..3e5021cd45d4 100644 --- a/libs/hwui/utils/LinearAllocator.cpp +++ b/libs/hwui/utils/LinearAllocator.cpp @@ -29,6 +29,7 @@ #include <stdlib.h> #include <utils/Log.h> +#include <utils/Macros.h> // The ideal size of a page allocation (these need to be multiples of 8) #define INITIAL_PAGE_SIZE ((size_t)512) // 512b @@ -41,15 +42,6 @@ // Must be smaller than INITIAL_PAGE_SIZE #define MAX_WASTE_RATIO (0.5f) -#if ALIGN_DOUBLE -#define ALIGN_SZ (sizeof(double)) -#else -#define ALIGN_SZ (sizeof(int)) -#endif - -#define ALIGN(x) (((x) + ALIGN_SZ - 1) & ~(ALIGN_SZ - 1)) -#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)(p)))) - #if LOG_NDEBUG #define ADD_ALLOCATION() #define RM_ALLOCATION() diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h index d758f29d6dcb..eee6785afd53 100644 --- a/libs/hwui/utils/Macros.h +++ b/libs/hwui/utils/Macros.h @@ -34,4 +34,13 @@ private: \ #define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#if ALIGN_DOUBLE +#define ALIGN_SZ (sizeof(double)) +#else +#define ALIGN_SZ (sizeof(int)) +#endif + +#define ALIGN(x) (((x) + ALIGN_SZ - 1) & ~(ALIGN_SZ - 1)) +#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)(p)))) + #endif /* MACROS_H */ diff --git a/libs/hwui/utils/TypeLogic.h b/libs/hwui/utils/TypeLogic.h new file mode 100644 index 000000000000..dbdad33d8335 --- /dev/null +++ b/libs/hwui/utils/TypeLogic.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#pragma once + +#include <type_traits> + +namespace android::uirenderer { + +template <typename D, typename S> struct copy_const { + using type = std::conditional_t<std::is_const<S>::value, std::add_const_t<D>, D>; +}; +template <typename D, typename S> using copy_const_t = typename copy_const<D, S>::type; + +template <typename D, typename S> struct copy_volatile { + using type = std::conditional_t<std::is_volatile<S>::value, std::add_volatile_t<D>, D>; +}; +template <typename D, typename S> using copy_volatile_t = typename copy_volatile<D, S>::type; + +template <typename D, typename S> struct copy_cv { + using type = copy_volatile_t<copy_const_t<D, S>, S>; +}; + +template <typename D, typename S> using same_cv = copy_cv<std::remove_cv_t<D>, S>; +template <typename D, typename S> using same_cv_t = typename same_cv<D, S>::type; + +}; // namespace android::uirenderer
\ No newline at end of file |