Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(659)

Unified Diff: third_party/WebKit/Source/core/paint/TableCollapsedBorderPainter.cpp

Issue 1781463002: Fix table background painting (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Sample code for improved collapsed border painting Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/core/paint/TableCollapsedBorderPainter.cpp
diff --git a/third_party/WebKit/Source/core/paint/TableCollapsedBorderPainter.cpp b/third_party/WebKit/Source/core/paint/TableCollapsedBorderPainter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..58344aab4e0ae6907e719f12da8c5000bdbbcc44
--- /dev/null
+++ b/third_party/WebKit/Source/core/paint/TableCollapsedBorderPainter.cpp
@@ -0,0 +1,1187 @@
+// 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/TableCollapsedBorderPainter.h"
+
+#include "core/layout/LayoutTableCell.h"
+#include "core/layout/LayoutTableCol.h"
+#include "core/paint/BlockPainter.h"
+#include "core/paint/BoxPainter.h"
+#include "core/paint/LayoutObjectDrawingRecorder.h"
+#include "core/paint/PaintInfo.h"
+#include "platform/graphics/GraphicsContextStateSaver.h"
+#include <algorithm>
+
+namespace blink {
+
+// Comparator: returns
+// -1 => e1 < e2
+// 0 => e1 == e2
+// 1 => e1 > e2
+static int compareEdges(const TableCollapsedBorderPainter::EdgeRecord& e1, const TableCollapsedBorderPainter::EdgeRecord& e2)
+{
+
+ // if (!e1.m_border) {
+ // if (!e2.m_border)
+ // return 0;
+ // else
+ // return -1;
+ // }
+ // if (!e2.m_border)
+ // return 1;
+
+ EBorderStyle e1Style = e1.m_border.style();
+ EBorderStyle e2Style = e2.m_border.style();
+
+// RULES: https://www.w3.org/TR/CSS2/tables.html#border-conflict-resolution
+// 1) Hidden edges win
+// 2) None edges lose
+// 3) Wider border-width win
+// 4) Louder border-style win
+// 5) Higher precedence wins
+
+ // Rule #1
+ if (e1Style == BorderStyleHidden) {
+ if (e2Style == BorderStyleHidden)
+ return 0;
+ // else
+ return 1;
+ }
+ if (e2Style == BorderStyleHidden)
+ return -1;
+
+ // Rule #2
+ if (e1Style == BorderStyleNone) {
+ if (e2Style == BorderStyleNone)
+ return 0;
+ // else
+ return -1;
+ }
+ if (e2Style == BorderStyleNone)
+ return 1;
+
+ // Rule #3
+ if (e1.m_border.width() < e2.m_border.width())
+ return -1;
+ // else
+ if (e2.m_border.width() < e1.m_border.width())
+ return 1;
+
+ // Rule #4
+ if (e1Style > e2Style)
+ return 1;
+ // else
+ if (e2Style > e1Style)
+ return -1;
+
+ // Rule #5
+ if (e1.m_precedence != e2.m_precedence)
+ return e1.m_precedence < e2.m_precedence ? -1 : 1;
+
+ return 0;
+}
+
+// Like compareEdges, except that HIDDEN edges lose
+static int compareIntersectionEdges(const TableCollapsedBorderPainter::EdgeRecord& e1, const TableCollapsedBorderPainter::EdgeRecord& e2)
+{
+ EBorderStyle e1Style = e1.m_border.style();
+ EBorderStyle e2Style = e2.m_border.style();
+ // Rule #1
+ if (e1Style == BorderStyleHidden) {
+ if (e2Style == BorderStyleHidden)
+ return 0;
+ // else
+ return -1;
+ }
+ if (e2Style == BorderStyleHidden)
+ return 1;
+ return compareEdges(e1, e2);
+}
+
+#ifndef NDEBUG
+
+static std::string directionToStr(TableCollapsedBorderPainter::EdgeDirection dir)
+{
+ switch (dir) {
+ case TableCollapsedBorderPainter::North: return "North";
+ case TableCollapsedBorderPainter::West: return "West";
+ case TableCollapsedBorderPainter::East: return "East";
+ case TableCollapsedBorderPainter::South: return "South";
+ case TableCollapsedBorderPainter::None: return "None";
+ }
+}
+
+static std::string precedenceToStr(EBorderPrecedence p)
+{
+ switch (p) {
+ case BorderPrecedenceOff: return "OFF";
+ case BorderPrecedenceTable: return "TABLE";
+ case BorderPrecedenceColumnGroup: return "COLGROUP";
+ case BorderPrecedenceColumn: return "COL";
+ case BorderPrecedenceRowGroup: return "ROWGROUP";
+ case BorderPrecedenceRow: return "ROW";
+ case BorderPrecedenceCell: return "CELL";
+ }
+}
+
+void TableCollapsedBorderPainter::showEdge(unsigned row, unsigned col, EdgeDirection direction, EBorderPrecedence precedence, const BorderValue& border, Color resolvedColor) const
+{
+ Color c = border.color().resolve(resolvedColor);
+ LOG(INFO) << "[" << row << " " << col << " " << directionToStr(direction)
+ << "] " << precedenceToStr(precedence) << " "
+ << border.width() << " " << c.serializedAsCSSComponentValue().ascii().data();
+}
+
+void TableCollapsedBorderPainter::showEdges(bool showHidden) const
+{
+ LOG(INFO) << "edges";
+ for (auto r = m_startVisibleRow; r <= m_endVisibleRow; r++) {
+ LOG(INFO) << "row:" << r;
+ for (auto c = m_startVisibleColumn; c < m_endVisibleColumn; c++) {
+ auto edgeIdx = edgeToIndex(r, c, East);
+ if (edgeIdx != npos) {
+ EdgeRecord edge = m_edges[edgeIdx];
+ if (showHidden || edge.m_precedence != BorderPrecedenceOff)
+ showEdge(r, c, East, edge.m_precedence, edge.m_border, edge.m_resolvedColor);
+ }
+ edgeIdx = edgeToIndex(r, c, South);
+ if (edgeIdx != npos) {
+ EdgeRecord edge = m_edges[edgeIdx];
+ if (showHidden || edge.m_precedence != BorderPrecedenceOff)
+ showEdge(r, c, South, edge.m_precedence, edge.m_border, edge.m_resolvedColor);
+ }
+ }
+ }
+}
+void TableCollapsedBorderPainter::showVisibleEdges(const VisibleEdgeContainer& edges) const
+{
+ LOG(INFO) << "visedges";
+ for (auto edge = edges.begin() ; edge < edges.end(); edge++) {
+ showEdge((*edge).m_row, (*edge).m_column, (*edge).m_direction, (*edge).m_precedence, (*edge).m_border, (*edge).m_resolvedColor);
+ }
+}
+
+void TableCollapsedBorderPainter::showIntersection(unsigned row, unsigned col) const
+{
+ auto i = intersectionToIndex(row, col);
+ if (i != npos) {
+ const Intersection in = m_intersections[i];
+ if (in.m_direction != None) {
+ LOG(INFO) << "[" << row << ", " << col << "] "
+ << in.m_width.toInt() << " " << in.m_height.toInt() << " Win:" << directionToStr(in.m_direction);
+ }
+ }
+}
+
+void TableCollapsedBorderPainter::showIntersections() const
+{
+ LOG(INFO) << "intersections";
+ for (auto r = m_startVisibleRow; r <= m_endVisibleRow; r++) {
+ for (auto c = m_startVisibleColumn; c < m_endVisibleColumn; c++) {
+ showIntersection(r, c);
+ }
+ }
+}
+
+#endif
+
+
+void TableCollapsedBorderPainter::paintBorders(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const CellSpan& dirtyRows, const CellSpan& dirtyColumns, const TableCollapsedBorderPainter& previousPainter)
+{
+ initEdges(dirtyRows, dirtyColumns, previousPainter);
+ // draw all the edges
+ // initial algorithm: just draw everything
+ // later algorithms: draw continuous lines if possible
+ initIntersections();
+
+ paintEdges(paintInfo, paintOffset, dirtyRows, dirtyColumns);
+}
+
+void TableCollapsedBorderPainter::initEdges(const CellSpan& dirtyRows, const CellSpan& dirtyColumns, const TableCollapsedBorderPainter& previousPainter)
+{
+ // Initialize sizes
+ // number of rows/cols in the section
+ m_numRows = m_layoutTableSection->numRows();
+ m_numEffectiveColumns = m_layoutTableSection->table()->numEffectiveColumns();
+
+ // Coordinates of intersections whose edges we'd like to measure.
+ // Measurement area is dirtyRows x dirtyCols + single-cell wide border zone above/left
+ // of dirty area.
+ //
+ // Border zone is needed to measure intersections inside dirty area correctly.
+ //
+ // Number of intersections inside n-rows is n+1, inside m-cols is m+1
+ // start and end. End points to one beyond, equivalent to iterator's .end()
+ m_startVisibleRow = dirtyRows.start() == 0 ? 0 : dirtyRows.start() - 1;
+ m_startVisibleColumn = dirtyColumns.start() == 0 ? 0 : dirtyColumns.start() - 1;
+ m_endVisibleRow = dirtyRows.end() + 1;
+ m_endVisibleColumn = dirtyColumns.end() + 1;
+
+ unsigned edgeRowCount = m_endVisibleRow - m_startVisibleRow;
+ unsigned edgeColumnCount = m_endVisibleColumn - m_startVisibleColumn;
+ m_edges.resize(2 * edgeRowCount * edgeColumnCount);
+ populateEdges(dirtyRows, dirtyColumns, previousPainter);
+#ifndef NDEBUG
+ // showEdges();
+#endif
+}
+
+void TableCollapsedBorderPainter::initIntersections()
+{
+ m_maxIntersectionWidth = 0;
+ m_maxIntersectionHeight = 0;
+ m_intersections.resize((m_endVisibleRow - m_startVisibleRow) * (m_endVisibleColumn - m_startVisibleColumn));
+ for (unsigned r = m_startVisibleRow; r < m_endVisibleRow; r++) {
+ for (unsigned c = m_startVisibleColumn; c < m_endVisibleColumn; c++) {
+ initIntersection(r, c);
+ }
+ }
+#ifndef NDEBUG
+ // showIntersections();
+#endif
+}
+
+void TableCollapsedBorderPainter::initIntersection(unsigned row, unsigned col)
+{
+ EdgeRecord edges[None];
+
+ for (int d = North; d < None; d++) {
+ unsigned index = edgeToIndex(row, col, (EdgeDirection)d);
+ if (index != npos)
+ edges[d] = m_edges[index];
+ }
+
+ EdgeDirection winner = North;
+ for (int d = West; d < None; d++) {
+ if (compareIntersectionEdges(edges[winner], edges[d]) == -1)
+ winner = (EdgeDirection)d;
+ }
+
+ unsigned index = intersectionToIndex(row, col);
+ // only set if our winner is really an edge
+ if (edges[winner].m_precedence != BorderPrecedenceOff) {
+ unsigned width = 0;
+ unsigned height = 0;
+ if (winner == North || winner == South) {
+ width = edges[winner].m_border.width();
+ if (compareIntersectionEdges(edges[East], edges[West]) < 1) // West won
+ height = edges[West].m_border.width();
+ else
+ height = edges[East].m_border.width();
+ } else { // winner == East || West
+ height = edges[winner].m_border.width();
+ if (compareIntersectionEdges(edges[North], edges[South]) < 1) // South won
+ width = edges[South].m_border.width();
+ else
+ width = edges[North].m_border.width();
+ }
+ m_maxIntersectionHeight = std::max(m_maxIntersectionHeight, height);
+ m_maxIntersectionWidth = std::max(m_maxIntersectionWidth, width);
+ m_intersections[index] = Intersection(LayoutUnit(width), LayoutUnit(height), winner);
+ // LOG(INFO) << "In: " << row << " " << col << ": " << width << "px " << height << "px " << directionToStr(winner);
+ }
+}
+
+void TableCollapsedBorderPainter::populateEdges(const CellSpan& dirtyRows, const CellSpan& dirtyColumns, const TableCollapsedBorderPainter& previousPainter)
+{
+ VisibleEdgeContainer edges;
+
+ // Iterate everything in reverse priority order
+
+ // populate adjacent edges from adjacent section
+ getVisibleEdgesSiblingSection(edges, previousPainter);
+ mergeVisibleEdges(edges);
+
+ LayoutTable * table = m_layoutTableSection->table();
+ // populate <table>
+ getVisibleEdgesTable(edges, m_layoutTableSection->table());
+ mergeVisibleEdges(edges);
+
+ // populate <colgroup>
+ Vector<const LayoutTableCol*>colgroups;
+ for (LayoutTableCol* colgroup = table->firstColumn(); colgroup; colgroup = colgroup->nextColumn())
+ colgroups.append(colgroup);
+
+ for (auto colGroup = colgroups.rbegin(); colGroup != colgroups.rend(); colGroup++) {
+ if ((*colGroup)->isTableColumnGroup()) {
+ getVisibleEdgesColgroup(edges, *colGroup);
+ mergeVisibleEdges(edges);
+ }
+ }
+ // populate <col>
+ for (auto col = colgroups.rbegin(); col != colgroups.rend(); col++) {
+ if ((*col)->isTableColumn()) {
+ getVisibleEdgesCol(edges, *col);
+ mergeVisibleEdges(edges);
+ }
+ }
+
+ // populate <tbody>
+ getVisibleEdgesSection(edges);
+ mergeVisibleEdges(edges);
+ // populate <tr>
+ for (int r = dirtyRows.end() - 1; r >= (int) dirtyRows.start(); r--) {
+ const LayoutTableRow * row = m_layoutTableSection->rowLayoutObjectAt(r);
+ if (row) {
+ getVisibleEdgesRow(edges, row);
+ mergeVisibleEdges(edges);
+ }
+ }
+ // populate <td>, iterate in reverse
+ TextDirection direction = m_layoutTableSection->style()->direction();
+ for (int r = dirtyRows.end() - 1; r >= (int) dirtyRows.start(); r--) {
+ for (int c = dirtyColumns.end() - 1; c >= (int)dirtyColumns.start(); c--) {
+ // HashSet for primary cell to eliminate duplicates
+ const LayoutTableCell * cell = m_layoutTableSection->primaryCellAt(r, c);
+ if (cell) {
+ getVisibleEdgesCell(edges, cell, direction);
+ mergeVisibleEdges(edges);
+ }
+ }
+ }
+#ifndef NDEBUG
+ // showEdges();
+#endif
+}
+
+// Gets edges of the neighboring section
+void TableCollapsedBorderPainter::getVisibleEdgesSiblingSection(VisibleEdgeContainer& edges, const TableCollapsedBorderPainter& previousPainter)
+{
+ edges.clear();
+
+ bool isAbove = previousPainter.m_layoutTableSection == m_layoutTableSection->table()->sectionAbove(m_layoutTableSection);
+
+ bool isBelow = previousPainter.m_layoutTableSection == m_layoutTableSection->table()->sectionBelow(m_layoutTableSection);
+
+ if (!isAbove && !isBelow) {
+ // Happens if we are the first section
+ // LOG(INFO) << "not sure where sibling section is";
+ return;
+ }
+
+ unsigned siblingRow = isAbove ? previousPainter.m_numRows : 0;
+ unsigned myRow = isAbove ? 0 : m_numRows;
+ for (unsigned c = previousPainter.m_startVisibleColumn; c <= previousPainter.m_endVisibleColumn; c++) {
+ auto siblingIndex = previousPainter.edgeToIndex(siblingRow, c, East);
+ auto myIndex = edgeToIndex(myRow, c, East);
+ if (siblingIndex != npos && myIndex != npos) {
+ EdgeRecord siblingEdge = previousPainter.m_edges[siblingIndex];
+ edges.append(VisibleEdgeRecord(myRow, c, East, siblingEdge.m_border, siblingEdge.m_precedence, siblingEdge.m_resolvedColor));
+ }
+ }
+}
+
+void TableCollapsedBorderPainter::getVisibleEdgesTable(VisibleEdgeContainer& edges, const LayoutTable * table)
+{
+ edges.clear();
+ Color resolvedColor = table->resolveColor(CSSPropertyColor);
+ const ComputedStyle* borderStyle = table->style();
+ const BorderValue* topBorder = &borderStyle->borderTop();
+ const BorderValue* rightBorder = &borderStyle->borderRight();
+ const BorderValue* bottomBorder = &borderStyle->borderBottom();
+ const BorderValue* leftBorder = &borderStyle->borderLeft();
+
+ rotateBorders(m_layoutTableSection->style()->direction(), table->style()->getWritingMode(), &topBorder, &rightBorder, &bottomBorder, &leftBorder);
+
+ // top row, only if we abut table top
+ if (this->m_layoutTableSection == table->topNonEmptySection()) {
+ fillHorizontalEdges(edges, 0, 0, m_numEffectiveColumns, *topBorder, BorderPrecedenceTable, resolvedColor);
+ }
+ // bottom row, only if we abut table bottom
+ if (this->m_layoutTableSection == table->bottomNonEmptySection()) {
+ fillHorizontalEdges(edges, m_numRows, 0, m_numEffectiveColumns, *bottomBorder, BorderPrecedenceTable, resolvedColor);
+ }
+ fillVerticalEdges(edges, 0, 0, m_numRows, *leftBorder, BorderPrecedenceTable, resolvedColor);
+ fillVerticalEdges(edges, m_numEffectiveColumns, 0, m_numRows, *rightBorder, BorderPrecedenceTable, resolvedColor);
+}
+
+void TableCollapsedBorderPainter::getVisibleEdgesSection(VisibleEdgeContainer& edges)
+{
+ edges.clear();
+ Color resolvedColor = m_layoutTableSection->resolveColor(CSSPropertyColor);
+ // Traverse all the section edges, and assign them
+ fillVisibleRect(edges, 0, 0, m_numRows, m_numEffectiveColumns, m_layoutTableSection->style(),
+ LTR, m_layoutTableSection->style()->getWritingMode(), resolvedColor, BorderPrecedenceRowGroup);
+}
+
+void TableCollapsedBorderPainter::getVisibleEdgesColgroup(VisibleEdgeContainer& edges, const LayoutTableCol * colgroup)
+{
+ edges.clear();
+ Color resolvedColor = colgroup->resolveColor(CSSPropertyColor);
+ Vector<unsigned> indexes = colgroup->getEffectiveColumnIndexes();
+ if (indexes.size() > 0) {
+ unsigned startColIndex = indexes[0];
+ unsigned endColIndex = indexes.last() + 1;
+ fillVisibleRect(edges, 0, startColIndex, m_numRows, endColIndex, colgroup->style(),
+ colgroup->style()->direction(), colgroup->style()->getWritingMode(), resolvedColor, BorderPrecedenceColumnGroup);
+ }
+}
+
+void TableCollapsedBorderPainter::getVisibleEdgesCol(VisibleEdgeContainer& edges, const LayoutTableCol * col)
+{
+ edges.clear();
+ Color resolvedColor = col->resolveColor(CSSPropertyColor);
+ LayoutTable* table = m_layoutTableSection->table();
+ if (!table)
+ return;
+
+ Vector<unsigned> indexes = col->getEffectiveColumnIndexes();
+ if (indexes.size() > 0) {
+ // fill multiple virtual columns
+ for (auto idx = indexes.rbegin(); idx!= indexes.rend(); ++idx) {
+ fillVisibleRect(edges, 0, *idx, m_numRows, *idx + 1, col->style(),
+ col->style()->direction(), col->style()->getWritingMode(), resolvedColor, BorderPrecedenceColumn);
+ }
+ }
+ // unsigned startAbsoluteColIndex = table->colElementToAbsoluteColumn(col);
+ // unsigned endAbsoluteColIndex = startAbsoluteColIndex + col->span();
+ // unsigned startColIndex = table->absoluteColumnToEffectiveColumn(startAbsoluteColIndex);
+ // unsigned endColIndex = table->absoluteColumnToEffectiveColumn(endAbsoluteColIndex);
+
+ // // We replicat column span times. Weird, but that is the standard:
+ // // "For the purposes of the CSS table model, the col element is expected to be treated as if it was present as many times as its span attribute specifies."
+ // for (auto tmpEnd = endColIndex; tmpEnd > startColIndex; tmpEnd--) {
+ // fillVisibleRect(edges, 0, tmpEnd - 1, m_numRows, tmpEnd, col->style(),
+ // col->style()->direction(), col->style()->getWritingMode(), resolvedColor, BorderPrecedenceColumn);
+ // }
+}
+
+void TableCollapsedBorderPainter::getVisibleEdgesRow(VisibleEdgeContainer& edges, const LayoutTableRow * row)
+{
+ edges.clear();
+ Color resolvedColor = row->resolveColor(CSSPropertyColor);
+ unsigned rowIndex = row->rowIndex();
+ // We get direction from section because row direction only applies to cells,
+ // not the entire row.
+ fillVisibleRect(edges, rowIndex, 0, rowIndex + 1, m_numEffectiveColumns, row->style(),
+ m_layoutTableSection->style()->direction(), row->style()->getWritingMode(), resolvedColor, BorderPrecedenceRow);
+}
+
+void TableCollapsedBorderPainter::getVisibleEdgesCell(VisibleEdgeContainer& edges, const LayoutTableCell * cell, TextDirection direction)
+{
+ edges.clear();
+ Color resolvedColor = cell->resolveColor(CSSPropertyColor);
+
+ if (!cell->parent()) {
+ LOG(INFO) << "DETACHED CELL";
+ return;
+ }
+
+ const LayoutTable * table = m_layoutTableSection->table();
+ unsigned startRow = cell->parent() ? cell->rowIndex() : 65000;
+ unsigned absoluteCol = cell->absoluteColumnIndex();
+
+
+ unsigned effStartCol = table->absoluteColumnToEffectiveColumn(absoluteCol);
+ unsigned effEndCol = table->absoluteColumnToEffectiveColumn(absoluteCol + cell->colSpan());
+ unsigned endRow = std::min(startRow + cell->rowSpan(), m_numRows);
+
+ // LOG(INFO) << "m_columns: " << table->effectiveColumns().size()
+ // << " startRow: " << startRow << " endRow: " << endRow
+ // << " startCol: " << effStartCol << " endCol:" << effEndCol
+ // << " abscol:" << absoluteCol;
+
+ // Fill border
+ // cell's direction is LTR because we do not rotate cell's borders
+ fillVisibleRect(edges, startRow, effStartCol, endRow, effEndCol, cell->style(),
+ direction, cell->style()->getWritingMode(), resolvedColor, BorderPrecedenceCell);
+
+ // Hide row inner edges
+ for (unsigned row = startRow + 1; row < endRow; row++) {
+ if (row >= m_startVisibleRow && row < m_endVisibleRow) {
+ for (unsigned effCol = effStartCol; effCol < effEndCol; effCol++) {
+ if (effCol >= m_startVisibleColumn && effCol < m_endVisibleColumn) {
+ edges.append(VisibleEdgeRecord(row, effCol, East, m_hiddenBorder, BorderPrecedenceCell, resolvedColor, true));
+ }
+ }
+ }
+ }
+ // Hide col inner edges
+ for (unsigned effCol = effStartCol + 1; effCol < effEndCol; effCol++) {
+ if (effCol >= m_startVisibleColumn && effCol < m_endVisibleColumn) {
+ for (unsigned row = startRow; row < endRow; row++) {
+ if (row >= m_startVisibleRow && row < m_endVisibleRow) {
+ edges.append(VisibleEdgeRecord(row, effCol, South, m_hiddenBorder, BorderPrecedenceCell, resolvedColor, true));
+ }
+ }
+ }
+ }
+#ifdef NDEBUG
+ // showVisibleEdges(edges);
+#endif
+}
+
+
+void TableCollapsedBorderPainter::rotateBorders(TextDirection textDirection, WritingMode writingMode,
+ const BorderValue** top, const BorderValue** right, const BorderValue** bottom, const BorderValue** left) const
+{
+ bool isLTR = blink::isLeftToRightDirection(textDirection);
+ if (blink::isHorizontalWritingMode(writingMode)) {
+ if (isLTR)
+ {} // do nothing
+ else {
+ std::swap(*right, *left);
+ }
+ } else if (blink::isFlippedBlocksWritingMode(writingMode)) {
+ if (isLTR) {
+ auto tmp = *top;
+ *top = *right;
+ *right = *bottom;
+ *bottom = *left;
+ *left = tmp;
+ } else {
+ std::swap(*top, *right);
+ std::swap(*bottom, *left);
+ }
+ } else { // isFlippedLinesWritingMode
+ if (isLTR) {
+ std::swap(*bottom, *right);
+ std::swap(*left, *top);
+ } else {
+ auto tmp = *top;
+ *top = *left;
+ *left = *bottom;
+ *bottom = *right;
+ *right = tmp;
+ }
+ }
+}
+
+void TableCollapsedBorderPainter::fillVisibleRect(VisibleEdgeContainer& edges,
+ unsigned startRow, unsigned startColumn, unsigned endRow, unsigned endColumn,
+ const ComputedStyle* borderStyle, TextDirection textDirection, WritingMode writingMode,
+ Color resolvedColor, EBorderPrecedence precedence)
+{
+ const BorderValue* topBorder = &borderStyle->borderTop();
+ const BorderValue* bottomBorder = &borderStyle->borderBottom();
+ const BorderValue* rightBorder = &borderStyle->borderRight();
+ const BorderValue* leftBorder = &borderStyle->borderLeft();
+
+ rotateBorders(textDirection, writingMode, &topBorder, &rightBorder, &bottomBorder, &leftBorder);
+
+ fillHorizontalEdges(edges, startRow, startColumn, endColumn, *topBorder, precedence, resolvedColor);
+ fillHorizontalEdges(edges, endRow, startColumn, endColumn, *bottomBorder, precedence, resolvedColor);
+ fillVerticalEdges(edges, startColumn, startRow, endRow, *leftBorder, precedence, resolvedColor);
+ fillVerticalEdges(edges, endColumn, startRow, endRow, *rightBorder, precedence, resolvedColor);
+}
+
+void TableCollapsedBorderPainter::fillHorizontalEdges(VisibleEdgeContainer& edges, unsigned row, unsigned startColumn, unsigned endColumn,
+ const BorderValue &border, EBorderPrecedence precedence, Color resolvedColor)
+{
+ if (border.style() == BorderStyleNone)
+ return;
+
+ if (row >= m_startVisibleRow && row < m_endVisibleRow) {
+ for (unsigned c = startColumn; c < endColumn; c++) {
+ // FIXME: modify for loop instead of comparing guard
+ if (c >= m_startVisibleColumn && c < m_endVisibleColumn)
+ edges.append(VisibleEdgeRecord(row, c, East, border, precedence, resolvedColor));
+ }
+ }
+}
+
+void TableCollapsedBorderPainter::fillVerticalEdges(VisibleEdgeContainer& edges, unsigned column, unsigned startRow, unsigned endRow, const BorderValue &border, EBorderPrecedence precedence, Color resolvedColor)
+{
+ if (border.style() == BorderStyleNone)
+ return;
+
+ if (column >= m_startVisibleColumn && column < m_endVisibleColumn) {
+ for (unsigned r = startRow; r < endRow; r++) {
+ // FIXME: modify for loop instead of comparing guard
+ if (r >= m_startVisibleRow && r < m_endVisibleRow)
+ edges.append(VisibleEdgeRecord(r, column, South, border, precedence, resolvedColor));
+ }
+ }
+}
+
+void TableCollapsedBorderPainter::mergeVisibleEdges(VisibleEdgeContainer& edges)
+{
+ for (auto edge = edges.begin(); edge < edges.end(); edge++) {
+ unsigned idx = edgeToIndex((*edge).m_row, (*edge).m_column, (*edge).m_direction);
+ ASSERT(idx != npos);
+ EdgeRecord edgeRecord((*edge).m_border, (*edge).m_precedence, (*edge).m_resolvedColor);
+ if ((*edge).m_forceRemoval)
+ m_edges[idx] = edgeRecord;
+ // if both edges are same priority, new edge wins
+ if (compareEdges(m_edges[idx], edgeRecord ) != 1)
+ m_edges[idx] = edgeRecord;
+ }
+}
+
+static EBorderStyle collapsedBorderStyle(EBorderStyle style)
+{
+ if (style == BorderStyleOutset)
+ return BorderStyleGroove;
+ if (style == BorderStyleInset)
+ return BorderStyleRidge;
+ return style;
+}
+
+void TableCollapsedBorderPainter::paintEdges(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, const CellSpan& rows, const CellSpan& cols)
+{
+ // see TableCellPainter::paintCollapsedBorders
+ LayoutRect paintRect = m_layoutTableSection->getCellPhysicalPosition(rows.start(), cols.start());
+ paintRect.unite(m_layoutTableSection->getCellPhysicalPosition(rows.end() > 0 ? rows.end() - 1 : 0, cols.end() > 0 ? cols.end() - 1 : 0));
+
+ // paintRect size calculation is not exact, we expand by maxborder, instead of exact border
+ paintRect.expand(LayoutSize(LayoutUnit(m_maxIntersectionWidth * 2), LayoutUnit(m_maxIntersectionHeight * 2)));
+ paintRect.moveBy(paintOffset);
+
+ LayoutPoint location = m_layoutTableSection->location();
+ paintRect.moveBy(location);
+
+ if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible(
+ paintInfo.context,
+ *m_layoutTableSection,
+ DisplayItem::TableCollapsedBorderBase))
+ return;
+ LayoutObjectDrawingRecorder recorder(
+ paintInfo.context,
+ *m_layoutTableSection,
+ DisplayItem::TableCollapsedBorderBase,
+ paintRect);
+
+ // Paint edges carefully to get them all
+ // Every row paint : ┌┌┌┌┌, then |
+ // Bottom border paint: _____
+ WritingMode writingMode = m_layoutTableSection->style()->getWritingMode();
+ TextDirection textDirection = m_layoutTableSection->style()->direction();
+ for (unsigned r = rows.start(); r < rows.end(); r++) {
+ // const LayoutTableRow * row = m_layoutTableSection->rowLayoutObjectAt(r);
+ // if (row)
+ // textDirection = row->style()->direction();
+ for (unsigned c = cols.start(); c < cols.end(); c++) {
+ paintOneEdge(paintInfo, paintOffset, r, c, East, writingMode, textDirection);
+ paintOneEdge(paintInfo, paintOffset, r, c, South, writingMode, textDirection);
+ }
+ // paint the last column on edge
+ paintOneEdge(paintInfo, paintOffset, r, cols.end(), South, writingMode, textDirection);
+ }
+ // Paint the last row
+ for (unsigned c = cols.start(); c < cols.end(); c++)
+ paintOneEdge(paintInfo, paintOffset, rows.end(), c, East, writingMode, textDirection);
+}
+
+// Returns a rect that encloses 'direction' border of the cellRect
+LayoutRect TableCollapsedBorderPainter::cellRectAsBorder(const LayoutRect& cellRect, BoxSide side, unsigned borderWidth, WritingMode writingMode, TextDirection textDirection)
+{
+
+ unsigned smallHalf = borderWidth / 2; // C++ always rounds down
+ unsigned bigHalf = borderWidth - smallHalf;
+
+ unsigned topOffset;
+ unsigned leftOffset;
+
+ /* Tricky: if the border width is odd, we need a consistent way of
+ distributing the extra pixel. The rule is:
+ - south and east edges always get the extra pixel on the inside
+ of the cell
+ */
+
+ bool isLTR = blink::isLeftToRightDirection(textDirection);
+ if (blink::isHorizontalWritingMode(writingMode)) {
+ if (isLTR) {
+ topOffset = smallHalf;
+ leftOffset = smallHalf;
+ } else {
+ topOffset = smallHalf;
+ leftOffset = bigHalf;
+ }
+ } else { // vertical
+ if (blink::isFlippedBlocksWritingMode(writingMode)) {
+ if (isLTR) {
+ topOffset = smallHalf;
+ leftOffset = bigHalf;
+ } else {
+ topOffset = bigHalf;
+ leftOffset = bigHalf;
+ }
+ } else { // flippedLines
+ if (isLTR) {
+ topOffset = smallHalf;
+ leftOffset = smallHalf;
+ } else {
+ topOffset = bigHalf;
+ leftOffset = smallHalf;
+ }
+ }
+ }
+ switch (side) {
+ case BSTop:
+ return LayoutRect(
+ LayoutPoint(cellRect.x(), cellRect.y() - topOffset),
+ LayoutSize(cellRect.width(), LayoutUnit(borderWidth)));
+ case BSBottom:
+ return LayoutRect(
+ LayoutPoint(cellRect.x(), cellRect.maxY() - topOffset),
+ LayoutSize(cellRect.width(), LayoutUnit(borderWidth)));
+ case BSLeft:
+ return LayoutRect(
+ LayoutPoint(cellRect.x() - leftOffset, cellRect.y()),
+ LayoutSize(LayoutUnit(borderWidth), cellRect.height()));
+ case BSRight:
+ return LayoutRect(
+ LayoutPoint(cellRect.maxX() - leftOffset, cellRect.y()),
+ LayoutSize(LayoutUnit(borderWidth), cellRect.height()));
+ }
+
+}
+//
+LayoutRect TableCollapsedBorderPainter::edgePaintPosition(unsigned row, unsigned col, unsigned borderWidth, EdgeDirection direction, WritingMode writingMode, TextDirection textDirection)
+{
+ // Compute edge's size from size of the cell
+ LayoutRect position;
+
+ bool isLTR = blink::isLeftToRightDirection(textDirection);
+ BoxSide side = BSLeft;
+ LayoutRect cellRect;
+ // If this is the last row intersection, get size from cell in next to last
+ if (row == m_numRows) {
+ ASSERT(direction == East);
+ cellRect = getCellPhysicalPosition(row - 1, col);
+ if (blink::isHorizontalWritingMode(writingMode)) {
+ side = BSBottom;
+ } else if (blink::isFlippedBlocksWritingMode(writingMode)) {
+ side = BSLeft;
+ } else {
+ side = BSRight;
+ }
+ } else if (col == m_numEffectiveColumns) {
+ // If this is the last column, get size from the cell before
+ ASSERT(direction == South);
+ cellRect = getCellPhysicalPosition(row, col - 1);
+ if (blink::isHorizontalWritingMode(writingMode)) {
+ side = isLTR ? BSRight : BSLeft;
+ } else if (blink::isFlippedBlocksWritingMode(writingMode)) {
+ side = isLTR ? BSBottom : BSTop;
+ } else {
+ side = isLTR ? BSBottom : BSTop;
+ }
+ } else {
+ cellRect = getCellPhysicalPosition(row, col);
+ if (direction == East) {
+ if (blink::isHorizontalWritingMode(writingMode)) {
+ side = BSTop;
+ } else if (blink::isFlippedBlocksWritingMode(writingMode)) {
+ side = BSRight;
+ } else {
+ side = BSLeft;
+ }
+ } else { // direction == South
+ if (blink::isHorizontalWritingMode(writingMode)) {
+ side = isLTR ? BSLeft : BSRight;
+ } else if (blink::isFlippedBlocksWritingMode(writingMode)) {
+ side = isLTR ? BSTop : BSBottom;
+ } else { // flippedLines
+ side = isLTR ? BSTop : BSBottom;
+ }
+ }
+ }
+ return cellRectAsBorder(cellRect, side, borderWidth, writingMode, textDirection);
+}
+
+// Paints an edge starting from intersection[row, col] in direction
+void TableCollapsedBorderPainter::paintOneEdge(
+ const PaintInfo& paintInfo, const LayoutPoint& paintOffset,
+ unsigned row, unsigned col, EdgeDirection direction,
+ WritingMode writingMode, TextDirection textDirection)
+{
+ ASSERT(direction == South || direction == East);
+
+ unsigned idx = edgeToIndex(row, col, direction);
+ ASSERT(idx != npos);
+ const BorderValue& border = m_edges[idx].m_border;
+
+ if (border.style() == BorderStyleHidden || !border.nonZero())
+ return;
+
+#ifndef NDEBUG
+ // LOG(INFO) << "painting";
+ // EdgeRecord edge = m_edges[idx];
+ // showEdge(row, col, direction, edge.m_precedence, edge.m_border, border->color().resolve(m_edges[idx].m_resolvedColor));
+#endif
+ LayoutRect position = edgePaintPosition(row, col, border.width(), direction, writingMode, textDirection);
+
+ // LOG(INFO) << "paint " << position.x().toInt() << ", " << position.y().toInt() << "; "
+ // << position.width().toInt() << ", " << position.height().toInt();
+
+ adjustForIntersections(position, row, col, direction, writingMode, textDirection);
+
+ // LOG(INFO) << "intersection " << position.x().toInt() << ", " << position.y().toInt() << "; "
+ // << position.width().toInt() << ", " << position.height().toInt();
+
+ // Offset by sectionLocation
+ LayoutPoint sectionLocation = m_layoutTableSection->location();
+ position.moveBy(sectionLocation);
+ position.moveBy(paintOffset);
+
+ BoxSide side;
+ if (blink::isHorizontalWritingMode(writingMode))
+ side = direction == East ? BSTop : BSLeft;
+ else
+ side = direction == East ? BSLeft : BSTop;
+
+ ObjectPainter::drawLineForBoxSide(
+ paintInfo.context,
+ position.x(), position.y(), position.maxX(), position.maxY(), // left, top, right, bottom,
+ side,
+ border.color().resolve(m_edges[idx].m_resolvedColor),
+ collapsedBorderStyle(border.style()),
+ 0, 0, true);
+}
+
+void TableCollapsedBorderPainter::adjustForIntersections(LayoutRect& position, unsigned row, unsigned col, EdgeDirection direction, WritingMode writingMode, TextDirection textDirection)
+{
+
+ ASSERT(direction == South || direction == East);
+
+ const Intersection * startIntersection = nullptr;
+ const Intersection * endIntersection = nullptr;
+ bool winnerStart = false;
+ bool winnerEnd = false;
+ // START intersection
+ unsigned index = intersectionToIndex(row, col);
+ if (index != npos) {
+ startIntersection = &m_intersections[index];
+ winnerStart = startIntersection->m_direction == direction;
+ }
+ // END intersection
+ if (direction == South)
+ row += 1;
+ else
+ col += 1;
+ index = intersectionToIndex(row, col);
+ if (index != npos) {
+ endIntersection = &m_intersections[index];
+ if (direction == South)
+ winnerEnd = endIntersection->m_direction == North;
+ else
+ winnerEnd = endIntersection->m_direction == West;
+ }
+
+ bool isLTR = blink::isLeftToRightDirection(textDirection);
+
+ if (blink::isHorizontalWritingMode(writingMode))
+ adjustForIntersectionsHorizontal(position, direction, isLTR, startIntersection, winnerStart, endIntersection, winnerEnd);
+ else if (blink::isFlippedBlocksWritingMode(writingMode))
+ adjustForIntersectionsFlippedBlocks(position, direction, isLTR, startIntersection, winnerStart, endIntersection, winnerEnd);
+ else if (blink::isFlippedLinesWritingMode(writingMode))
+ adjustForIntersectionsFlippedLines(position, direction, isLTR, startIntersection, winnerStart, endIntersection, winnerEnd);
+ else
+ ASSERT(false);
+}
+
+/*
+writing-mode: HORIZONTAL-TB
+ N
+compass: W--+--E intersection: <--width -->
+ S
+ start intersection
+ South edge, win : expand top by height/2
+ South edge, lose: shrink top by height/2
+ East edge, win : expand left by width/2
+ East edge, lose : shrink left by width/2
+ end intersection
+ South edge, win : expand bottom by height/2
+ South edge lose : shrink bottom by height/2
+ East edge, win : expand right by width/2
+ East edge, lose : shrink right by width/2
+
+writing-mode: HORIZONTAL(RTL)
+ N
+compass: E--+--W intersection: <-- width -->
+ S
+same as HORIZONTAL-TB in South direction
+ start intersection
+ South: same as LTR
+ East edge, win : expand right by width/2
+ East edge, lose : shrink right by width/2
+ end intersection
+ South: same as LTR
+ East edge, win : expand left by width/2
+ East edge, lose : shrink left by width/2
+*/
+void TableCollapsedBorderPainter::adjustForIntersectionsHorizontal(LayoutRect& position, EdgeDirection direction, bool isLTR,
+ const Intersection* startIntersection, bool winnerStart,
+ const Intersection* endIntersection, bool winnerEnd)
+{
+ if (startIntersection) {
+
+ if (direction == South) {
+ unsigned smallDelta = startIntersection->m_height.toUnsigned() / 2;
+ unsigned bigDelta = startIntersection->m_height.toUnsigned() - smallDelta;
+ if (winnerStart)
+ position.expandEdges(LayoutUnit(smallDelta), LayoutUnit(0), LayoutUnit(0), LayoutUnit(0));
+ else
+ position.contractEdges(LayoutUnit(bigDelta), LayoutUnit(0), LayoutUnit(0), LayoutUnit(0));
+ } else { // East
+ unsigned smallDelta = startIntersection->m_width.toUnsigned() / 2;
+ unsigned bigDelta = startIntersection->m_width.toUnsigned() - smallDelta;
+ if (isLTR) {
+ if (winnerStart) {
+ position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0), LayoutUnit(smallDelta));
+ } else {
+ position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0), LayoutUnit(bigDelta));
+ }
+ } else { // RTL
+ if (winnerStart) {
+ position.expandEdges(LayoutUnit(0), LayoutUnit(smallDelta), LayoutUnit(0), LayoutUnit(0));
+ } else {
+ position.contractEdges(LayoutUnit(0), LayoutUnit(bigDelta), LayoutUnit(0), LayoutUnit(0));
+ }
+ }
+ }
+ }
+ if (endIntersection) {
+ if (direction == South) {
+ unsigned smallDelta = endIntersection->m_height.toUnsigned() / 2;
+ unsigned bigDelta = endIntersection->m_height.toUnsigned() - smallDelta;
+ if (winnerEnd)
+ position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(bigDelta), LayoutUnit(0));
+ else
+ position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(smallDelta), LayoutUnit(0));
+ } else { // East
+ unsigned smallDelta = endIntersection->m_width.toUnsigned() / 2;
+ unsigned bigDelta = endIntersection->m_width.toUnsigned() - smallDelta;
+ if (isLTR) {
+ if (winnerEnd) {
+ position.expandEdges(LayoutUnit(0), LayoutUnit(bigDelta), LayoutUnit(0), LayoutUnit(0));
+ } else { // loser
+ position.contractEdges(LayoutUnit(0), LayoutUnit(smallDelta), LayoutUnit(0), LayoutUnit(0));
+ }
+ } else { // RTL
+ if (winnerEnd)
+ position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0), LayoutUnit(bigDelta));
+ else
+ position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0), LayoutUnit(smallDelta));
+ }
+ }
+ }
+}
+
+/*
+writing-mode: VERTICAL-RL (flipped blocks)
+ W
+compass: vertical: S--+--N intersection: <--- height ---->
+ E
+
+ start intersection
+ South edge, win : expand right by height/2
+ South edge, lose: shrink right by height/2
+ East edge, win : expand top by width/2
+ East edge, lose : shrink top by width/2
+ end intersection
+ South edge, win : expand left by height/2
+ South edge, lose: shrink left by height/2
+ East edge, win : expand bottom by width/2
+ East edge, lose : shrink bottom by width/2
+
+writing-mode: VERTICAL-RL RTL
+ E
+compass: vertical: S--+--N intersection: <--- height ---->
+ W
+ start intersection
+ South edge, win : expand right by height/2
+ South edge, lose: shrink right by height/2
+ East edge, win : expand bottom by width/2
+ East edge, lose : shrink bottom by width/2
+ end intersection
+ South edge, win : expand left by height/2
+ South edge, lose: shrink left by height/2
+ East edge, win : expand top by width/2
+ East edge, lose : shrink top by width/2
+
+*/
+void TableCollapsedBorderPainter::adjustForIntersectionsFlippedBlocks(LayoutRect& position, EdgeDirection direction, bool isLTR,
+ const Intersection* startIntersection, bool winnerStart,
+ const Intersection* endIntersection, bool winnerEnd)
+{
+ if (startIntersection) {
+
+ if (direction == South) {
+ unsigned smallDelta = startIntersection->m_height.toUnsigned() / 2;
+ unsigned bigDelta = startIntersection->m_height.toUnsigned() - smallDelta;
+ if (winnerStart)
+ position.expandEdges(LayoutUnit(0), LayoutUnit(smallDelta), LayoutUnit(0), LayoutUnit(0));
+ else
+ position.contractEdges(LayoutUnit(0), LayoutUnit(bigDelta), LayoutUnit(0), LayoutUnit(0));
+ } else { // East
+ unsigned smallDelta = startIntersection->m_width.toUnsigned() / 2;
+ unsigned bigDelta = startIntersection->m_width.toUnsigned() - smallDelta;
+ if (isLTR) {
+ if (winnerStart) {
+ position.expandEdges(LayoutUnit(smallDelta), LayoutUnit(0), LayoutUnit(0), LayoutUnit(0));
+ } else {
+ position.contractEdges(LayoutUnit(bigDelta), LayoutUnit(0), LayoutUnit(0), LayoutUnit(0));
+ }
+ } else { // RTL
+ if (winnerStart) {
+ position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(bigDelta), LayoutUnit(0));
+ } else {
+ position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(smallDelta), LayoutUnit(0));
+ }
+ }
+ }
+ }
+ if (endIntersection) {
+ if (direction == South) {
+ unsigned smallDelta = endIntersection->m_height.toUnsigned() / 2;
+ unsigned bigDelta = endIntersection->m_height.toUnsigned() - smallDelta;
+ if (winnerEnd)
+ position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0), LayoutUnit(bigDelta));
+ else
+ position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0), LayoutUnit(smallDelta));
+ } else { // East
+ unsigned smallDelta = endIntersection->m_width.toUnsigned() / 2;
+ unsigned bigDelta = endIntersection->m_width.toUnsigned() - smallDelta;
+ if (isLTR) {
+ if (winnerEnd)
+ position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(bigDelta), LayoutUnit(0));
+ else // loser
+ position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(smallDelta), LayoutUnit(0));
+ } else { // RTL
+ if (winnerEnd)
+ position.expandEdges(LayoutUnit(bigDelta), LayoutUnit(0), LayoutUnit(0), LayoutUnit(0));
+ else
+ position.contractEdges(LayoutUnit(smallDelta), LayoutUnit(0), LayoutUnit(0), LayoutUnit(0));
+ }
+ }
+ }
+}
+
+/*
+writing-mode: VERTICAL-LR (flipped lines)
+ W
+compass: rotated N--+--S
+ E
+ start intersection
+ East edge, win : expand top by width/2
+ East edge, lose : shrink top by width/2
+ South edge, win : expand left by height/2
+ South edge, lose: shrink left by height/2
+ end intersection
+ East edge, win : expand bottom by width/2
+ East edge, lose : shrink bottom by width/2
+ South edge, win : expand right by height/2
+ South edge lose : shrink right by height/2
+
+writing-mode: VERTICAL-LR, DIRECTION RTL
+ E
+compass: N-+-S intersection <--height -->
+ W
+ start intersection
+ East edge. win : expand bottom by width / 2
+ East edge, lose: shrink bottom by width / 2
+ end intersection
+ East edge, win : expand top by width / 2
+ East edge, lose: expand top by width / 2
+*/
+
+void TableCollapsedBorderPainter::adjustForIntersectionsFlippedLines(LayoutRect& position, EdgeDirection direction, bool isLTR,
+ const Intersection* startIntersection, bool winnerStart,
+ const Intersection* endIntersection, bool winnerEnd)
+{
+ if (startIntersection) {
+
+ if (direction == South) {
+ unsigned smallDelta = startIntersection->m_height.toUnsigned() / 2;
+ unsigned bigDelta = startIntersection->m_height.toUnsigned() - smallDelta;
+ if (winnerStart)
+ position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0), LayoutUnit(smallDelta));
+ else
+ position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0), LayoutUnit(bigDelta));
+ } else { // East
+ unsigned smallDelta = startIntersection->m_width.toUnsigned() / 2;
+ unsigned bigDelta = startIntersection->m_width.toUnsigned() - smallDelta;
+ if (isLTR) {
+ if (winnerStart) {
+ position.expandEdges(LayoutUnit(smallDelta), LayoutUnit(0), LayoutUnit(0), LayoutUnit(0));
+ } else {
+ position.contractEdges(LayoutUnit(bigDelta), LayoutUnit(0), LayoutUnit(0), LayoutUnit(0));
+ }
+ } else { // RTL
+ if (winnerStart) {
+ position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(smallDelta), LayoutUnit(0));
+ } else {
+ position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(bigDelta), LayoutUnit(0));
+ }
+ }
+ }
+ }
+ if (endIntersection) {
+ if (direction == South) {
+ unsigned smallDelta = endIntersection->m_height.toUnsigned() / 2;
+ unsigned bigDelta = endIntersection->m_height.toUnsigned() - smallDelta;
+ if (winnerEnd)
+ position.expandEdges(LayoutUnit(0), LayoutUnit(bigDelta), LayoutUnit(0), LayoutUnit(0));
+ else
+ position.contractEdges(LayoutUnit(0), LayoutUnit(smallDelta), LayoutUnit(0), LayoutUnit(0));
+ } else { // East
+ unsigned smallDelta = endIntersection->m_width.toUnsigned() / 2;
+ unsigned bigDelta = endIntersection->m_width.toUnsigned() - smallDelta;
+ if (isLTR) {
+ if (winnerEnd) {
+ position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(bigDelta), LayoutUnit(0));
+ } else { // loser
+ position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(smallDelta), LayoutUnit(0));
+ }
+ } else { // RTL
+ if (winnerEnd) {
+ position.expandEdges(LayoutUnit(bigDelta), LayoutUnit(0), LayoutUnit(0), LayoutUnit(0));
+ } else {
+ position.contractEdges(LayoutUnit(smallDelta), LayoutUnit(0), LayoutUnit(0), LayoutUnit(0));
+ }
+ }
+ }
+ }
+}
+
+// returns edge index for position, TableCollapsedBorderPainter::npos if out of range
+// topLeft intersection is 0, 0, bottomRight is numRows+1, numColumns + 1
+unsigned TableCollapsedBorderPainter::edgeToIndex(unsigned intersectionRow, unsigned intersectionColumn, EdgeDirection direction) const
+{
+/* Edges map to m_edges like this:
+ - each intersection 'stores' only two edges: east and south edges
+ - to map edge to index:
+ - find intersection so that requested edge is east or south
+ - edge is row * cols * 2 + (east ? 0 : 1)
+ - for example:
+ - North edge at intersection 5, 3, is also South edge at intersection 4, 3
+ - its index is 4 (rows) * 3 (cols) * 2 + 1 (for South)
+*/
+ switch (direction) {
+ case North:
+ intersectionRow -= 1;
+ direction = South;
+ break;
+ case West:
+ intersectionColumn -= 1;
+ direction = East;
+ break;
+ case South:
+ case East:
+ case None:
+ break;
+ }
+ // Check if we are inside the covered area
+ if (intersectionRow < m_startVisibleRow || intersectionColumn < m_startVisibleColumn
+ || intersectionRow >= m_endVisibleRow || intersectionColumn >= m_endVisibleColumn) {
+ // LOG(ERROR) << "GOT AN NPOS";
+ return TableCollapsedBorderPainter::npos;
+ }
+
+ unsigned index = (intersectionRow - m_startVisibleRow) * (m_endVisibleColumn - m_startVisibleColumn) * 2;
+ index += (intersectionColumn - m_startVisibleColumn) * 2;
+ return direction == East ? index : index + 1; // each vertex holds [East, South]
+}
+
+unsigned TableCollapsedBorderPainter::intersectionToIndex(unsigned row, unsigned column) const
+{
+ if (row < m_startVisibleRow || column < m_startVisibleColumn
+ || row >= m_endVisibleRow || column >= m_endVisibleColumn )
+ return TableCollapsedBorderPainter::npos;
+ return (row - m_startVisibleRow) * (m_endVisibleColumn - m_startVisibleColumn) + column;
+}
+
+} // blink

Powered by Google App Engine
This is Rietveld 408576698