blob: a5bc679deb796aa8c847effa46cf3f1aaa5a6f86 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/paint/GridPainter.h"
#include "core/layout/LayoutGrid.h"
#include "core/paint/BlockPainter.h"
#include "core/paint/PaintInfo.h"
#include <algorithm>
namespace blink {
static GridSpan dirtiedGridAreas(const Vector<LayoutUnit>& coordinates,
LayoutUnit start,
LayoutUnit end) {
// This function does a binary search over the coordinates.
// This doesn't work with grid items overflowing their grid areas, but that is
// managed with m_gridItemsOverflowingGridArea.
size_t startGridAreaIndex =
std::upper_bound(coordinates.begin(), coordinates.end() - 1, start) -
coordinates.begin();
if (startGridAreaIndex > 0)
--startGridAreaIndex;
size_t endGridAreaIndex =
std::upper_bound(coordinates.begin() + startGridAreaIndex,
coordinates.end() - 1, end) -
coordinates.begin();
if (endGridAreaIndex > 0)
--endGridAreaIndex;
// GridSpan stores lines' indexes (not tracks' indexes).
return GridSpan::translatedDefiniteGridSpan(startGridAreaIndex,
endGridAreaIndex + 1);
}
class GridItemsSorter {
public:
bool operator()(const std::pair<LayoutBox*, size_t>& firstChild,
const std::pair<LayoutBox*, size_t>& secondChild) const {
if (firstChild.first->style()->order() !=
secondChild.first->style()->order())
return firstChild.first->style()->order() <
secondChild.first->style()->order();
return firstChild.second < secondChild.second;
}
};
void GridPainter::paintChildren(const PaintInfo& paintInfo,
const LayoutPoint& paintOffset) {
ASSERT(!m_layoutGrid.needsLayout());
LayoutRect localPaintInvalidationRect =
LayoutRect(paintInfo.cullRect().m_rect);
localPaintInvalidationRect.moveBy(-paintOffset);
Vector<LayoutUnit> columnPositions = m_layoutGrid.columnPositions();
if (!m_layoutGrid.styleRef().isLeftToRightDirection()) {
// Translate columnPositions in RTL as we need the physical coordinates of
// the columns in order to call dirtiedGridAreas().
for (size_t i = 0; i < columnPositions.size(); i++)
columnPositions[i] =
m_layoutGrid.translateRTLCoordinate(columnPositions[i]);
// We change the order of tracks in columnPositions, as in RTL the leftmost
// track will be the last one.
std::sort(columnPositions.begin(), columnPositions.end());
}
GridSpan dirtiedColumns =
dirtiedGridAreas(columnPositions, localPaintInvalidationRect.x(),
localPaintInvalidationRect.maxX());
GridSpan dirtiedRows = dirtiedGridAreas(m_layoutGrid.rowPositions(),
localPaintInvalidationRect.y(),
localPaintInvalidationRect.maxY());
if (!m_layoutGrid.styleRef().isLeftToRightDirection()) {
// As we changed the order of tracks previously, we need to swap the dirtied
// columns in RTL.
size_t lastLine = columnPositions.size() - 1;
dirtiedColumns = GridSpan::translatedDefiniteGridSpan(
lastLine - dirtiedColumns.endLine(),
lastLine - dirtiedColumns.startLine());
}
Vector<std::pair<LayoutBox*, size_t>> gridItemsToBePainted;
for (const auto& row : dirtiedRows) {
for (const auto& column : dirtiedColumns) {
const Vector<LayoutBox*, 1>& children =
m_layoutGrid.gridCell(row, column);
for (auto* child : children)
gridItemsToBePainted.append(
std::make_pair(child, m_layoutGrid.paintIndexForGridItem(child)));
}
}
for (auto* item : m_layoutGrid.itemsOverflowingGridArea()) {
if (item->frameRect().intersects(localPaintInvalidationRect))
gridItemsToBePainted.append(
std::make_pair(item, m_layoutGrid.paintIndexForGridItem(item)));
}
// Sort grid items following order-modified document order.
// See http://www.w3.org/TR/css-flexbox/#order-modified-document-order
std::stable_sort(gridItemsToBePainted.begin(), gridItemsToBePainted.end(),
GridItemsSorter());
LayoutBox* previous = 0;
for (const auto& gridItemAndPaintIndex : gridItemsToBePainted) {
// We might have duplicates because of spanning children are included in all
// cells they span. Skip them here to avoid painting items several times.
LayoutBox* current = gridItemAndPaintIndex.first;
if (current == previous)
continue;
BlockPainter(m_layoutGrid)
.paintAllChildPhasesAtomically(*current, paintInfo, paintOffset);
previous = current;
}
}
} // namespace blink