Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 54d7032b authored by Stan Iliev's avatar Stan Iliev
Browse files

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
parent acda839b
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -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());
+16 −1
Original line number Diff line number Diff line
@@ -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);
+6 −6
Original line number Diff line number Diff line
@@ -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
+26 −7
Original line number Diff line number Diff line
@@ -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 didSetMatrix(const SkMatrix& matrix) override {
            mDrawCounter++;
            // 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 {
            // This function is invoked by EndReorderBarrierDrawable::drawShadow to apply shadow
            // matrix.
            mDrawCounter++;
            EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X, CASTER_Y), matrix);
            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.