Holepunch layers for SurfaceView
Update RenderNodeDrawable to hole punch areas into layers created for SurfaceView Bug: 184297961 Test: Added CTS test to SurfaceViewTests Change-Id: I1f03a4fe34c5a8b7411ebe728ea3d4195fcd1fac
This commit is contained in:
@@ -33,7 +33,6 @@ import android.graphics.Color;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.RenderNode;
|
||||
@@ -670,10 +669,16 @@ public class SurfaceView extends View implements ViewRootImpl.SurfaceChangedCall
|
||||
if (mClipSurfaceToBounds && mClipBounds != null) {
|
||||
mTmpRect.intersect(mClipBounds);
|
||||
}
|
||||
canvas.drawRoundRect(mTmpRect.left, mTmpRect.top, mTmpRect.right, mTmpRect.bottom,
|
||||
mCornerRadius, mCornerRadius, mRoundedViewportPaint);
|
||||
canvas.punchHole(
|
||||
mTmpRect.left,
|
||||
mTmpRect.top,
|
||||
mTmpRect.right,
|
||||
mTmpRect.bottom,
|
||||
mCornerRadius,
|
||||
mCornerRadius
|
||||
);
|
||||
} else {
|
||||
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
|
||||
canvas.punchHole(0f, 0f, getWidth(), getHeight(), 0f, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -670,6 +670,13 @@ public abstract class BaseCanvas {
|
||||
indices, indexOffset, indexCount, paint.getNativeInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public void punchHole(float left, float top, float right, float bottom, float rx, float ry) {
|
||||
nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@@ -815,4 +822,7 @@ public abstract class BaseCanvas {
|
||||
|
||||
private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath,
|
||||
float hOffset, float vOffset, int flags, long nativePaint);
|
||||
|
||||
private static native void nPunchHole(long renderer, float left, float top, float right,
|
||||
float bottom, float rx, float ry);
|
||||
}
|
||||
|
||||
@@ -610,6 +610,14 @@ public class BaseRecordingCanvas extends Canvas {
|
||||
indices, indexOffset, indexCount, paint.getNativeInstance());
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
@Override
|
||||
public void punchHole(float left, float top, float right, float bottom, float rx, float ry) {
|
||||
nPunchHole(mNativeCanvasWrapper, left, top, right, bottom, rx, ry);
|
||||
}
|
||||
|
||||
@FastNative
|
||||
private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, float left,
|
||||
float top, long nativePaintOrZero, int canvasDensity, int screenDensity,
|
||||
@@ -735,4 +743,8 @@ public class BaseRecordingCanvas extends Canvas {
|
||||
@FastNative
|
||||
private static native void nDrawTextOnPath(long nativeCanvas, String text, long nativePath,
|
||||
float hOffset, float vOffset, int flags, long nativePaint);
|
||||
|
||||
@FastNative
|
||||
private static native void nPunchHole(long renderer, float left, float top, float right,
|
||||
float bottom, float rx, float ry);
|
||||
}
|
||||
|
||||
@@ -464,10 +464,12 @@ cc_defaults {
|
||||
"canvas/CanvasOpBuffer.cpp",
|
||||
"canvas/CanvasOpRasterizer.cpp",
|
||||
"effects/StretchEffect.cpp",
|
||||
"pipeline/skia/HolePunch.cpp",
|
||||
"pipeline/skia/SkiaDisplayList.cpp",
|
||||
"pipeline/skia/SkiaRecordingCanvas.cpp",
|
||||
"pipeline/skia/RenderNodeDrawable.cpp",
|
||||
"pipeline/skia/ReorderBarrierDrawables.cpp",
|
||||
"pipeline/skia/TransformCanvas.cpp",
|
||||
"renderthread/Frame.cpp",
|
||||
"renderthread/RenderTask.cpp",
|
||||
"renderthread/TimeLord.cpp",
|
||||
|
||||
@@ -72,6 +72,10 @@ public:
|
||||
return mImpl && !(mImpl->isEmpty());
|
||||
}
|
||||
|
||||
[[nodiscard]] bool hasHolePunches() const {
|
||||
return mImpl && mImpl->hasHolePunches();
|
||||
}
|
||||
|
||||
[[nodiscard]] bool containsProjectionReceiver() const {
|
||||
return mImpl && mImpl->containsProjectionReceiver();
|
||||
}
|
||||
|
||||
@@ -255,15 +255,19 @@ void RenderNode::prepareTreeImpl(TreeObserver& observer, TreeInfo& info, bool fu
|
||||
|
||||
if (mDisplayList) {
|
||||
info.out.hasFunctors |= mDisplayList.hasFunctor();
|
||||
mHasHolePunches = mDisplayList.hasHolePunches();
|
||||
bool isDirty = mDisplayList.prepareListAndChildren(
|
||||
observer, info, childFunctorsNeedLayer,
|
||||
[](RenderNode* child, TreeObserver& observer, TreeInfo& info,
|
||||
bool functorsNeedLayer) {
|
||||
[this](RenderNode* child, TreeObserver& observer, TreeInfo& info,
|
||||
bool functorsNeedLayer) {
|
||||
child->prepareTreeImpl(observer, info, functorsNeedLayer);
|
||||
mHasHolePunches |= child->hasHolePunches();
|
||||
});
|
||||
if (isDirty) {
|
||||
damageSelf(info);
|
||||
}
|
||||
} else {
|
||||
mHasHolePunches = false;
|
||||
}
|
||||
pushLayerUpdate(info);
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "DisplayList.h"
|
||||
#include "Matrix.h"
|
||||
#include "RenderProperties.h"
|
||||
#include "pipeline/skia/HolePunch.h"
|
||||
#include "pipeline/skia/SkiaDisplayList.h"
|
||||
#include "pipeline/skia/SkiaLayer.h"
|
||||
|
||||
@@ -284,6 +285,8 @@ private:
|
||||
|
||||
UsageHint mUsageHint = UsageHint::Unknown;
|
||||
|
||||
bool mHasHolePunches;
|
||||
|
||||
// METHODS & FIELDS ONLY USED BY THE SKIA RENDERER
|
||||
public:
|
||||
/**
|
||||
@@ -294,6 +297,8 @@ public:
|
||||
return std::move(mAvailableDisplayList);
|
||||
}
|
||||
|
||||
bool hasHolePunches() { return mHasHolePunches; }
|
||||
|
||||
/**
|
||||
* Attach unused displayList to this node for potential future reuse.
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "hwui/MinikinUtils.h"
|
||||
#include "hwui/PaintFilter.h"
|
||||
#include "pipeline/skia/AnimatedDrawables.h"
|
||||
#include "pipeline/skia/HolePunch.h"
|
||||
|
||||
#include <SkAndroidFrameworkUtils.h>
|
||||
#include <SkAnimatedImage.h>
|
||||
@@ -244,6 +245,13 @@ const SkiaCanvas::SaveRec* SkiaCanvas::currentSaveRec() const {
|
||||
return (rec && rec->saveCount == currentSaveCount) ? rec : nullptr;
|
||||
}
|
||||
|
||||
void SkiaCanvas::punchHole(const SkRRect& rect) {
|
||||
SkPaint paint = SkPaint();
|
||||
paint.setColor(0);
|
||||
paint.setBlendMode(SkBlendMode::kClear);
|
||||
mCanvas->drawRRect(rect, paint);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// functions to emulate legacy SaveFlags (i.e. independent matrix/clip flags)
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -60,6 +60,8 @@ public:
|
||||
LOG_ALWAYS_FATAL("SkiaCanvas does not support enableZ");
|
||||
}
|
||||
|
||||
virtual void punchHole(const SkRRect& rect) override;
|
||||
|
||||
virtual void setBitmap(const SkBitmap& bitmap) override;
|
||||
|
||||
virtual bool isOpaque() override;
|
||||
|
||||
@@ -155,6 +155,8 @@ public:
|
||||
LOG_ALWAYS_FATAL("Not supported");
|
||||
}
|
||||
|
||||
virtual void punchHole(const SkRRect& rect) = 0;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Canvas state operations
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "SkGraphics.h"
|
||||
#include "SkRegion.h"
|
||||
#include "SkVertices.h"
|
||||
#include "SkRRect.h"
|
||||
|
||||
namespace minikin {
|
||||
class MeasuredText;
|
||||
@@ -667,6 +668,11 @@ static void setCompatibilityVersion(JNIEnv* env, jobject, jint apiLevel) {
|
||||
Canvas::setCompatibilityVersion(apiLevel);
|
||||
}
|
||||
|
||||
static void punchHole(JNIEnv* env, jobject, jlong canvasPtr, jfloat left, jfloat top, jfloat right,
|
||||
jfloat bottom, jfloat rx, jfloat ry) {
|
||||
auto canvas = reinterpret_cast<Canvas*>(canvasPtr);
|
||||
canvas->punchHole(SkRRect::MakeRectXY(SkRect::MakeLTRB(left, top, right, bottom), rx, ry));
|
||||
}
|
||||
|
||||
}; // namespace CanvasJNI
|
||||
|
||||
@@ -740,6 +746,7 @@ static const JNINativeMethod gDrawMethods[] = {
|
||||
{"nDrawTextRun","(JLjava/lang/String;IIIIFFZJ)V", (void*) CanvasJNI::drawTextRunString},
|
||||
{"nDrawTextOnPath","(J[CIIJFFIJ)V", (void*) CanvasJNI::drawTextOnPathChars},
|
||||
{"nDrawTextOnPath","(JLjava/lang/String;JFFIJ)V", (void*) CanvasJNI::drawTextOnPathString},
|
||||
{"nPunchHole", "(JFFFFFF)V", (void*) CanvasJNI::punchHole}
|
||||
};
|
||||
|
||||
int register_android_graphics_Canvas(JNIEnv* env) {
|
||||
|
||||
21
libs/hwui/pipeline/skia/HolePunch.cpp
Normal file
21
libs/hwui/pipeline/skia/HolePunch.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 "HolePunch.h"
|
||||
#include <string>
|
||||
|
||||
using namespace android::uirenderer::skiapipeline;
|
||||
|
||||
const std::string HOLE_PUNCH_ANNOTATION = "surface_hole_punch";
|
||||
30
libs/hwui/pipeline/skia/HolePunch.h
Normal file
30
libs/hwui/pipeline/skia/HolePunch.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 <string>
|
||||
#include "SkRRect.h"
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
namespace skiapipeline {
|
||||
|
||||
const static std::string HOLE_PUNCH_ANNOTATION;
|
||||
|
||||
} // namespace skiapipeline
|
||||
} // namespace uirenderer
|
||||
} // namespace android
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <SkPaintFilterCanvas.h>
|
||||
#include "RenderNode.h"
|
||||
#include "SkiaDisplayList.h"
|
||||
#include "TransformCanvas.h"
|
||||
#include "utils/TraceUtils.h"
|
||||
|
||||
#include <include/effects/SkImageFilters.h>
|
||||
@@ -256,6 +257,11 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
|
||||
canvas->drawAnnotation(bounds, String8::format(
|
||||
"SurfaceID|%" PRId64, renderNode->uniqueId()).c_str(), nullptr);
|
||||
}
|
||||
|
||||
if (renderNode->hasHolePunches()) {
|
||||
TransformCanvas transformCanvas(canvas);
|
||||
displayList->draw(&transformCanvas);
|
||||
}
|
||||
canvas->drawImageRect(snapshotImage, bounds, bounds, sampling, &paint,
|
||||
SkCanvas::kStrict_SrcRectConstraint);
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ public:
|
||||
|
||||
private:
|
||||
std::vector<Pair<VectorDrawableRoot*, SkMatrix>> mVectorDrawables;
|
||||
|
||||
bool mHasHolePunches;
|
||||
public:
|
||||
void appendVD(VectorDrawableRoot* r) { appendVD(r, SkMatrix::I()); }
|
||||
|
||||
@@ -171,6 +171,14 @@ public:
|
||||
mVectorDrawables.push_back(Pair<VectorDrawableRoot*, SkMatrix>(r, mat));
|
||||
}
|
||||
|
||||
void setHasHolePunches(bool hasHolePunches) {
|
||||
mHasHolePunches = hasHolePunches;
|
||||
}
|
||||
|
||||
bool hasHolePunches() {
|
||||
return mHasHolePunches;
|
||||
}
|
||||
|
||||
std::vector<AnimatedImageDrawable*> mAnimatedImages;
|
||||
DisplayListData mDisplayList;
|
||||
|
||||
|
||||
@@ -53,6 +53,27 @@ void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, in
|
||||
|
||||
mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height));
|
||||
SkiaCanvas::reset(&mRecorder);
|
||||
mDisplayList->setHasHolePunches(false);
|
||||
}
|
||||
|
||||
void SkiaRecordingCanvas::punchHole(const SkRRect& rect) {
|
||||
// Add the marker annotation to allow HWUI to determine where the current
|
||||
// clip/transformation should be applied
|
||||
SkVector vector = rect.getSimpleRadii();
|
||||
const int dataSize = 2;
|
||||
float data[dataSize];
|
||||
data[0] = vector.x();
|
||||
data[1] = vector.y();
|
||||
mRecorder.drawAnnotation(rect.rect(), HOLE_PUNCH_ANNOTATION.c_str(),
|
||||
SkData::MakeWithCopy(data, dataSize));
|
||||
|
||||
// Clear the current rect within the layer itself
|
||||
SkPaint paint = SkPaint();
|
||||
paint.setColor(0);
|
||||
paint.setBlendMode(SkBlendMode::kClear);
|
||||
mRecorder.drawRRect(rect, paint);
|
||||
|
||||
mDisplayList->setHasHolePunches(true);
|
||||
}
|
||||
|
||||
std::unique_ptr<SkiaDisplayList> SkiaRecordingCanvas::finishRecording() {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "HolePunch.h"
|
||||
#include "RecordingCanvas.h"
|
||||
#include "ReorderBarrierDrawables.h"
|
||||
#include "SkiaCanvas.h"
|
||||
@@ -43,6 +44,8 @@ public:
|
||||
initDisplayList(renderNode, width, height);
|
||||
}
|
||||
|
||||
virtual void punchHole(const SkRRect& rect) override;
|
||||
|
||||
virtual void finishRecording(uirenderer::RenderNode* destination) override;
|
||||
std::unique_ptr<SkiaDisplayList> finishRecording();
|
||||
|
||||
|
||||
43
libs/hwui/pipeline/skia/TransformCanvas.cpp
Normal file
43
libs/hwui/pipeline/skia/TransformCanvas.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 "TransformCanvas.h"
|
||||
#include "HolePunch.h"
|
||||
#include "SkData.h"
|
||||
#include "SkDrawable.h"
|
||||
|
||||
using namespace android::uirenderer::skiapipeline;
|
||||
|
||||
void TransformCanvas::onDrawAnnotation(const SkRect& rect, const char* key, SkData* value) {
|
||||
if (HOLE_PUNCH_ANNOTATION == key) {
|
||||
auto* rectParams = static_cast<const float*>(value->data());
|
||||
float radiusX = rectParams[0];
|
||||
float radiusY = rectParams[1];
|
||||
SkRRect roundRect = SkRRect::MakeRectXY(rect, radiusX, radiusY);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setColor(0);
|
||||
paint.setBlendMode(SkBlendMode::kClear);
|
||||
mWrappedCanvas->drawRRect(roundRect, paint);
|
||||
}
|
||||
}
|
||||
|
||||
void TransformCanvas::onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) {
|
||||
drawable->draw(this, matrix);
|
||||
}
|
||||
|
||||
bool TransformCanvas::onFilter(SkPaint& paint) const {
|
||||
return false;
|
||||
}
|
||||
35
libs/hwui/pipeline/skia/TransformCanvas.h
Normal file
35
libs/hwui/pipeline/skia/TransformCanvas.h
Normal file
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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 <include/core/SkCanvas.h>
|
||||
#include "SkPaintFilterCanvas.h"
|
||||
|
||||
class TransformCanvas : public SkPaintFilterCanvas {
|
||||
public:
|
||||
TransformCanvas(SkCanvas* target) : SkPaintFilterCanvas(target), mWrappedCanvas(target) {}
|
||||
|
||||
protected:
|
||||
bool onFilter(SkPaint& paint) const override;
|
||||
|
||||
protected:
|
||||
void onDrawAnnotation(const SkRect& rect, const char* key, SkData* value) override;
|
||||
void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override;
|
||||
|
||||
private:
|
||||
// We don't own the canvas so just maintain a raw pointer to it
|
||||
SkCanvas* mWrappedCanvas;
|
||||
};
|
||||
Reference in New Issue
Block a user