[poincare] Make GridLayout rendering faster

This commit is contained in:
Léa Saviot
2019-03-04 11:58:11 +01:00
committed by Émilie Feral
parent fbfbf5c845
commit 80e2879cb7
4 changed files with 105 additions and 50 deletions

View File

@@ -124,6 +124,7 @@ protected:
// Tree
Direct<LayoutNode> children() { return Direct<LayoutNode>(this); }
Direct<LayoutNode> childrenFromIndex(int i) { return Direct<LayoutNode>(this, i); }
// Sizing and positioning
virtual KDSize computeSize() = 0;

View File

@@ -98,7 +98,7 @@ public:
template <typename T>
class Direct final {
public:
Direct(const T * node) : m_node(const_cast<T *>(node)) {}
Direct(const T * node, int firstIndex = 0) : m_node(const_cast<T *>(node)), m_firstIndex(firstIndex) {}
class Iterator : public TreeNode::Iterator<T> {
public:
using TreeNode::Iterator<T>::Iterator;
@@ -107,10 +107,17 @@ public:
return *this;
}
};
Iterator begin() const { return Iterator(static_cast<T *>(m_node->next())); }
Iterator begin() const {
TreeNode * n = m_node->next();
for (int i = 0; i < m_firstIndex; i++) {
n = n->nextSibling();
}
return Iterator(static_cast<T *>(n));
}
Iterator end() const { return Iterator(static_cast<T *>(m_node->nextSibling())); }
private:
T * m_node;
int m_firstIndex;
};
template <typename T>
@@ -155,6 +162,7 @@ protected:
m_parentIdentifier(NoNodeIdentifier),
m_referenceCounter(0)
{}
private:
void updateParentIdentifierInChildren() const {
changeParentIdentifierInChildren(m_identifier);

View File

@@ -43,7 +43,8 @@ void GridLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRecompu
cursor->setLayoutNode(childAtIndex(0));
return;
}
int childIndex = indexOfChild(cursor->layoutNode());
LayoutNode * cursorNode = cursor->layoutNode();
int childIndex = indexOfChild(cursorNode);
if (childIndex >= 0 && cursor->position() == LayoutCursor::Position::Right) {
// Case: The cursor points to a grid's child.
if (childIsRightOfGrid(childIndex)) {
@@ -52,7 +53,7 @@ void GridLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRecompu
return;
}
// Case: Right of another child. Go Left of its sibling on the right.
cursor->setLayoutNode(childAtIndex(childIndex + 1));
cursor->setLayoutNode(static_cast<LayoutNode *>(cursorNode->nextSibling()));
cursor->setPosition(LayoutCursor::Position::Left);
return;
}
@@ -66,10 +67,10 @@ void GridLayoutNode::moveCursorRight(LayoutCursor * cursor, bool * shouldRecompu
void GridLayoutNode::moveCursorUp(LayoutCursor * cursor, bool * shouldRecomputeLayout, bool equivalentPositionVisited) {
/* If the cursor is child that is not on the top row, move it inside its upper
* neighbour.*/
* neighbour. */
int childIndex = m_numberOfColumns;
while (childIndex < numberOfChildren()) {
if (cursor->layoutNode()->hasAncestor(childAtIndex(childIndex), true)) {
for (LayoutNode * l : childrenFromIndex(childIndex)) {
if (cursor->layoutNode()->hasAncestor(l, true)) {
childAtIndex(childIndex - m_numberOfColumns)->moveCursorUpInDescendants(cursor, shouldRecomputeLayout);
return;
}
@@ -80,12 +81,16 @@ void GridLayoutNode::moveCursorUp(LayoutCursor * cursor, bool * shouldRecomputeL
void GridLayoutNode::moveCursorDown(LayoutCursor * cursor, bool * shouldRecomputeLayout, bool equivalentPositionVisited) {
int childIndex = 0;
while (childIndex < numberOfChildren() - m_numberOfColumns) {
if (cursor->layoutNode()->hasAncestor(childAtIndex(childIndex), true)) {
int maxIndex = numberOfChildren() - m_numberOfColumns;
for (LayoutNode * l : children()) {
if (cursor->layoutNode()->hasAncestor(l, true)) {
childAtIndex(childIndex + m_numberOfColumns)->moveCursorDownInDescendants(cursor, shouldRecomputeLayout);
return;
}
childIndex++;
if (childIndex >= maxIndex) {
break;
}
}
LayoutNode::moveCursorDown(cursor, shouldRecomputeLayout, equivalentPositionVisited);
}
@@ -191,17 +196,9 @@ KDCoordinate GridLayoutNode::computeBaseline() {
}
KDPoint GridLayoutNode::positionOfChild(LayoutNode * l) {
int rowIndex = 0;
int columnIndex = 0;
for (int i = 0; i < m_numberOfRows; i++) {
for (int j = 0; j < m_numberOfColumns; j++) {
if (l == childAtIndex(i*m_numberOfColumns+j)) {
rowIndex = i;
columnIndex = j;
break;
}
}
}
int childIndex = indexOfChild(l);
int rowIndex = rowAtChildIndex(childIndex);
int columnIndex = columnAtChildIndex(childIndex);
KDCoordinate x = 0;
for (int j = 0; j < columnIndex; j++) {
x += columnWidth(j);
@@ -218,21 +215,33 @@ KDPoint GridLayoutNode::positionOfChild(LayoutNode * l) {
// Private
KDCoordinate GridLayoutNode::rowBaseline(int i) {
assert(m_numberOfColumns > 0);
KDCoordinate rowBaseline = 0;
for (int j = 0; j < m_numberOfColumns; j++) {
rowBaseline = maxCoordinate(rowBaseline, childAtIndex(i*m_numberOfColumns+j)->baseline());
int j = 0;
for (LayoutNode * l : childrenFromIndex(i*m_numberOfColumns)) {
rowBaseline = maxCoordinate(rowBaseline, l->baseline());
j++;
if (j >= m_numberOfColumns) {
break;
}
}
return rowBaseline;
}
KDCoordinate GridLayoutNode::rowHeight(int i) const {
KDCoordinate rowHeight = 0;
KDCoordinate baseline = const_cast<GridLayoutNode *>(this)->rowBaseline(i);
for (int j = 0; j < m_numberOfColumns; j++) {
LayoutNode * currentChild = const_cast<GridLayoutNode *>(this)->childAtIndex(i*m_numberOfColumns+j);
rowHeight = maxCoordinate(rowHeight, currentChild->layoutSize().height() - currentChild->baseline());
KDCoordinate underBaseline = 0;
KDCoordinate aboveBaseline = 0;
int j = 0;
for (LayoutNode * l : const_cast<GridLayoutNode *>(this)->childrenFromIndex(i*m_numberOfColumns)) {
KDCoordinate b = l->baseline();
underBaseline = maxCoordinate(underBaseline, l->layoutSize().height() - b);
aboveBaseline = maxCoordinate(aboveBaseline, b);
j++;
if (j >= m_numberOfColumns) {
break;
}
}
return baseline+rowHeight;
return aboveBaseline+underBaseline;
}
KDCoordinate GridLayoutNode::height() const {
@@ -240,14 +249,22 @@ KDCoordinate GridLayoutNode::height() const {
for (int i = 0; i < m_numberOfRows; i++) {
totalHeight += rowHeight(i);
}
totalHeight += maxCoordinate((m_numberOfRows-1)*k_gridEntryMargin, 0);
totalHeight += m_numberOfRows > 0 ? (m_numberOfRows-1)*k_gridEntryMargin : 0;
return totalHeight;
}
KDCoordinate GridLayoutNode::columnWidth(int j) const {
KDCoordinate columnWidth = 0;
for (int i = 0; i < m_numberOfRows; i++) {
columnWidth = maxCoordinate(columnWidth, const_cast<GridLayoutNode *>(this)->childAtIndex(i*m_numberOfColumns+j)->layoutSize().width());
int childIndex = j;
int lastIndex = (m_numberOfRows-1)*m_numberOfColumns + j;
for (LayoutNode * l : const_cast<GridLayoutNode *>(this)->childrenFromIndex(j)) {
if (childIndex%m_numberOfColumns == j) {
columnWidth = maxCoordinate(columnWidth, l->layoutSize().width());
if (childIndex >= lastIndex) {
break;
}
}
childIndex++;
}
return columnWidth;
}
@@ -257,7 +274,7 @@ KDCoordinate GridLayoutNode::width() const {
for (int j = 0; j < m_numberOfColumns; j++) {
totalWidth += columnWidth(j);
}
totalWidth += maxCoordinate(0, (m_numberOfColumns-1)*k_gridEntryMargin);
totalWidth += m_numberOfColumns > 0 ? (m_numberOfColumns-1)*k_gridEntryMargin : 0;
return totalWidth;
}
@@ -268,4 +285,4 @@ void GridLayout::setDimensions(int rows, int columns) {
setNumberOfColumns(columns);
}
}
}

View File

@@ -142,12 +142,17 @@ void MatrixLayoutNode::moveCursorVertically(VerticalDirection direction, LayoutC
bool shouldRemoveGreySquares = false;
int firstIndex = direction == VerticalDirection::Up ? 0 : numberOfChildren() - m_numberOfColumns;
int lastIndex = direction == VerticalDirection::Up ? m_numberOfColumns : numberOfChildren();
for (int childIndex = firstIndex; childIndex < lastIndex; childIndex++) {
if (cursor->layoutReference().hasAncestor(thisRef.childAtIndex(childIndex), true)) {
int i = firstIndex;
for (LayoutNode * l : childrenFromIndex(firstIndex)) {
if (i >= lastIndex) {
break;
}
if (cursor->layoutReference().node()->hasAncestor(l, true)) {
// The cursor is leaving the matrix, so remove the grey squares.
shouldRemoveGreySquares = true;
break;
}
i++;
}
GridLayoutNode::moveCursorVertically(direction, cursor, shouldRecomputeLayout, equivalentPositionVisited);
if (cursor->isDefined() && shouldRemoveGreySquares) {
@@ -160,30 +165,43 @@ void MatrixLayoutNode::moveCursorVertically(VerticalDirection direction, LayoutC
// Private
void MatrixLayoutNode::newRowOrColumnAtIndex(int index) {
assert(index >= 0 && index < m_numberOfColumns*m_numberOfRows);
assert(index >= 0 && index < m_numberOfColumns * m_numberOfRows);
bool shouldAddNewRow = childIsBottomOfGrid(index); // We need to compute this boolean before modifying the layout
int correspondingRow = rowAtChildIndex(index);
if (childIsRightOfGrid(index)) {
assert(m_numberOfRows >= 2);
// Color the grey EmptyLayouts of the column in yellow.
int correspondingColumn = m_numberOfColumns - 1;
for (int i = 0; i < m_numberOfRows - 1; i++) {
LayoutNode * lastLayoutOfRow = childAtIndex(i*m_numberOfColumns+correspondingColumn);
if (lastLayoutOfRow->isEmpty()) {
if (!lastLayoutOfRow->isHorizontal()) {
static_cast<EmptyLayoutNode *>(lastLayoutOfRow)->setColor(EmptyLayoutNode::Color::Yellow);
} else {
assert(lastLayoutOfRow->numberOfChildren() == 1);
static_cast<EmptyLayoutNode *>(lastLayoutOfRow->childAtIndex(0))->setColor(EmptyLayoutNode::Color::Yellow);
int childIndex = correspondingColumn;
int maxIndex = (m_numberOfRows - 2)*m_numberOfColumns+correspondingColumn;
for (LayoutNode * lastLayoutOfRow : childrenFromIndex(correspondingColumn)) {
if (childIndex > maxIndex) {
break;
}
if (childIndex % m_numberOfColumns == correspondingColumn) {
if (lastLayoutOfRow->isEmpty()) {
if (!lastLayoutOfRow->isHorizontal()) {
static_cast<EmptyLayoutNode *>(lastLayoutOfRow)->setColor(EmptyLayoutNode::Color::Yellow);
} else {
assert(lastLayoutOfRow->numberOfChildren() == 1);
static_cast<EmptyLayoutNode *>(lastLayoutOfRow->childAtIndex(0))->setColor(EmptyLayoutNode::Color::Yellow);
}
}
}
childIndex++;
}
// Add a column of grey EmptyLayouts on the right.
addEmptyColumn(EmptyLayoutNode::Color::Grey);
}
if (shouldAddNewRow) {
assert(m_numberOfColumns >= 2);
// Color the grey EmptyLayouts of the row in yellow.
for (int i = 0; i < m_numberOfColumns - 1; i++) {
LayoutNode * lastLayoutOfColumn = childAtIndex(correspondingRow*m_numberOfColumns+i);
int childIndex = correspondingRow * m_numberOfColumns;
int maxIndex = correspondingRow * m_numberOfColumns + m_numberOfColumns - 2;
for (LayoutNode * lastLayoutOfColumn : childrenFromIndex(correspondingRow*m_numberOfColumns)) {
if (childIndex > maxIndex) {
break;
}
if (lastLayoutOfColumn->isEmpty()) {
if (!lastLayoutOfColumn->isHorizontal()) {
static_cast<EmptyLayoutNode *>(lastLayoutOfColumn)->setColor(EmptyLayoutNode::Color::Yellow);
@@ -192,6 +210,7 @@ void MatrixLayoutNode::newRowOrColumnAtIndex(int index) {
static_cast<EmptyLayoutNode *>(lastLayoutOfColumn->childAtIndex(0))->setColor(EmptyLayoutNode::Color::Yellow);
}
}
childIndex++;
}
// Add a row of grey EmptyLayouts at the bottom.
addEmptyRow(EmptyLayoutNode::Color::Grey);
@@ -200,20 +219,30 @@ void MatrixLayoutNode::newRowOrColumnAtIndex(int index) {
bool MatrixLayoutNode::isRowEmpty(int index) const {
assert(index >= 0 && index < m_numberOfRows);
for (int i = index * m_numberOfColumns; i < (index+1) * m_numberOfColumns; i++) {
if (!const_cast<MatrixLayoutNode *>(this)->childAtIndex(i)->isEmpty()) {
int i = index * m_numberOfColumns;
for (LayoutNode * l : const_cast<MatrixLayoutNode *>(this)->childrenFromIndex(index * m_numberOfColumns)) {
if (i >= (index + 1) * m_numberOfColumns) {
break;
}
if (!l->isEmpty()) {
return false;
}
i++;
}
return true;
}
bool MatrixLayoutNode::isColumnEmpty(int index) const {
assert(index >= 0 && index < m_numberOfColumns);
for (int i = index; i < m_numberOfRows * m_numberOfColumns; i+= m_numberOfColumns) {
if (!const_cast<MatrixLayoutNode *>(this)->childAtIndex(i)->isEmpty()) {
int i = index;
for (LayoutNode * l : const_cast<MatrixLayoutNode *>(this)->childrenFromIndex(index)) {
if (i > index + (m_numberOfRows - 1) * m_numberOfColumns) {
break;
}
if (i % m_numberOfColumns == index && !l->isEmpty()) {
return false;
}
i++;
}
return true;
}