| OLD | NEW |
| (Empty) | |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "core/paint/TableCollapsedBorderPainter.h" |
| 6 |
| 7 #include "core/layout/LayoutTableCell.h" |
| 8 #include "core/layout/LayoutTableCol.h" |
| 9 #include "core/paint/BlockPainter.h" |
| 10 #include "core/paint/BoxPainter.h" |
| 11 #include "core/paint/LayoutObjectDrawingRecorder.h" |
| 12 #include "core/paint/PaintInfo.h" |
| 13 #include "platform/graphics/GraphicsContextStateSaver.h" |
| 14 #include <algorithm> |
| 15 |
| 16 namespace blink { |
| 17 |
| 18 // Comparator: returns |
| 19 // -1 => e1 < e2 |
| 20 // 0 => e1 == e2 |
| 21 // 1 => e1 > e2 |
| 22 static int compareEdges(const TableCollapsedBorderPainter::EdgeRecord& e1, const
TableCollapsedBorderPainter::EdgeRecord& e2) |
| 23 { |
| 24 |
| 25 // if (!e1.m_border) { |
| 26 // if (!e2.m_border) |
| 27 // return 0; |
| 28 // else |
| 29 // return -1; |
| 30 // } |
| 31 // if (!e2.m_border) |
| 32 // return 1; |
| 33 |
| 34 EBorderStyle e1Style = e1.m_border.style(); |
| 35 EBorderStyle e2Style = e2.m_border.style(); |
| 36 |
| 37 // RULES: https://www.w3.org/TR/CSS2/tables.html#border-conflict-resolution |
| 38 // 1) Hidden edges win |
| 39 // 2) None edges lose |
| 40 // 3) Wider border-width win |
| 41 // 4) Louder border-style win |
| 42 // 5) Higher precedence wins |
| 43 |
| 44 // Rule #1 |
| 45 if (e1Style == BorderStyleHidden) { |
| 46 if (e2Style == BorderStyleHidden) |
| 47 return 0; |
| 48 // else |
| 49 return 1; |
| 50 } |
| 51 if (e2Style == BorderStyleHidden) |
| 52 return -1; |
| 53 |
| 54 // Rule #2 |
| 55 if (e1Style == BorderStyleNone) { |
| 56 if (e2Style == BorderStyleNone) |
| 57 return 0; |
| 58 // else |
| 59 return -1; |
| 60 } |
| 61 if (e2Style == BorderStyleNone) |
| 62 return 1; |
| 63 |
| 64 // Rule #3 |
| 65 if (e1.m_border.width() < e2.m_border.width()) |
| 66 return -1; |
| 67 // else |
| 68 if (e2.m_border.width() < e1.m_border.width()) |
| 69 return 1; |
| 70 |
| 71 // Rule #4 |
| 72 if (e1Style > e2Style) |
| 73 return 1; |
| 74 // else |
| 75 if (e2Style > e1Style) |
| 76 return -1; |
| 77 |
| 78 // Rule #5 |
| 79 if (e1.m_precedence != e2.m_precedence) |
| 80 return e1.m_precedence < e2.m_precedence ? -1 : 1; |
| 81 |
| 82 return 0; |
| 83 } |
| 84 |
| 85 // Like compareEdges, except that HIDDEN edges lose |
| 86 static int compareIntersectionEdges(const TableCollapsedBorderPainter::EdgeRecor
d& e1, const TableCollapsedBorderPainter::EdgeRecord& e2) |
| 87 { |
| 88 EBorderStyle e1Style = e1.m_border.style(); |
| 89 EBorderStyle e2Style = e2.m_border.style(); |
| 90 // Rule #1 |
| 91 if (e1Style == BorderStyleHidden) { |
| 92 if (e2Style == BorderStyleHidden) |
| 93 return 0; |
| 94 // else |
| 95 return -1; |
| 96 } |
| 97 if (e2Style == BorderStyleHidden) |
| 98 return 1; |
| 99 return compareEdges(e1, e2); |
| 100 } |
| 101 |
| 102 #ifndef NDEBUG |
| 103 |
| 104 static std::string directionToStr(TableCollapsedBorderPainter::EdgeDirection dir
) |
| 105 { |
| 106 switch (dir) { |
| 107 case TableCollapsedBorderPainter::North: return "North"; |
| 108 case TableCollapsedBorderPainter::West: return "West"; |
| 109 case TableCollapsedBorderPainter::East: return "East"; |
| 110 case TableCollapsedBorderPainter::South: return "South"; |
| 111 case TableCollapsedBorderPainter::None: return "None"; |
| 112 } |
| 113 } |
| 114 |
| 115 static std::string precedenceToStr(EBorderPrecedence p) |
| 116 { |
| 117 switch (p) { |
| 118 case BorderPrecedenceOff: return "OFF"; |
| 119 case BorderPrecedenceTable: return "TABLE"; |
| 120 case BorderPrecedenceColumnGroup: return "COLGROUP"; |
| 121 case BorderPrecedenceColumn: return "COL"; |
| 122 case BorderPrecedenceRowGroup: return "ROWGROUP"; |
| 123 case BorderPrecedenceRow: return "ROW"; |
| 124 case BorderPrecedenceCell: return "CELL"; |
| 125 } |
| 126 } |
| 127 |
| 128 void TableCollapsedBorderPainter::showEdge(unsigned row, unsigned col, EdgeDirec
tion direction, EBorderPrecedence precedence, const BorderValue& border, Color r
esolvedColor) const |
| 129 { |
| 130 Color c = border.color().resolve(resolvedColor); |
| 131 LOG(INFO) << "[" << row << " " << col << " " << directionToStr(direction) |
| 132 << "] " << precedenceToStr(precedence) << " " |
| 133 << border.width() << " " << c.serializedAsCSSComponentValue().ascii().da
ta(); |
| 134 } |
| 135 |
| 136 void TableCollapsedBorderPainter::showEdges(bool showHidden) const |
| 137 { |
| 138 LOG(INFO) << "edges"; |
| 139 for (auto r = m_startVisibleRow; r <= m_endVisibleRow; r++) { |
| 140 LOG(INFO) << "row:" << r; |
| 141 for (auto c = m_startVisibleColumn; c < m_endVisibleColumn; c++) { |
| 142 auto edgeIdx = edgeToIndex(r, c, East); |
| 143 if (edgeIdx != npos) { |
| 144 EdgeRecord edge = m_edges[edgeIdx]; |
| 145 if (showHidden || edge.m_precedence != BorderPrecedenceOff) |
| 146 showEdge(r, c, East, edge.m_precedence, edge.m_border, edge.
m_resolvedColor); |
| 147 } |
| 148 edgeIdx = edgeToIndex(r, c, South); |
| 149 if (edgeIdx != npos) { |
| 150 EdgeRecord edge = m_edges[edgeIdx]; |
| 151 if (showHidden || edge.m_precedence != BorderPrecedenceOff) |
| 152 showEdge(r, c, South, edge.m_precedence, edge.m_border, edge
.m_resolvedColor); |
| 153 } |
| 154 } |
| 155 } |
| 156 } |
| 157 void TableCollapsedBorderPainter::showVisibleEdges(const VisibleEdgeContainer& e
dges) const |
| 158 { |
| 159 LOG(INFO) << "visedges"; |
| 160 for (auto edge = edges.begin() ; edge < edges.end(); edge++) { |
| 161 showEdge((*edge).m_row, (*edge).m_column, (*edge).m_direction, (*edge).m
_precedence, (*edge).m_border, (*edge).m_resolvedColor); |
| 162 } |
| 163 } |
| 164 |
| 165 void TableCollapsedBorderPainter::showIntersection(unsigned row, unsigned col) c
onst |
| 166 { |
| 167 auto i = intersectionToIndex(row, col); |
| 168 if (i != npos) { |
| 169 const Intersection in = m_intersections[i]; |
| 170 if (in.m_direction != None) { |
| 171 LOG(INFO) << "[" << row << ", " << col << "] " |
| 172 << in.m_width.toInt() << " " << in.m_height.toInt() << " Win:" <
< directionToStr(in.m_direction); |
| 173 } |
| 174 } |
| 175 } |
| 176 |
| 177 void TableCollapsedBorderPainter::showIntersections() const |
| 178 { |
| 179 LOG(INFO) << "intersections"; |
| 180 for (auto r = m_startVisibleRow; r <= m_endVisibleRow; r++) { |
| 181 for (auto c = m_startVisibleColumn; c < m_endVisibleColumn; c++) { |
| 182 showIntersection(r, c); |
| 183 } |
| 184 } |
| 185 } |
| 186 |
| 187 #endif |
| 188 |
| 189 |
| 190 void TableCollapsedBorderPainter::paintBorders(const PaintInfo& paintInfo, const
LayoutPoint& paintOffset, const CellSpan& dirtyRows, const CellSpan& dirtyColum
ns, const TableCollapsedBorderPainter& previousPainter) |
| 191 { |
| 192 initEdges(dirtyRows, dirtyColumns, previousPainter); |
| 193 // draw all the edges |
| 194 // initial algorithm: just draw everything |
| 195 // later algorithms: draw continuous lines if possible |
| 196 initIntersections(); |
| 197 |
| 198 paintEdges(paintInfo, paintOffset, dirtyRows, dirtyColumns); |
| 199 } |
| 200 |
| 201 void TableCollapsedBorderPainter::initEdges(const CellSpan& dirtyRows, const Cel
lSpan& dirtyColumns, const TableCollapsedBorderPainter& previousPainter) |
| 202 { |
| 203 // Initialize sizes |
| 204 // number of rows/cols in the section |
| 205 m_numRows = m_layoutTableSection->numRows(); |
| 206 m_numEffectiveColumns = m_layoutTableSection->table()->numEffectiveColumns()
; |
| 207 |
| 208 // Coordinates of intersections whose edges we'd like to measure. |
| 209 // Measurement area is dirtyRows x dirtyCols + single-cell wide border zone
above/left |
| 210 // of dirty area. |
| 211 // |
| 212 // Border zone is needed to measure intersections inside dirty area correctl
y. |
| 213 // |
| 214 // Number of intersections inside n-rows is n+1, inside m-cols is m+1 |
| 215 // start and end. End points to one beyond, equivalent to iterator's .end() |
| 216 m_startVisibleRow = dirtyRows.start() == 0 ? 0 : dirtyRows.start() - 1; |
| 217 m_startVisibleColumn = dirtyColumns.start() == 0 ? 0 : dirtyColumns.start()
- 1; |
| 218 m_endVisibleRow = dirtyRows.end() + 1; |
| 219 m_endVisibleColumn = dirtyColumns.end() + 1; |
| 220 |
| 221 unsigned edgeRowCount = m_endVisibleRow - m_startVisibleRow; |
| 222 unsigned edgeColumnCount = m_endVisibleColumn - m_startVisibleColumn; |
| 223 m_edges.resize(2 * edgeRowCount * edgeColumnCount); |
| 224 populateEdges(dirtyRows, dirtyColumns, previousPainter); |
| 225 #ifndef NDEBUG |
| 226 // showEdges(); |
| 227 #endif |
| 228 } |
| 229 |
| 230 void TableCollapsedBorderPainter::initIntersections() |
| 231 { |
| 232 m_maxIntersectionWidth = 0; |
| 233 m_maxIntersectionHeight = 0; |
| 234 m_intersections.resize((m_endVisibleRow - m_startVisibleRow) * (m_endVisible
Column - m_startVisibleColumn)); |
| 235 for (unsigned r = m_startVisibleRow; r < m_endVisibleRow; r++) { |
| 236 for (unsigned c = m_startVisibleColumn; c < m_endVisibleColumn; c++) { |
| 237 initIntersection(r, c); |
| 238 } |
| 239 } |
| 240 #ifndef NDEBUG |
| 241 // showIntersections(); |
| 242 #endif |
| 243 } |
| 244 |
| 245 void TableCollapsedBorderPainter::initIntersection(unsigned row, unsigned col) |
| 246 { |
| 247 EdgeRecord edges[None]; |
| 248 |
| 249 for (int d = North; d < None; d++) { |
| 250 unsigned index = edgeToIndex(row, col, (EdgeDirection)d); |
| 251 if (index != npos) |
| 252 edges[d] = m_edges[index]; |
| 253 } |
| 254 |
| 255 EdgeDirection winner = North; |
| 256 for (int d = West; d < None; d++) { |
| 257 if (compareIntersectionEdges(edges[winner], edges[d]) == -1) |
| 258 winner = (EdgeDirection)d; |
| 259 } |
| 260 |
| 261 unsigned index = intersectionToIndex(row, col); |
| 262 // only set if our winner is really an edge |
| 263 if (edges[winner].m_precedence != BorderPrecedenceOff) { |
| 264 unsigned width = 0; |
| 265 unsigned height = 0; |
| 266 if (winner == North || winner == South) { |
| 267 width = edges[winner].m_border.width(); |
| 268 if (compareIntersectionEdges(edges[East], edges[West]) < 1) // West
won |
| 269 height = edges[West].m_border.width(); |
| 270 else |
| 271 height = edges[East].m_border.width(); |
| 272 } else { // winner == East || West |
| 273 height = edges[winner].m_border.width(); |
| 274 if (compareIntersectionEdges(edges[North], edges[South]) < 1) // Sou
th won |
| 275 width = edges[South].m_border.width(); |
| 276 else |
| 277 width = edges[North].m_border.width(); |
| 278 } |
| 279 m_maxIntersectionHeight = std::max(m_maxIntersectionHeight, height); |
| 280 m_maxIntersectionWidth = std::max(m_maxIntersectionWidth, width); |
| 281 m_intersections[index] = Intersection(LayoutUnit(width), LayoutUnit(heig
ht), winner); |
| 282 // LOG(INFO) << "In: " << row << " " << col << ": " << width << "px " <<
height << "px " << directionToStr(winner); |
| 283 } |
| 284 } |
| 285 |
| 286 void TableCollapsedBorderPainter::populateEdges(const CellSpan& dirtyRows, const
CellSpan& dirtyColumns, const TableCollapsedBorderPainter& previousPainter) |
| 287 { |
| 288 VisibleEdgeContainer edges; |
| 289 |
| 290 // Iterate everything in reverse priority order |
| 291 |
| 292 // populate adjacent edges from adjacent section |
| 293 getVisibleEdgesSiblingSection(edges, previousPainter); |
| 294 mergeVisibleEdges(edges); |
| 295 |
| 296 LayoutTable * table = m_layoutTableSection->table(); |
| 297 // populate <table> |
| 298 getVisibleEdgesTable(edges, m_layoutTableSection->table()); |
| 299 mergeVisibleEdges(edges); |
| 300 |
| 301 // populate <colgroup> |
| 302 Vector<const LayoutTableCol*>colgroups; |
| 303 for (LayoutTableCol* colgroup = table->firstColumn(); colgroup; colgroup = c
olgroup->nextColumn()) |
| 304 colgroups.append(colgroup); |
| 305 |
| 306 for (auto colGroup = colgroups.rbegin(); colGroup != colgroups.rend(); colGr
oup++) { |
| 307 if ((*colGroup)->isTableColumnGroup()) { |
| 308 getVisibleEdgesColgroup(edges, *colGroup); |
| 309 mergeVisibleEdges(edges); |
| 310 } |
| 311 } |
| 312 // populate <col> |
| 313 for (auto col = colgroups.rbegin(); col != colgroups.rend(); col++) { |
| 314 if ((*col)->isTableColumn()) { |
| 315 getVisibleEdgesCol(edges, *col); |
| 316 mergeVisibleEdges(edges); |
| 317 } |
| 318 } |
| 319 |
| 320 // populate <tbody> |
| 321 getVisibleEdgesSection(edges); |
| 322 mergeVisibleEdges(edges); |
| 323 // populate <tr> |
| 324 for (int r = dirtyRows.end() - 1; r >= (int) dirtyRows.start(); r--) { |
| 325 const LayoutTableRow * row = m_layoutTableSection->rowLayoutObjectAt(r); |
| 326 if (row) { |
| 327 getVisibleEdgesRow(edges, row); |
| 328 mergeVisibleEdges(edges); |
| 329 } |
| 330 } |
| 331 // populate <td>, iterate in reverse |
| 332 TextDirection direction = m_layoutTableSection->style()->direction(); |
| 333 for (int r = dirtyRows.end() - 1; r >= (int) dirtyRows.start(); r--) { |
| 334 for (int c = dirtyColumns.end() - 1; c >= (int)dirtyColumns.start(); c--
) { |
| 335 // HashSet for primary cell to eliminate duplicates |
| 336 const LayoutTableCell * cell = m_layoutTableSection->primaryCellAt(r
, c); |
| 337 if (cell) { |
| 338 getVisibleEdgesCell(edges, cell, direction); |
| 339 mergeVisibleEdges(edges); |
| 340 } |
| 341 } |
| 342 } |
| 343 #ifndef NDEBUG |
| 344 // showEdges(); |
| 345 #endif |
| 346 } |
| 347 |
| 348 // Gets edges of the neighboring section |
| 349 void TableCollapsedBorderPainter::getVisibleEdgesSiblingSection(VisibleEdgeConta
iner& edges, const TableCollapsedBorderPainter& previousPainter) |
| 350 { |
| 351 edges.clear(); |
| 352 |
| 353 bool isAbove = previousPainter.m_layoutTableSection == m_layoutTableSection-
>table()->sectionAbove(m_layoutTableSection); |
| 354 |
| 355 bool isBelow = previousPainter.m_layoutTableSection == m_layoutTableSection-
>table()->sectionBelow(m_layoutTableSection); |
| 356 |
| 357 if (!isAbove && !isBelow) { |
| 358 // Happens if we are the first section |
| 359 // LOG(INFO) << "not sure where sibling section is"; |
| 360 return; |
| 361 } |
| 362 |
| 363 unsigned siblingRow = isAbove ? previousPainter.m_numRows : 0; |
| 364 unsigned myRow = isAbove ? 0 : m_numRows; |
| 365 for (unsigned c = previousPainter.m_startVisibleColumn; c <= previousPainter
.m_endVisibleColumn; c++) { |
| 366 auto siblingIndex = previousPainter.edgeToIndex(siblingRow, c, East); |
| 367 auto myIndex = edgeToIndex(myRow, c, East); |
| 368 if (siblingIndex != npos && myIndex != npos) { |
| 369 EdgeRecord siblingEdge = previousPainter.m_edges[siblingIndex]; |
| 370 edges.append(VisibleEdgeRecord(myRow, c, East, siblingEdge.m_border,
siblingEdge.m_precedence, siblingEdge.m_resolvedColor)); |
| 371 } |
| 372 } |
| 373 } |
| 374 |
| 375 void TableCollapsedBorderPainter::getVisibleEdgesTable(VisibleEdgeContainer& edg
es, const LayoutTable * table) |
| 376 { |
| 377 edges.clear(); |
| 378 Color resolvedColor = table->resolveColor(CSSPropertyColor); |
| 379 const ComputedStyle* borderStyle = table->style(); |
| 380 const BorderValue* topBorder = &borderStyle->borderTop(); |
| 381 const BorderValue* rightBorder = &borderStyle->borderRight(); |
| 382 const BorderValue* bottomBorder = &borderStyle->borderBottom(); |
| 383 const BorderValue* leftBorder = &borderStyle->borderLeft(); |
| 384 |
| 385 rotateBorders(m_layoutTableSection->style()->direction(), table->style()->ge
tWritingMode(), &topBorder, &rightBorder, &bottomBorder, &leftBorder); |
| 386 |
| 387 // top row, only if we abut table top |
| 388 if (this->m_layoutTableSection == table->topNonEmptySection()) { |
| 389 fillHorizontalEdges(edges, 0, 0, m_numEffectiveColumns, *topBorder, Bord
erPrecedenceTable, resolvedColor); |
| 390 } |
| 391 // bottom row, only if we abut table bottom |
| 392 if (this->m_layoutTableSection == table->bottomNonEmptySection()) { |
| 393 fillHorizontalEdges(edges, m_numRows, 0, m_numEffectiveColumns, *bottomB
order, BorderPrecedenceTable, resolvedColor); |
| 394 } |
| 395 fillVerticalEdges(edges, 0, 0, m_numRows, *leftBorder, BorderPrecedenceTable
, resolvedColor); |
| 396 fillVerticalEdges(edges, m_numEffectiveColumns, 0, m_numRows, *rightBorder,
BorderPrecedenceTable, resolvedColor); |
| 397 } |
| 398 |
| 399 void TableCollapsedBorderPainter::getVisibleEdgesSection(VisibleEdgeContainer& e
dges) |
| 400 { |
| 401 edges.clear(); |
| 402 Color resolvedColor = m_layoutTableSection->resolveColor(CSSPropertyColor); |
| 403 // Traverse all the section edges, and assign them |
| 404 fillVisibleRect(edges, 0, 0, m_numRows, m_numEffectiveColumns, m_layoutTable
Section->style(), |
| 405 LTR, m_layoutTableSection->style()->getWritingMode(), resolvedColor, Bo
rderPrecedenceRowGroup); |
| 406 } |
| 407 |
| 408 void TableCollapsedBorderPainter::getVisibleEdgesColgroup(VisibleEdgeContainer&
edges, const LayoutTableCol * colgroup) |
| 409 { |
| 410 edges.clear(); |
| 411 Color resolvedColor = colgroup->resolveColor(CSSPropertyColor); |
| 412 Vector<unsigned> indexes = colgroup->getEffectiveColumnIndexes(); |
| 413 if (indexes.size() > 0) { |
| 414 unsigned startColIndex = indexes[0]; |
| 415 unsigned endColIndex = indexes.last() + 1; |
| 416 fillVisibleRect(edges, 0, startColIndex, m_numRows, endColIndex, colgrou
p->style(), |
| 417 colgroup->style()->direction(), colgroup->style()->getWritingMode(),
resolvedColor, BorderPrecedenceColumnGroup); |
| 418 } |
| 419 } |
| 420 |
| 421 void TableCollapsedBorderPainter::getVisibleEdgesCol(VisibleEdgeContainer& edges
, const LayoutTableCol * col) |
| 422 { |
| 423 edges.clear(); |
| 424 Color resolvedColor = col->resolveColor(CSSPropertyColor); |
| 425 LayoutTable* table = m_layoutTableSection->table(); |
| 426 if (!table) |
| 427 return; |
| 428 |
| 429 Vector<unsigned> indexes = col->getEffectiveColumnIndexes(); |
| 430 if (indexes.size() > 0) { |
| 431 // fill multiple virtual columns |
| 432 for (auto idx = indexes.rbegin(); idx!= indexes.rend(); ++idx) { |
| 433 fillVisibleRect(edges, 0, *idx, m_numRows, *idx + 1, col->style(), |
| 434 col->style()->direction(), col->style()->getWritingMode(), resol
vedColor, BorderPrecedenceColumn); |
| 435 } |
| 436 } |
| 437 // unsigned startAbsoluteColIndex = table->colElementToAbsoluteColumn(col); |
| 438 // unsigned endAbsoluteColIndex = startAbsoluteColIndex + col->span(); |
| 439 // unsigned startColIndex = table->absoluteColumnToEffectiveColumn(startAbso
luteColIndex); |
| 440 // unsigned endColIndex = table->absoluteColumnToEffectiveColumn(endAbsolute
ColIndex); |
| 441 |
| 442 // // We replicat column span times. Weird, but that is the standard: |
| 443 // // "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
." |
| 444 // for (auto tmpEnd = endColIndex; tmpEnd > startColIndex; tmpEnd--) { |
| 445 // fillVisibleRect(edges, 0, tmpEnd - 1, m_numRows, tmpEnd, col->style()
, |
| 446 // col->style()->direction(), col->style()->getWritingMode(), resolv
edColor, BorderPrecedenceColumn); |
| 447 // } |
| 448 } |
| 449 |
| 450 void TableCollapsedBorderPainter::getVisibleEdgesRow(VisibleEdgeContainer& edges
, const LayoutTableRow * row) |
| 451 { |
| 452 edges.clear(); |
| 453 Color resolvedColor = row->resolveColor(CSSPropertyColor); |
| 454 unsigned rowIndex = row->rowIndex(); |
| 455 // We get direction from section because row direction only applies to cells
, |
| 456 // not the entire row. |
| 457 fillVisibleRect(edges, rowIndex, 0, rowIndex + 1, m_numEffectiveColumns, row
->style(), |
| 458 m_layoutTableSection->style()->direction(), row->style()->getWritingMode
(), resolvedColor, BorderPrecedenceRow); |
| 459 } |
| 460 |
| 461 void TableCollapsedBorderPainter::getVisibleEdgesCell(VisibleEdgeContainer& edge
s, const LayoutTableCell * cell, TextDirection direction) |
| 462 { |
| 463 edges.clear(); |
| 464 Color resolvedColor = cell->resolveColor(CSSPropertyColor); |
| 465 |
| 466 if (!cell->parent()) { |
| 467 LOG(INFO) << "DETACHED CELL"; |
| 468 return; |
| 469 } |
| 470 |
| 471 const LayoutTable * table = m_layoutTableSection->table(); |
| 472 unsigned startRow = cell->parent() ? cell->rowIndex() : 65000; |
| 473 unsigned absoluteCol = cell->absoluteColumnIndex(); |
| 474 |
| 475 |
| 476 unsigned effStartCol = table->absoluteColumnToEffectiveColumn(absoluteCol); |
| 477 unsigned effEndCol = table->absoluteColumnToEffectiveColumn(absoluteCol + ce
ll->colSpan()); |
| 478 unsigned endRow = std::min(startRow + cell->rowSpan(), m_numRows); |
| 479 |
| 480 // LOG(INFO) << "m_columns: " << table->effectiveColumns().size() |
| 481 // << " startRow: " << startRow << " endRow: " << endRow |
| 482 // << " startCol: " << effStartCol << " endCol:" << effEndCol |
| 483 // << " abscol:" << absoluteCol; |
| 484 |
| 485 // Fill border |
| 486 // cell's direction is LTR because we do not rotate cell's borders |
| 487 fillVisibleRect(edges, startRow, effStartCol, endRow, effEndCol, cell->style
(), |
| 488 direction, cell->style()->getWritingMode(), resolvedColor, BorderPrecede
nceCell); |
| 489 |
| 490 // Hide row inner edges |
| 491 for (unsigned row = startRow + 1; row < endRow; row++) { |
| 492 if (row >= m_startVisibleRow && row < m_endVisibleRow) { |
| 493 for (unsigned effCol = effStartCol; effCol < effEndCol; effCol++) { |
| 494 if (effCol >= m_startVisibleColumn && effCol < m_endVisibleColum
n) { |
| 495 edges.append(VisibleEdgeRecord(row, effCol, East, m_hiddenBo
rder, BorderPrecedenceCell, resolvedColor, true)); |
| 496 } |
| 497 } |
| 498 } |
| 499 } |
| 500 // Hide col inner edges |
| 501 for (unsigned effCol = effStartCol + 1; effCol < effEndCol; effCol++) { |
| 502 if (effCol >= m_startVisibleColumn && effCol < m_endVisibleColumn) { |
| 503 for (unsigned row = startRow; row < endRow; row++) { |
| 504 if (row >= m_startVisibleRow && row < m_endVisibleRow) { |
| 505 edges.append(VisibleEdgeRecord(row, effCol, South, m_hiddenB
order, BorderPrecedenceCell, resolvedColor, true)); |
| 506 } |
| 507 } |
| 508 } |
| 509 } |
| 510 #ifdef NDEBUG |
| 511 // showVisibleEdges(edges); |
| 512 #endif |
| 513 } |
| 514 |
| 515 |
| 516 void TableCollapsedBorderPainter::rotateBorders(TextDirection textDirection, Wri
tingMode writingMode, |
| 517 const BorderValue** top, const BorderValue** right, const BorderValue** bott
om, const BorderValue** left) const |
| 518 { |
| 519 bool isLTR = blink::isLeftToRightDirection(textDirection); |
| 520 if (blink::isHorizontalWritingMode(writingMode)) { |
| 521 if (isLTR) |
| 522 {} // do nothing |
| 523 else { |
| 524 std::swap(*right, *left); |
| 525 } |
| 526 } else if (blink::isFlippedBlocksWritingMode(writingMode)) { |
| 527 if (isLTR) { |
| 528 auto tmp = *top; |
| 529 *top = *right; |
| 530 *right = *bottom; |
| 531 *bottom = *left; |
| 532 *left = tmp; |
| 533 } else { |
| 534 std::swap(*top, *right); |
| 535 std::swap(*bottom, *left); |
| 536 } |
| 537 } else { // isFlippedLinesWritingMode |
| 538 if (isLTR) { |
| 539 std::swap(*bottom, *right); |
| 540 std::swap(*left, *top); |
| 541 } else { |
| 542 auto tmp = *top; |
| 543 *top = *left; |
| 544 *left = *bottom; |
| 545 *bottom = *right; |
| 546 *right = tmp; |
| 547 } |
| 548 } |
| 549 } |
| 550 |
| 551 void TableCollapsedBorderPainter::fillVisibleRect(VisibleEdgeContainer& edges, |
| 552 unsigned startRow, unsigned startColumn, unsigned endRow, unsigned endColumn
, |
| 553 const ComputedStyle* borderStyle, TextDirection textDirection, WritingMode w
ritingMode, |
| 554 Color resolvedColor, EBorderPrecedence precedence) |
| 555 { |
| 556 const BorderValue* topBorder = &borderStyle->borderTop(); |
| 557 const BorderValue* bottomBorder = &borderStyle->borderBottom(); |
| 558 const BorderValue* rightBorder = &borderStyle->borderRight(); |
| 559 const BorderValue* leftBorder = &borderStyle->borderLeft(); |
| 560 |
| 561 rotateBorders(textDirection, writingMode, &topBorder, &rightBorder, &bottomB
order, &leftBorder); |
| 562 |
| 563 fillHorizontalEdges(edges, startRow, startColumn, endColumn, *topBorder, pre
cedence, resolvedColor); |
| 564 fillHorizontalEdges(edges, endRow, startColumn, endColumn, *bottomBorder, pr
ecedence, resolvedColor); |
| 565 fillVerticalEdges(edges, startColumn, startRow, endRow, *leftBorder, precede
nce, resolvedColor); |
| 566 fillVerticalEdges(edges, endColumn, startRow, endRow, *rightBorder, preceden
ce, resolvedColor); |
| 567 } |
| 568 |
| 569 void TableCollapsedBorderPainter::fillHorizontalEdges(VisibleEdgeContainer& edge
s, unsigned row, unsigned startColumn, unsigned endColumn, |
| 570 const BorderValue &border, EBorderPrecedence precedence, Color resolvedColor
) |
| 571 { |
| 572 if (border.style() == BorderStyleNone) |
| 573 return; |
| 574 |
| 575 if (row >= m_startVisibleRow && row < m_endVisibleRow) { |
| 576 for (unsigned c = startColumn; c < endColumn; c++) { |
| 577 // FIXME: modify for loop instead of comparing guard |
| 578 if (c >= m_startVisibleColumn && c < m_endVisibleColumn) |
| 579 edges.append(VisibleEdgeRecord(row, c, East, border, precedence,
resolvedColor)); |
| 580 } |
| 581 } |
| 582 } |
| 583 |
| 584 void TableCollapsedBorderPainter::fillVerticalEdges(VisibleEdgeContainer& edges,
unsigned column, unsigned startRow, unsigned endRow, const BorderValue &border,
EBorderPrecedence precedence, Color resolvedColor) |
| 585 { |
| 586 if (border.style() == BorderStyleNone) |
| 587 return; |
| 588 |
| 589 if (column >= m_startVisibleColumn && column < m_endVisibleColumn) { |
| 590 for (unsigned r = startRow; r < endRow; r++) { |
| 591 // FIXME: modify for loop instead of comparing guard |
| 592 if (r >= m_startVisibleRow && r < m_endVisibleRow) |
| 593 edges.append(VisibleEdgeRecord(r, column, South, border, precede
nce, resolvedColor)); |
| 594 } |
| 595 } |
| 596 } |
| 597 |
| 598 void TableCollapsedBorderPainter::mergeVisibleEdges(VisibleEdgeContainer& edges) |
| 599 { |
| 600 for (auto edge = edges.begin(); edge < edges.end(); edge++) { |
| 601 unsigned idx = edgeToIndex((*edge).m_row, (*edge).m_column, (*edge).m_di
rection); |
| 602 ASSERT(idx != npos); |
| 603 EdgeRecord edgeRecord((*edge).m_border, (*edge).m_precedence, (*edge).m_
resolvedColor); |
| 604 if ((*edge).m_forceRemoval) |
| 605 m_edges[idx] = edgeRecord; |
| 606 // if both edges are same priority, new edge wins |
| 607 if (compareEdges(m_edges[idx], edgeRecord ) != 1) |
| 608 m_edges[idx] = edgeRecord; |
| 609 } |
| 610 } |
| 611 |
| 612 static EBorderStyle collapsedBorderStyle(EBorderStyle style) |
| 613 { |
| 614 if (style == BorderStyleOutset) |
| 615 return BorderStyleGroove; |
| 616 if (style == BorderStyleInset) |
| 617 return BorderStyleRidge; |
| 618 return style; |
| 619 } |
| 620 |
| 621 void TableCollapsedBorderPainter::paintEdges(const PaintInfo& paintInfo, const L
ayoutPoint& paintOffset, const CellSpan& rows, const CellSpan& cols) |
| 622 { |
| 623 // see TableCellPainter::paintCollapsedBorders |
| 624 LayoutRect paintRect = m_layoutTableSection->getCellPhysicalPosition(rows.st
art(), cols.start()); |
| 625 paintRect.unite(m_layoutTableSection->getCellPhysicalPosition(rows.end() > 0
? rows.end() - 1 : 0, cols.end() > 0 ? cols.end() - 1 : 0)); |
| 626 |
| 627 // paintRect size calculation is not exact, we expand by maxborder, instead
of exact border |
| 628 paintRect.expand(LayoutSize(LayoutUnit(m_maxIntersectionWidth * 2), LayoutUn
it(m_maxIntersectionHeight * 2))); |
| 629 paintRect.moveBy(paintOffset); |
| 630 |
| 631 LayoutPoint location = m_layoutTableSection->location(); |
| 632 paintRect.moveBy(location); |
| 633 |
| 634 if (LayoutObjectDrawingRecorder::useCachedDrawingIfPossible( |
| 635 paintInfo.context, |
| 636 *m_layoutTableSection, |
| 637 DisplayItem::TableCollapsedBorderBase)) |
| 638 return; |
| 639 LayoutObjectDrawingRecorder recorder( |
| 640 paintInfo.context, |
| 641 *m_layoutTableSection, |
| 642 DisplayItem::TableCollapsedBorderBase, |
| 643 paintRect); |
| 644 |
| 645 // Paint edges carefully to get them all |
| 646 // Every row paint : ┌┌┌┌┌, then | |
| 647 // Bottom border paint: _____ |
| 648 WritingMode writingMode = m_layoutTableSection->style()->getWritingMode(); |
| 649 TextDirection textDirection = m_layoutTableSection->style()->direction(); |
| 650 for (unsigned r = rows.start(); r < rows.end(); r++) { |
| 651 // const LayoutTableRow * row = m_layoutTableSection->rowLayoutObjectAt(
r); |
| 652 // if (row) |
| 653 // textDirection = row->style()->direction(); |
| 654 for (unsigned c = cols.start(); c < cols.end(); c++) { |
| 655 paintOneEdge(paintInfo, paintOffset, r, c, East, writingMode, textDi
rection); |
| 656 paintOneEdge(paintInfo, paintOffset, r, c, South, writingMode, textD
irection); |
| 657 } |
| 658 // paint the last column on edge |
| 659 paintOneEdge(paintInfo, paintOffset, r, cols.end(), South, writingMode,
textDirection); |
| 660 } |
| 661 // Paint the last row |
| 662 for (unsigned c = cols.start(); c < cols.end(); c++) |
| 663 paintOneEdge(paintInfo, paintOffset, rows.end(), c, East, writingMode, t
extDirection); |
| 664 } |
| 665 |
| 666 // Returns a rect that encloses 'direction' border of the cellRect |
| 667 LayoutRect TableCollapsedBorderPainter::cellRectAsBorder(const LayoutRect& cellR
ect, BoxSide side, unsigned borderWidth, WritingMode writingMode, TextDirection
textDirection) |
| 668 { |
| 669 |
| 670 unsigned smallHalf = borderWidth / 2; // C++ always rounds down |
| 671 unsigned bigHalf = borderWidth - smallHalf; |
| 672 |
| 673 unsigned topOffset; |
| 674 unsigned leftOffset; |
| 675 |
| 676 /* Tricky: if the border width is odd, we need a consistent way of |
| 677 distributing the extra pixel. The rule is: |
| 678 - south and east edges always get the extra pixel on the inside |
| 679 of the cell |
| 680 */ |
| 681 |
| 682 bool isLTR = blink::isLeftToRightDirection(textDirection); |
| 683 if (blink::isHorizontalWritingMode(writingMode)) { |
| 684 if (isLTR) { |
| 685 topOffset = smallHalf; |
| 686 leftOffset = smallHalf; |
| 687 } else { |
| 688 topOffset = smallHalf; |
| 689 leftOffset = bigHalf; |
| 690 } |
| 691 } else { // vertical |
| 692 if (blink::isFlippedBlocksWritingMode(writingMode)) { |
| 693 if (isLTR) { |
| 694 topOffset = smallHalf; |
| 695 leftOffset = bigHalf; |
| 696 } else { |
| 697 topOffset = bigHalf; |
| 698 leftOffset = bigHalf; |
| 699 } |
| 700 } else { // flippedLines |
| 701 if (isLTR) { |
| 702 topOffset = smallHalf; |
| 703 leftOffset = smallHalf; |
| 704 } else { |
| 705 topOffset = bigHalf; |
| 706 leftOffset = smallHalf; |
| 707 } |
| 708 } |
| 709 } |
| 710 switch (side) { |
| 711 case BSTop: |
| 712 return LayoutRect( |
| 713 LayoutPoint(cellRect.x(), cellRect.y() - topOffset), |
| 714 LayoutSize(cellRect.width(), LayoutUnit(borderWidth))); |
| 715 case BSBottom: |
| 716 return LayoutRect( |
| 717 LayoutPoint(cellRect.x(), cellRect.maxY() - topOffset), |
| 718 LayoutSize(cellRect.width(), LayoutUnit(borderWidth))); |
| 719 case BSLeft: |
| 720 return LayoutRect( |
| 721 LayoutPoint(cellRect.x() - leftOffset, cellRect.y()), |
| 722 LayoutSize(LayoutUnit(borderWidth), cellRect.height())); |
| 723 case BSRight: |
| 724 return LayoutRect( |
| 725 LayoutPoint(cellRect.maxX() - leftOffset, cellRect.y()), |
| 726 LayoutSize(LayoutUnit(borderWidth), cellRect.height())); |
| 727 } |
| 728 |
| 729 } |
| 730 // |
| 731 LayoutRect TableCollapsedBorderPainter::edgePaintPosition(unsigned row, unsigned
col, unsigned borderWidth, EdgeDirection direction, WritingMode writingMode, Te
xtDirection textDirection) |
| 732 { |
| 733 // Compute edge's size from size of the cell |
| 734 LayoutRect position; |
| 735 |
| 736 bool isLTR = blink::isLeftToRightDirection(textDirection); |
| 737 BoxSide side = BSLeft; |
| 738 LayoutRect cellRect; |
| 739 // If this is the last row intersection, get size from cell in next to last |
| 740 if (row == m_numRows) { |
| 741 ASSERT(direction == East); |
| 742 cellRect = getCellPhysicalPosition(row - 1, col); |
| 743 if (blink::isHorizontalWritingMode(writingMode)) { |
| 744 side = BSBottom; |
| 745 } else if (blink::isFlippedBlocksWritingMode(writingMode)) { |
| 746 side = BSLeft; |
| 747 } else { |
| 748 side = BSRight; |
| 749 } |
| 750 } else if (col == m_numEffectiveColumns) { |
| 751 // If this is the last column, get size from the cell before |
| 752 ASSERT(direction == South); |
| 753 cellRect = getCellPhysicalPosition(row, col - 1); |
| 754 if (blink::isHorizontalWritingMode(writingMode)) { |
| 755 side = isLTR ? BSRight : BSLeft; |
| 756 } else if (blink::isFlippedBlocksWritingMode(writingMode)) { |
| 757 side = isLTR ? BSBottom : BSTop; |
| 758 } else { |
| 759 side = isLTR ? BSBottom : BSTop; |
| 760 } |
| 761 } else { |
| 762 cellRect = getCellPhysicalPosition(row, col); |
| 763 if (direction == East) { |
| 764 if (blink::isHorizontalWritingMode(writingMode)) { |
| 765 side = BSTop; |
| 766 } else if (blink::isFlippedBlocksWritingMode(writingMode)) { |
| 767 side = BSRight; |
| 768 } else { |
| 769 side = BSLeft; |
| 770 } |
| 771 } else { // direction == South |
| 772 if (blink::isHorizontalWritingMode(writingMode)) { |
| 773 side = isLTR ? BSLeft : BSRight; |
| 774 } else if (blink::isFlippedBlocksWritingMode(writingMode)) { |
| 775 side = isLTR ? BSTop : BSBottom; |
| 776 } else { // flippedLines |
| 777 side = isLTR ? BSTop : BSBottom; |
| 778 } |
| 779 } |
| 780 } |
| 781 return cellRectAsBorder(cellRect, side, borderWidth, writingMode, textDirect
ion); |
| 782 } |
| 783 |
| 784 // Paints an edge starting from intersection[row, col] in direction |
| 785 void TableCollapsedBorderPainter::paintOneEdge( |
| 786 const PaintInfo& paintInfo, const LayoutPoint& paintOffset, |
| 787 unsigned row, unsigned col, EdgeDirection direction, |
| 788 WritingMode writingMode, TextDirection textDirection) |
| 789 { |
| 790 ASSERT(direction == South || direction == East); |
| 791 |
| 792 unsigned idx = edgeToIndex(row, col, direction); |
| 793 ASSERT(idx != npos); |
| 794 const BorderValue& border = m_edges[idx].m_border; |
| 795 |
| 796 if (border.style() == BorderStyleHidden || !border.nonZero()) |
| 797 return; |
| 798 |
| 799 #ifndef NDEBUG |
| 800 // LOG(INFO) << "painting"; |
| 801 // EdgeRecord edge = m_edges[idx]; |
| 802 // showEdge(row, col, direction, edge.m_precedence, edge.m_border, border->c
olor().resolve(m_edges[idx].m_resolvedColor)); |
| 803 #endif |
| 804 LayoutRect position = edgePaintPosition(row, col, border.width(), direction,
writingMode, textDirection); |
| 805 |
| 806 // LOG(INFO) << "paint " << position.x().toInt() << ", " << position.y().toI
nt() << "; " |
| 807 // << position.width().toInt() << ", " << position.height().toInt(); |
| 808 |
| 809 adjustForIntersections(position, row, col, direction, writingMode, textDirec
tion); |
| 810 |
| 811 // LOG(INFO) << "intersection " << position.x().toInt() << ", " << position.
y().toInt() << "; " |
| 812 // << position.width().toInt() << ", " << position.height().toInt(); |
| 813 |
| 814 // Offset by sectionLocation |
| 815 LayoutPoint sectionLocation = m_layoutTableSection->location(); |
| 816 position.moveBy(sectionLocation); |
| 817 position.moveBy(paintOffset); |
| 818 |
| 819 BoxSide side; |
| 820 if (blink::isHorizontalWritingMode(writingMode)) |
| 821 side = direction == East ? BSTop : BSLeft; |
| 822 else |
| 823 side = direction == East ? BSLeft : BSTop; |
| 824 |
| 825 ObjectPainter::drawLineForBoxSide( |
| 826 paintInfo.context, |
| 827 position.x(), position.y(), position.maxX(), position.maxY(), // left, t
op, right, bottom, |
| 828 side, |
| 829 border.color().resolve(m_edges[idx].m_resolvedColor), |
| 830 collapsedBorderStyle(border.style()), |
| 831 0, 0, true); |
| 832 } |
| 833 |
| 834 void TableCollapsedBorderPainter::adjustForIntersections(LayoutRect& position, u
nsigned row, unsigned col, EdgeDirection direction, WritingMode writingMode, Tex
tDirection textDirection) |
| 835 { |
| 836 |
| 837 ASSERT(direction == South || direction == East); |
| 838 |
| 839 const Intersection * startIntersection = nullptr; |
| 840 const Intersection * endIntersection = nullptr; |
| 841 bool winnerStart = false; |
| 842 bool winnerEnd = false; |
| 843 // START intersection |
| 844 unsigned index = intersectionToIndex(row, col); |
| 845 if (index != npos) { |
| 846 startIntersection = &m_intersections[index]; |
| 847 winnerStart = startIntersection->m_direction == direction; |
| 848 } |
| 849 // END intersection |
| 850 if (direction == South) |
| 851 row += 1; |
| 852 else |
| 853 col += 1; |
| 854 index = intersectionToIndex(row, col); |
| 855 if (index != npos) { |
| 856 endIntersection = &m_intersections[index]; |
| 857 if (direction == South) |
| 858 winnerEnd = endIntersection->m_direction == North; |
| 859 else |
| 860 winnerEnd = endIntersection->m_direction == West; |
| 861 } |
| 862 |
| 863 bool isLTR = blink::isLeftToRightDirection(textDirection); |
| 864 |
| 865 if (blink::isHorizontalWritingMode(writingMode)) |
| 866 adjustForIntersectionsHorizontal(position, direction, isLTR, startInters
ection, winnerStart, endIntersection, winnerEnd); |
| 867 else if (blink::isFlippedBlocksWritingMode(writingMode)) |
| 868 adjustForIntersectionsFlippedBlocks(position, direction, isLTR, startInt
ersection, winnerStart, endIntersection, winnerEnd); |
| 869 else if (blink::isFlippedLinesWritingMode(writingMode)) |
| 870 adjustForIntersectionsFlippedLines(position, direction, isLTR, startInte
rsection, winnerStart, endIntersection, winnerEnd); |
| 871 else |
| 872 ASSERT(false); |
| 873 } |
| 874 |
| 875 /* |
| 876 writing-mode: HORIZONTAL-TB |
| 877 N |
| 878 compass: W--+--E intersection: <--width --> |
| 879 S |
| 880 start intersection |
| 881 South edge, win : expand top by height/2 |
| 882 South edge, lose: shrink top by height/2 |
| 883 East edge, win : expand left by width/2 |
| 884 East edge, lose : shrink left by width/2 |
| 885 end intersection |
| 886 South edge, win : expand bottom by height/2 |
| 887 South edge lose : shrink bottom by height/2 |
| 888 East edge, win : expand right by width/2 |
| 889 East edge, lose : shrink right by width/2 |
| 890 |
| 891 writing-mode: HORIZONTAL(RTL) |
| 892 N |
| 893 compass: E--+--W intersection: <-- width --> |
| 894 S |
| 895 same as HORIZONTAL-TB in South direction |
| 896 start intersection |
| 897 South: same as LTR |
| 898 East edge, win : expand right by width/2 |
| 899 East edge, lose : shrink right by width/2 |
| 900 end intersection |
| 901 South: same as LTR |
| 902 East edge, win : expand left by width/2 |
| 903 East edge, lose : shrink left by width/2 |
| 904 */ |
| 905 void TableCollapsedBorderPainter::adjustForIntersectionsHorizontal(LayoutRect& p
osition, EdgeDirection direction, bool isLTR, |
| 906 const Intersection* startIntersection, bool winnerStart, |
| 907 const Intersection* endIntersection, bool winnerEnd) |
| 908 { |
| 909 if (startIntersection) { |
| 910 |
| 911 if (direction == South) { |
| 912 unsigned smallDelta = startIntersection->m_height.toUnsigned() / 2; |
| 913 unsigned bigDelta = startIntersection->m_height.toUnsigned() - small
Delta; |
| 914 if (winnerStart) |
| 915 position.expandEdges(LayoutUnit(smallDelta), LayoutUnit(0), Layo
utUnit(0), LayoutUnit(0)); |
| 916 else |
| 917 position.contractEdges(LayoutUnit(bigDelta), LayoutUnit(0), Layo
utUnit(0), LayoutUnit(0)); |
| 918 } else { // East |
| 919 unsigned smallDelta = startIntersection->m_width.toUnsigned() / 2; |
| 920 unsigned bigDelta = startIntersection->m_width.toUnsigned() - smallD
elta; |
| 921 if (isLTR) { |
| 922 if (winnerStart) { |
| 923 position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUni
t(0), LayoutUnit(smallDelta)); |
| 924 } else { |
| 925 position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutU
nit(0), LayoutUnit(bigDelta)); |
| 926 } |
| 927 } else { // RTL |
| 928 if (winnerStart) { |
| 929 position.expandEdges(LayoutUnit(0), LayoutUnit(smallDelta),
LayoutUnit(0), LayoutUnit(0)); |
| 930 } else { |
| 931 position.contractEdges(LayoutUnit(0), LayoutUnit(bigDelta),
LayoutUnit(0), LayoutUnit(0)); |
| 932 } |
| 933 } |
| 934 } |
| 935 } |
| 936 if (endIntersection) { |
| 937 if (direction == South) { |
| 938 unsigned smallDelta = endIntersection->m_height.toUnsigned() / 2; |
| 939 unsigned bigDelta = endIntersection->m_height.toUnsigned() - smallDe
lta; |
| 940 if (winnerEnd) |
| 941 position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(bi
gDelta), LayoutUnit(0)); |
| 942 else |
| 943 position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(
smallDelta), LayoutUnit(0)); |
| 944 } else { // East |
| 945 unsigned smallDelta = endIntersection->m_width.toUnsigned() / 2; |
| 946 unsigned bigDelta = endIntersection->m_width.toUnsigned() - smallDel
ta; |
| 947 if (isLTR) { |
| 948 if (winnerEnd) { |
| 949 position.expandEdges(LayoutUnit(0), LayoutUnit(bigDelta), La
youtUnit(0), LayoutUnit(0)); |
| 950 } else { // loser |
| 951 position.contractEdges(LayoutUnit(0), LayoutUnit(smallDelta)
, LayoutUnit(0), LayoutUnit(0)); |
| 952 } |
| 953 } else { // RTL |
| 954 if (winnerEnd) |
| 955 position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUni
t(0), LayoutUnit(bigDelta)); |
| 956 else |
| 957 position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutU
nit(0), LayoutUnit(smallDelta)); |
| 958 } |
| 959 } |
| 960 } |
| 961 } |
| 962 |
| 963 /* |
| 964 writing-mode: VERTICAL-RL (flipped blocks) |
| 965 W |
| 966 compass: vertical: S--+--N intersection: <--- height ----> |
| 967 E |
| 968 |
| 969 start intersection |
| 970 South edge, win : expand right by height/2 |
| 971 South edge, lose: shrink right by height/2 |
| 972 East edge, win : expand top by width/2 |
| 973 East edge, lose : shrink top by width/2 |
| 974 end intersection |
| 975 South edge, win : expand left by height/2 |
| 976 South edge, lose: shrink left by height/2 |
| 977 East edge, win : expand bottom by width/2 |
| 978 East edge, lose : shrink bottom by width/2 |
| 979 |
| 980 writing-mode: VERTICAL-RL RTL |
| 981 E |
| 982 compass: vertical: S--+--N intersection: <--- height ----> |
| 983 W |
| 984 start intersection |
| 985 South edge, win : expand right by height/2 |
| 986 South edge, lose: shrink right by height/2 |
| 987 East edge, win : expand bottom by width/2 |
| 988 East edge, lose : shrink bottom by width/2 |
| 989 end intersection |
| 990 South edge, win : expand left by height/2 |
| 991 South edge, lose: shrink left by height/2 |
| 992 East edge, win : expand top by width/2 |
| 993 East edge, lose : shrink top by width/2 |
| 994 |
| 995 */ |
| 996 void TableCollapsedBorderPainter::adjustForIntersectionsFlippedBlocks(LayoutRect
& position, EdgeDirection direction, bool isLTR, |
| 997 const Intersection* startIntersection, bool winnerStart, |
| 998 const Intersection* endIntersection, bool winnerEnd) |
| 999 { |
| 1000 if (startIntersection) { |
| 1001 |
| 1002 if (direction == South) { |
| 1003 unsigned smallDelta = startIntersection->m_height.toUnsigned() / 2; |
| 1004 unsigned bigDelta = startIntersection->m_height.toUnsigned() - small
Delta; |
| 1005 if (winnerStart) |
| 1006 position.expandEdges(LayoutUnit(0), LayoutUnit(smallDelta), Layo
utUnit(0), LayoutUnit(0)); |
| 1007 else |
| 1008 position.contractEdges(LayoutUnit(0), LayoutUnit(bigDelta), Layo
utUnit(0), LayoutUnit(0)); |
| 1009 } else { // East |
| 1010 unsigned smallDelta = startIntersection->m_width.toUnsigned() / 2; |
| 1011 unsigned bigDelta = startIntersection->m_width.toUnsigned() - smallD
elta; |
| 1012 if (isLTR) { |
| 1013 if (winnerStart) { |
| 1014 position.expandEdges(LayoutUnit(smallDelta), LayoutUnit(0),
LayoutUnit(0), LayoutUnit(0)); |
| 1015 } else { |
| 1016 position.contractEdges(LayoutUnit(bigDelta), LayoutUnit(0),
LayoutUnit(0), LayoutUnit(0)); |
| 1017 } |
| 1018 } else { // RTL |
| 1019 if (winnerStart) { |
| 1020 position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUni
t(bigDelta), LayoutUnit(0)); |
| 1021 } else { |
| 1022 position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutU
nit(smallDelta), LayoutUnit(0)); |
| 1023 } |
| 1024 } |
| 1025 } |
| 1026 } |
| 1027 if (endIntersection) { |
| 1028 if (direction == South) { |
| 1029 unsigned smallDelta = endIntersection->m_height.toUnsigned() / 2; |
| 1030 unsigned bigDelta = endIntersection->m_height.toUnsigned() - smallDe
lta; |
| 1031 if (winnerEnd) |
| 1032 position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0)
, LayoutUnit(bigDelta)); |
| 1033 else |
| 1034 position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(
0), LayoutUnit(smallDelta)); |
| 1035 } else { // East |
| 1036 unsigned smallDelta = endIntersection->m_width.toUnsigned() / 2; |
| 1037 unsigned bigDelta = endIntersection->m_width.toUnsigned() - smallDel
ta; |
| 1038 if (isLTR) { |
| 1039 if (winnerEnd) |
| 1040 position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUni
t(bigDelta), LayoutUnit(0)); |
| 1041 else // loser |
| 1042 position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutU
nit(smallDelta), LayoutUnit(0)); |
| 1043 } else { // RTL |
| 1044 if (winnerEnd) |
| 1045 position.expandEdges(LayoutUnit(bigDelta), LayoutUnit(0), La
youtUnit(0), LayoutUnit(0)); |
| 1046 else |
| 1047 position.contractEdges(LayoutUnit(smallDelta), LayoutUnit(0)
, LayoutUnit(0), LayoutUnit(0)); |
| 1048 } |
| 1049 } |
| 1050 } |
| 1051 } |
| 1052 |
| 1053 /* |
| 1054 writing-mode: VERTICAL-LR (flipped lines) |
| 1055 W |
| 1056 compass: rotated N--+--S |
| 1057 E |
| 1058 start intersection |
| 1059 East edge, win : expand top by width/2 |
| 1060 East edge, lose : shrink top by width/2 |
| 1061 South edge, win : expand left by height/2 |
| 1062 South edge, lose: shrink left by height/2 |
| 1063 end intersection |
| 1064 East edge, win : expand bottom by width/2 |
| 1065 East edge, lose : shrink bottom by width/2 |
| 1066 South edge, win : expand right by height/2 |
| 1067 South edge lose : shrink right by height/2 |
| 1068 |
| 1069 writing-mode: VERTICAL-LR, DIRECTION RTL |
| 1070 E |
| 1071 compass: N-+-S intersection <--height --> |
| 1072 W |
| 1073 start intersection |
| 1074 East edge. win : expand bottom by width / 2 |
| 1075 East edge, lose: shrink bottom by width / 2 |
| 1076 end intersection |
| 1077 East edge, win : expand top by width / 2 |
| 1078 East edge, lose: expand top by width / 2 |
| 1079 */ |
| 1080 |
| 1081 void TableCollapsedBorderPainter::adjustForIntersectionsFlippedLines(LayoutRect&
position, EdgeDirection direction, bool isLTR, |
| 1082 const Intersection* startIntersection, bool winnerStart, |
| 1083 const Intersection* endIntersection, bool winnerEnd) |
| 1084 { |
| 1085 if (startIntersection) { |
| 1086 |
| 1087 if (direction == South) { |
| 1088 unsigned smallDelta = startIntersection->m_height.toUnsigned() / 2; |
| 1089 unsigned bigDelta = startIntersection->m_height.toUnsigned() - small
Delta; |
| 1090 if (winnerStart) |
| 1091 position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0)
, LayoutUnit(smallDelta)); |
| 1092 else |
| 1093 position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(
0), LayoutUnit(bigDelta)); |
| 1094 } else { // East |
| 1095 unsigned smallDelta = startIntersection->m_width.toUnsigned() / 2; |
| 1096 unsigned bigDelta = startIntersection->m_width.toUnsigned() - smallD
elta; |
| 1097 if (isLTR) { |
| 1098 if (winnerStart) { |
| 1099 position.expandEdges(LayoutUnit(smallDelta), LayoutUnit(0),
LayoutUnit(0), LayoutUnit(0)); |
| 1100 } else { |
| 1101 position.contractEdges(LayoutUnit(bigDelta), LayoutUnit(0),
LayoutUnit(0), LayoutUnit(0)); |
| 1102 } |
| 1103 } else { // RTL |
| 1104 if (winnerStart) { |
| 1105 position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUni
t(smallDelta), LayoutUnit(0)); |
| 1106 } else { |
| 1107 position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutU
nit(bigDelta), LayoutUnit(0)); |
| 1108 } |
| 1109 } |
| 1110 } |
| 1111 } |
| 1112 if (endIntersection) { |
| 1113 if (direction == South) { |
| 1114 unsigned smallDelta = endIntersection->m_height.toUnsigned() / 2; |
| 1115 unsigned bigDelta = endIntersection->m_height.toUnsigned() - smallDe
lta; |
| 1116 if (winnerEnd) |
| 1117 position.expandEdges(LayoutUnit(0), LayoutUnit(bigDelta), Layout
Unit(0), LayoutUnit(0)); |
| 1118 else |
| 1119 position.contractEdges(LayoutUnit(0), LayoutUnit(smallDelta), La
youtUnit(0), LayoutUnit(0)); |
| 1120 } else { // East |
| 1121 unsigned smallDelta = endIntersection->m_width.toUnsigned() / 2; |
| 1122 unsigned bigDelta = endIntersection->m_width.toUnsigned() - smallDel
ta; |
| 1123 if (isLTR) { |
| 1124 if (winnerEnd) { |
| 1125 position.expandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUni
t(bigDelta), LayoutUnit(0)); |
| 1126 } else { // loser |
| 1127 position.contractEdges(LayoutUnit(0), LayoutUnit(0), LayoutU
nit(smallDelta), LayoutUnit(0)); |
| 1128 } |
| 1129 } else { // RTL |
| 1130 if (winnerEnd) { |
| 1131 position.expandEdges(LayoutUnit(bigDelta), LayoutUnit(0), La
youtUnit(0), LayoutUnit(0)); |
| 1132 } else { |
| 1133 position.contractEdges(LayoutUnit(smallDelta), LayoutUnit(0)
, LayoutUnit(0), LayoutUnit(0)); |
| 1134 } |
| 1135 } |
| 1136 } |
| 1137 } |
| 1138 } |
| 1139 |
| 1140 // returns edge index for position, TableCollapsedBorderPainter::npos if out of
range |
| 1141 // topLeft intersection is 0, 0, bottomRight is numRows+1, numColumns + 1 |
| 1142 unsigned TableCollapsedBorderPainter::edgeToIndex(unsigned intersectionRow, unsi
gned intersectionColumn, EdgeDirection direction) const |
| 1143 { |
| 1144 /* Edges map to m_edges like this: |
| 1145 - each intersection 'stores' only two edges: east and south edges |
| 1146 - to map edge to index: |
| 1147 - find intersection so that requested edge is east or south |
| 1148 - edge is row * cols * 2 + (east ? 0 : 1) |
| 1149 - for example: |
| 1150 - North edge at intersection 5, 3, is also South edge at intersection 4, 3 |
| 1151 - its index is 4 (rows) * 3 (cols) * 2 + 1 (for South) |
| 1152 */ |
| 1153 switch (direction) { |
| 1154 case North: |
| 1155 intersectionRow -= 1; |
| 1156 direction = South; |
| 1157 break; |
| 1158 case West: |
| 1159 intersectionColumn -= 1; |
| 1160 direction = East; |
| 1161 break; |
| 1162 case South: |
| 1163 case East: |
| 1164 case None: |
| 1165 break; |
| 1166 } |
| 1167 // Check if we are inside the covered area |
| 1168 if (intersectionRow < m_startVisibleRow || intersectionColumn < m_startVisib
leColumn |
| 1169 || intersectionRow >= m_endVisibleRow || intersectionColumn >= m_endVisi
bleColumn) { |
| 1170 // LOG(ERROR) << "GOT AN NPOS"; |
| 1171 return TableCollapsedBorderPainter::npos; |
| 1172 } |
| 1173 |
| 1174 unsigned index = (intersectionRow - m_startVisibleRow) * (m_endVisibleColumn
- m_startVisibleColumn) * 2; |
| 1175 index += (intersectionColumn - m_startVisibleColumn) * 2; |
| 1176 return direction == East ? index : index + 1; // each vertex holds [East, So
uth] |
| 1177 } |
| 1178 |
| 1179 unsigned TableCollapsedBorderPainter::intersectionToIndex(unsigned row, unsigned
column) const |
| 1180 { |
| 1181 if (row < m_startVisibleRow || column < m_startVisibleColumn |
| 1182 || row >= m_endVisibleRow || column >= m_endVisibleColumn ) |
| 1183 return TableCollapsedBorderPainter::npos; |
| 1184 return (row - m_startVisibleRow) * (m_endVisibleColumn - m_startVisibleColum
n) + column; |
| 1185 } |
| 1186 |
| 1187 } // blink |
| OLD | NEW |