Restore matrix transform for out-of-order render nodes
Restore matrix for render nodes, which are drawn out of order.
Test: DrawChildBug-debug.apk draws correctly, new test ag/4355529
Bug: 80173852
Change-Id: I3f789a7cf0ee5816da84255199b265643f95af1c
This commit is contained in:
@@ -142,7 +142,7 @@ void RenderNodeDrawable::forceDraw(SkCanvas* canvas) {
|
||||
LOG_ALWAYS_FATAL_IF(!mProjectedDisplayList->mProjectedOutline);
|
||||
const bool shouldClip = mProjectedDisplayList->mProjectedOutline->getPath();
|
||||
SkAutoCanvasRestore acr2(canvas, shouldClip);
|
||||
canvas->setMatrix(mProjectedDisplayList->mProjectedReceiverParentMatrix);
|
||||
canvas->setMatrix(mProjectedDisplayList->mParentMatrix);
|
||||
if (shouldClip) {
|
||||
clipOutline(*mProjectedDisplayList->mProjectedOutline, canvas, nullptr);
|
||||
}
|
||||
@@ -200,9 +200,7 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const {
|
||||
setViewProperties(properties, canvas, &alphaMultiplier);
|
||||
}
|
||||
SkiaDisplayList* displayList = (SkiaDisplayList*)mRenderNode->getDisplayList();
|
||||
if (displayList->containsProjectionReceiver()) {
|
||||
displayList->mProjectedReceiverParentMatrix = canvas->getTotalMatrix();
|
||||
}
|
||||
displayList->mParentMatrix = canvas->getTotalMatrix();
|
||||
|
||||
// TODO should we let the bound of the drawable do this for us?
|
||||
const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
|
||||
|
||||
@@ -55,6 +55,11 @@ void StartReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
|
||||
if (casterZ >= -NON_ZERO_EPSILON) { // draw only children with negative Z
|
||||
return;
|
||||
}
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
// Since we're drawing out of recording order, the child's matrix needs to be applied to the
|
||||
// canvas. In in-order drawing, the canvas already has the child's matrix applied.
|
||||
canvas->setMatrix(mDisplayList->mParentMatrix);
|
||||
canvas->concat(childNode->getRecordedMatrix());
|
||||
childNode->forceDraw(canvas);
|
||||
drawIndex++;
|
||||
}
|
||||
@@ -102,6 +107,11 @@ void EndReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
|
||||
|
||||
RenderNodeDrawable* childNode = zChildren[drawIndex];
|
||||
SkASSERT(childNode);
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
// Since we're drawing out of recording order, the child's matrix needs to be applied to the
|
||||
// canvas. In in-order drawing, the canvas already has the child's matrix applied.
|
||||
canvas->setMatrix(mStartBarrier->mDisplayList->mParentMatrix);
|
||||
canvas->concat(childNode->getRecordedMatrix());
|
||||
childNode->forceDraw(canvas);
|
||||
|
||||
drawIndex++;
|
||||
@@ -153,10 +163,15 @@ void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable*
|
||||
}
|
||||
|
||||
SkAutoCanvasRestore acr(canvas, true);
|
||||
// Since we're drawing out of recording order, the child's matrix needs to be applied to the
|
||||
// canvas. In in-order drawing, the canvas already has the child's matrix applied.
|
||||
canvas->setMatrix(mStartBarrier->mDisplayList->mParentMatrix);
|
||||
|
||||
SkMatrix shadowMatrix;
|
||||
mat4 hwuiMatrix;
|
||||
mat4 hwuiMatrix(caster->getRecordedMatrix());
|
||||
// TODO we don't pass the optional boolean to treat it as a 4x4 matrix
|
||||
// applyViewPropertyTransforms gets the same matrix, which render nodes apply with
|
||||
// RenderNodeDrawable::setViewProperties as a part if their draw.
|
||||
caster->getRenderNode()->applyViewPropertyTransforms(hwuiMatrix);
|
||||
hwuiMatrix.copyTo(shadowMatrix);
|
||||
canvas->concat(shadowMatrix);
|
||||
|
||||
@@ -173,12 +173,12 @@ public:
|
||||
// node is drawn.
|
||||
const Outline* mProjectedOutline = nullptr;
|
||||
|
||||
// mProjectedReceiverParentMatrix is valid when render node tree is traversed during the draw
|
||||
// pass. Render nodes that have a child receiver node, will store their matrix in
|
||||
// mProjectedReceiverParentMatrix. Child receiver node will set the matrix and then clip with
|
||||
// the
|
||||
// outline of their parent.
|
||||
SkMatrix mProjectedReceiverParentMatrix;
|
||||
// mParentMatrix is set and valid when render node tree is traversed during the draw
|
||||
// pass. Render nodes, which draw in a order different than recording order (e.g. nodes with a
|
||||
// child receiver node or Z elevation), can use mParentMatrix to calculate the final transform
|
||||
// without replaying the matrix transform OPs from the display list.
|
||||
// Child receiver node will set the matrix and then clip with the outline of their parent.
|
||||
SkMatrix mParentMatrix;
|
||||
};
|
||||
|
||||
}; // namespace skiapipeline
|
||||
|
||||
@@ -1094,7 +1094,7 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) {
|
||||
class ShadowTestCanvas : public SkCanvas {
|
||||
public:
|
||||
ShadowTestCanvas(int width, int height) : SkCanvas(width, height) {}
|
||||
int getIndex() { return mDrawCounter; }
|
||||
int getDrawCounter() { return mDrawCounter; }
|
||||
|
||||
virtual void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
|
||||
// expect to draw 2 RenderNodeDrawable, 1 StartReorderBarrierDrawable,
|
||||
@@ -1109,17 +1109,36 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) {
|
||||
EXPECT_EQ(dy, TRANSLATE_Y);
|
||||
}
|
||||
|
||||
virtual void didConcat(const SkMatrix& matrix) override {
|
||||
// This function is invoked by EndReorderBarrierDrawable::drawShadow to apply shadow
|
||||
// matrix.
|
||||
virtual void didSetMatrix(const SkMatrix& matrix) override {
|
||||
mDrawCounter++;
|
||||
EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X, CASTER_Y), matrix);
|
||||
EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
|
||||
getTotalMatrix());
|
||||
// First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
|
||||
// Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
|
||||
EXPECT_TRUE(matrix.isIdentity());
|
||||
EXPECT_TRUE(getTotalMatrix().isIdentity());
|
||||
}
|
||||
|
||||
virtual void didConcat(const SkMatrix& matrix) override {
|
||||
mDrawCounter++;
|
||||
if (mFirstDidConcat) {
|
||||
// First invocation is EndReorderBarrierDrawable::drawShadow to apply shadow matrix.
|
||||
mFirstDidConcat = false;
|
||||
EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
|
||||
matrix);
|
||||
EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
|
||||
getTotalMatrix());
|
||||
} else {
|
||||
// Second invocation is preparing the matrix for an elevated RenderNodeDrawable.
|
||||
EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y),
|
||||
matrix);
|
||||
EXPECT_EQ(SkMatrix::MakeTrans(TRANSLATE_X, TRANSLATE_Y),
|
||||
getTotalMatrix());
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
int mDrawCounter = 0;
|
||||
private:
|
||||
bool mFirstDidConcat = true;
|
||||
};
|
||||
|
||||
auto parent = TestUtils::createSkiaNode(
|
||||
@@ -1143,7 +1162,7 @@ TEST(ReorderBarrierDrawable, testShadowMatrix) {
|
||||
ShadowTestCanvas canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
|
||||
RenderNodeDrawable drawable(parent.get(), &canvas, false);
|
||||
canvas.drawDrawable(&drawable);
|
||||
EXPECT_EQ(6, canvas.getIndex());
|
||||
EXPECT_EQ(9, canvas.getDrawCounter());
|
||||
}
|
||||
|
||||
// Draw a vector drawable twice but with different bounds and verify correct bounds are used.
|
||||
|
||||
Reference in New Issue
Block a user