Maintain z order of shapepaths during update in CurveRenderer

The new nodes for any updated shapepath would be appended to the end
of the child list, and hence pop to the front of the z order
stack. Instead, maintain the order by inserting the new nodes in the
old ones' place in the child list.

Fixes: QTBUG-119192
Change-Id: I0fa477158648a901b488b08b9fdef6465c312dd0
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
This commit is contained in:
Eirik Aavitsland 2023-11-21 17:42:35 +01:00
parent 717a1dd908
commit 70495410a8
5 changed files with 197 additions and 7 deletions

View File

@ -352,26 +352,49 @@ void QQuickShapeCurveRenderer::updateNode()
strokeNode->setColor(pathData.pen.color());
};
for (PathData &pathData : m_paths) {
NodeList toBeDeleted;
for (int i = 0; i < m_paths.size(); i++) {
PathData &pathData = m_paths[i];
if (pathData.currentRunner) {
if (!pathData.currentRunner->isDone)
continue;
// Find insertion point for new nodes
QSGNode *nextNode = nullptr;
int j = i;
do {
const PathData &pd = m_paths[j];
if (!pd.fillNodes.isEmpty())
nextNode = pd.fillNodes.first();
else if (!pathData.strokeNodes.isEmpty())
nextNode = pd.strokeNodes.first();
} while (!nextNode && ++j < m_paths.size());
const PathData &newData = pathData.currentRunner->pathData;
if (newData.m_dirty & PathDirty)
pathData.path = newData.path;
if (newData.m_dirty & FillDirty) {
pathData.fillPath = newData.fillPath;
qDeleteAll(pathData.fillNodes);
for (auto *node : std::as_const(newData.fillNodes)) {
if (nextNode)
m_rootNode->insertChildNodeBefore(node, nextNode);
else
m_rootNode->appendChildNode(node);
}
toBeDeleted += pathData.fillNodes;
pathData.fillNodes = newData.fillNodes;
for (auto *node : std::as_const(pathData.fillNodes))
m_rootNode->appendChildNode(node);
}
if (newData.m_dirty & StrokeDirty) {
qDeleteAll(pathData.strokeNodes);
for (auto *node : std::as_const(newData.strokeNodes)) {
if (nextNode)
m_rootNode->insertChildNodeBefore(node, nextNode);
else
m_rootNode->appendChildNode(node);
}
toBeDeleted += pathData.strokeNodes;
pathData.strokeNodes = newData.strokeNodes;
for (auto *node : std::as_const(pathData.strokeNodes))
m_rootNode->appendChildNode(node);
}
if (newData.m_dirty & UniformsDirty)
updateUniforms(pathData);
@ -388,6 +411,7 @@ void QQuickShapeCurveRenderer::updateNode()
pathData.m_dirty = 0;
}
}
qDeleteAll(toBeDeleted); // also removes them from m_rootNode's child list
}
void QQuickShapeCurveRenderer::processPath(PathData *pathData)

View File

@ -3,6 +3,7 @@
# These are items to be used in other scenes; lack size
borderimages/SimpleBorderImage.qml
borderimages/SimpleNoBorder.qml
shape/OrderedPaths.qml
# This will not stabilize before the timeout
text/text_2500_chinese_characters.qml

View File

@ -0,0 +1,141 @@
import QtQuick
import QtQuick.Shapes
Item {
id: root
property bool async: false
property int counter: 0
NumberAnimation {
target: root
property: "counter"
duration: 2000
from: 0
to: 15
running: true
}
component RectStack : Shape {
asynchronous: root.async
property alias p1FillColor: p1.fillColor
property alias p2FillColor: p2.fillColor
property alias p3FillColor: p3.fillColor
property alias p4FillColor: p4.fillColor
property alias p1StrokeColor: p1.strokeColor
property alias p2StrokeColor: p2.strokeColor
property alias p3StrokeColor: p3.strokeColor
property alias p4StrokeColor: p4.strokeColor
ShapePath {
id: p1
fillColor: "black"
strokeColor: "transparent"
strokeWidth: 5
startX: 10
startY: 10
PathLine { relativeX: 100; relativeY: 0 }
PathLine { relativeX: 0; relativeY: 60 }
PathLine { relativeX: -100; relativeY: 0 }
PathLine { relativeX: 0; relativeY: -60 }
}
ShapePath {
id: p2
fillColor: "red"
strokeColor: "transparent"
strokeWidth: 5
startX: 20
startY: 15
PathLine { relativeX: 100; relativeY: 0 }
PathLine { relativeX: 0; relativeY: 60 }
PathLine { relativeX: -100; relativeY: 0 }
PathLine { relativeX: 0; relativeY: -60 }
}
ShapePath {
id: p3
fillColor: "green"
strokeColor: "transparent"
strokeWidth: 5
startX: 30
startY: 20
PathLine { relativeX: 100; relativeY: 0 }
PathLine { relativeX: 0; relativeY: 60 }
PathLine { relativeX: -100; relativeY: 0 }
PathLine { relativeX: 0; relativeY: -60 }
}
ShapePath {
id: p4
fillColor: "blue"
strokeColor: "transparent"
strokeWidth: 5
startX: 40
startY: 25
PathLine { relativeX: 100; relativeY: 0 }
PathLine { relativeX: 0; relativeY: 60 }
PathLine { relativeX: -100; relativeY: 0 }
PathLine { relativeX: 0; relativeY: -60 }
}
}
ListModel {
id: renderers
ListElement { renderer: Shape.GeometryRenderer }
ListElement { renderer: Shape.CurveRenderer }
}
Row {
spacing: 5
Repeater {
model: renderers
Column {
spacing: 5
RectStack {
preferredRendererType: renderer
}
RectStack {
preferredRendererType: renderer
p1FillColor: counter % 16 >= 8 ? "black" : "transparent"
p2FillColor: counter % 8 >= 4 ? "red" : "transparent"
p3FillColor: counter % 4 >= 2 ? "green" : "transparent"
p4FillColor: counter % 2 >= 1 ? "blue" : "transparent"
}
RectStack {
preferredRendererType: renderer
property int shifter: counter < 4 ? counter : counter + 1
p1FillColor: shifter % 2 == 0 ? "black" : "transparent"
p2FillColor: counter % 2 == 0 ? "red" : "transparent"
p3FillColor: shifter % 2 == 1 ? "green" : "transparent"
p4FillColor: counter % 2 == 1 ? "blue" : "transparent"
}
RectStack {
preferredRendererType: renderer
p1FillColor: counter % 16 >= 8 ? "black" : "transparent"
p2FillColor: counter % 8 >= 4 ? "red" : "transparent"
p3FillColor: counter % 4 >= 2 ? "green" : "transparent"
p4FillColor: counter % 2 >= 1 ? "blue" : "transparent"
p1StrokeColor: counter % 2 >= 1 ? "transparent" : "lightblue"
p2StrokeColor: counter % 4 >= 2 ? "transparent" : "lightgreen"
p3StrokeColor: counter % 8 >= 4 ? "transparent" : "pink"
p4StrokeColor: counter % 16 >= 8 ? "transparent" : "gray"
}
RectStack {
preferredRendererType: renderer
p1FillColor: "transparent"
p2FillColor: "transparent"
p3FillColor: "transparent"
p4FillColor: "transparent"
p1StrokeColor: counter % 16 >= 8 ? "lightblue": "transparent"
p2StrokeColor: counter % 8 >= 4 ? "lightgreen": "transparent"
p3StrokeColor: counter % 4 >= 2 ? "pink": "transparent"
p4StrokeColor: counter % 2 >= 1 ? "gray" : "transparent"
}
}
}
}
}

View File

@ -0,0 +1,12 @@
import QtQuick
Item {
width: 320
height: 480
OrderedPaths {
anchors.fill: parent
async: false
}
}

View File

@ -0,0 +1,12 @@
import QtQuick
Item {
width: 320
height: 480
OrderedPaths {
anchors.fill: parent
async: true
}
}