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

Side by Side Diff: third_party/WebKit/Source/core/paint/TableCollapsedBorderPainter.cpp

Issue 2791433003: Fix Border collapsing with colpsan / rowspan cells
Patch Set: bug 2902 Created 3 years, 8 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 unified diff | Download patch
OLDNEW
(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 #include "core/paint/TableCollapsedBorderPainter.h"
5 #include <algorithm>
6 #include "core/layout/LayoutTableCell.h"
7 #include "core/layout/LayoutTableCol.h"
8 #include "core/paint/BlockPainter.h"
9 #include "core/paint/BoxPainter.h"
10 #include "core/paint/LayoutObjectDrawingRecorder.h"
11 #include "core/paint/ObjectPainter.h"
12 #include "core/paint/PaintInfo.h"
13 #include "platform/graphics/GraphicsContextStateSaver.h"
14
15 namespace blink {
16 // Comparator: returns
17 // -1 => e1 < e2
18 // 0 => e1 == e2
19 // 1 => e1 > e2
20 static int CompareEdges(const TableCollapsedBorderPainter::EdgeRecord& e1,
21 const TableCollapsedBorderPainter::EdgeRecord& e2) {
22 // if (!e1.border_) {
23 // if (!e2.border_)
24 // return 0;
25 // else
26 // return -1;
27 // }
28 // if (!e2.border_)
29 // return 1;
30 EBorderStyle e1_style = e1.border_.Style();
31 EBorderStyle e2_style = e2.border_.Style();
32 // RULES: https://www.w3.org/TR/CSS2/tables.html#border-conflict-resolution
33 // 1) Hidden edges win
34 // 2) None edges lose
35 // 3) Wider border-width win
36 // 4) Louder border-style win
37 // 5) Higher precedence wins
38 // Rule #1
39 if (e1_style == kBorderStyleHidden) {
40 if (e2_style == kBorderStyleHidden)
41 return 0;
42 // else
43 return 1;
44 }
45 if (e2_style == kBorderStyleHidden)
46 return -1;
47 // Rule #2
48 if (e1_style == kBorderStyleNone) {
49 if (e2_style == kBorderStyleNone)
50 return 0;
51 // else
52 return -1;
53 }
54 if (e2_style == kBorderStyleNone)
55 return 1;
56 // Rule #3
57 if (e1.border_.Width() < e2.border_.Width())
58 return -1;
59 // else
60 if (e2.border_.Width() < e1.border_.Width())
61 return 1;
62 // Rule #4
63 if (e1_style > e2_style)
64 return 1;
65 // else
66 if (e2_style > e1_style)
67 return -1;
68 // Rule #5
69 if (e1.precedence_ != e2.precedence_)
70 return e1.precedence_ < e2.precedence_ ? -1 : 1;
71 return 0;
72 }
73
74 // Like CompareEdges, except that HIDDEN edges lose
75 static int CompareIntersectionEdges(
76 const TableCollapsedBorderPainter::EdgeRecord& e1,
77 const TableCollapsedBorderPainter::EdgeRecord& e2) {
78 EBorderStyle e1_style = e1.border_.Style();
79 EBorderStyle e2_style = e2.border_.Style();
80 // Rule #1
81 if (e1_style == kBorderStyleHidden) {
82 if (e2_style == kBorderStyleHidden)
83 return 0;
84 // else
85 return -1;
86 }
87 if (e2_style == kBorderStyleHidden)
88 return 1;
89 return CompareEdges(e1, e2);
90 }
91
92 static std::string DirectionToStr(
93 TableCollapsedBorderPainter::EdgeDirection dir) {
94 switch (dir) {
95 case TableCollapsedBorderPainter::North:
96 return "North";
97 case TableCollapsedBorderPainter::West:
98 return "West";
99 case TableCollapsedBorderPainter::East:
100 return "East";
101 case TableCollapsedBorderPainter::South:
102 return "South";
103 case TableCollapsedBorderPainter::None:
104 return "None";
105 }
106 }
107
108 static std::string PrecedenceToStr(EBorderPrecedence p) {
109 switch (p) {
110 case kBorderPrecedenceOff:
111 return "OFF";
112 case kBorderPrecedenceTable:
113 return "TABLE";
114 case kBorderPrecedenceColumnGroup:
115 return "COLGROUP";
116 case kBorderPrecedenceColumn:
117 return "COL";
118 case kBorderPrecedenceRowGroup:
119 return "ROWGROUP";
120 case kBorderPrecedenceRow:
121 return "ROW";
122 case kBorderPrecedenceCell:
123 return "CELL";
124 }
125 }
126
127 void TableCollapsedBorderPainter::ShowEdge(unsigned row,
128 unsigned col,
129 EdgeDirection direction,
130 EBorderPrecedence precedence,
131 const BorderValue& border,
132 Color resolved_color) const {
133 Color c = border.GetColor().Resolve(resolved_color);
134 LOG(INFO) << "[" << row << " " << col << " " << DirectionToStr(direction)
135 << "] " << PrecedenceToStr(precedence) << " " << border.Width()
136 << " " << c.SerializedAsCSSComponentValue().Ascii().data();
137 }
138
139 void TableCollapsedBorderPainter::ShowEdges(bool show_hidden) const {
140 LOG(INFO) << "edges";
141 for (auto r = start_visible_row_; r <= end_visible_row_; r++) {
142 LOG(INFO) << "row:" << r;
143 for (auto c = start_visible_column_; c < end_visible_column_; c++) {
144 auto edgeIdx = EdgeToIndex(r, c, East);
145 if (edgeIdx != npos) {
146 EdgeRecord edge = edges_[edgeIdx];
147 if (show_hidden || edge.precedence_ != kBorderPrecedenceOff) {
148 ShowEdge(r, c, East, edge.precedence_, edge.border_,
149 edge.resolved_color_);
150 }
151 }
152 edgeIdx = EdgeToIndex(r, c, South);
153 if (edgeIdx != npos) {
154 EdgeRecord edge = edges_[edgeIdx];
155 if (show_hidden || edge.precedence_ != kBorderPrecedenceOff) {
156 ShowEdge(r, c, South, edge.precedence_, edge.border_,
157 edge.resolved_color_);
158 }
159 }
160 }
161 }
162 }
163
164 void TableCollapsedBorderPainter::ShowVisibleEdges(
165 const VisibleEdgeContainer& edges) const {
166 LOG(INFO) << "visedges";
167 for (auto edge = edges.begin(); edge < edges.end(); edge++) {
168 ShowEdge((*edge).m_row, (*edge).m_column, (*edge).direction_,
169 (*edge).precedence_, (*edge).border_, (*edge).resolved_color_);
170 }
171 }
172
173 void TableCollapsedBorderPainter::ShowIntersection(unsigned row,
174 unsigned col) const {
175 auto i = IntersectionToIndex(row, col);
176 if (i != npos) {
177 const Intersection in = intersections_[i];
178 if (in.direction_ != None) {
179 LOG(INFO) << "[" << row << ", " << col << "] " << in.width_.ToInt() << " "
180 << in.height_.ToInt()
181 << " Win:" << DirectionToStr(in.direction_);
182 }
183 }
184 }
185
186 void TableCollapsedBorderPainter::ShowIntersections() const {
187 LOG(INFO) << "intersections";
188 for (auto r = start_visible_row_; r <= end_visible_row_; r++) {
189 for (auto c = start_visible_column_; c < end_visible_column_; c++) {
190 ShowIntersection(r, c);
191 }
192 }
193 }
194
195 void TableCollapsedBorderPainter::PaintBorders(
196 const PaintInfo& paint_info,
197 const LayoutPoint& paint_offset,
198 const CellSpan& dirty_rows,
199 const CellSpan& dirty_columns,
200 const TableCollapsedBorderPainter& previous_painter) {
201 InitEdges(dirty_rows, dirty_columns, previous_painter);
202 // draw all the edges
203 // initial algorithm: just draw everything
204 // later algorithms: draw continuous lines if possible
205 InitIntersections();
206 PaintEdges(paint_info, paint_offset, dirty_rows, dirty_columns);
207 }
208
209 void TableCollapsedBorderPainter::InitEdges(
210 const CellSpan& dirty_rows,
211 const CellSpan& dirty_columns,
212 const TableCollapsedBorderPainter& previous_painter) {
213 // Initialize sizes
214 // number of rows/cols in the section
215 num_rows_ = layout_table_section_->NumRows();
216 num_effective_columns_ =
217 layout_table_section_->Table()->NumEffectiveColumns();
218 // Coordinates of intersections whose edges we'd like to measure.
219 // Measurement area is dirty_rows x dirtyCols + single-cell wide border zone
220 // above/left of dirty area.
221 //
222 // Border zone is needed to measure intersections inside dirty area correctly.
223 //
224 // Number of intersections inside n-rows is n+1, inside m-cols is m+1
225 // start and end. End points to one beyond, equivalent to iterator's .end()
226 start_visible_row_ = dirty_rows.Start() == 0 ? 0 : dirty_rows.Start() - 1;
227 start_visible_column_ =
228 dirty_columns.Start() == 0 ? 0 : dirty_columns.Start() - 1;
229 end_visible_row_ = dirty_rows.end() + 1;
230 end_visible_column_ = dirty_columns.end() + 1;
231 unsigned edgeRowCount = end_visible_row_ - start_visible_row_;
232 unsigned edgeColumnCount = end_visible_column_ - start_visible_column_;
233 edges_.Resize(2 * edgeRowCount * edgeColumnCount);
234 PopulateEdges(dirty_rows, dirty_columns, previous_painter);
235 // ShowEdges();
236 }
237
238 void TableCollapsedBorderPainter::InitIntersections() {
239 max_intersection_width_ = 0;
240 max_intersection_height_ = 0;
241 intersections_.Resize((end_visible_row_ - start_visible_row_) *
242 (end_visible_column_ - start_visible_column_));
243 for (unsigned r = start_visible_row_; r < end_visible_row_; r++) {
244 for (unsigned c = start_visible_column_; c < end_visible_column_; c++) {
245 InitIntersection(r, c);
246 }
247 }
248 // ShowIntersections();
249 }
250
251 void TableCollapsedBorderPainter::InitIntersection(unsigned row, unsigned col) {
252 EdgeRecord edges[None];
253 for (int d = North; d < None; d++) {
254 unsigned index = EdgeToIndex(row, col, (EdgeDirection)d);
255 if (index != npos)
256 edges[d] = edges_[index];
257 }
258 EdgeDirection winner = North;
259 for (int d = West; d < None; d++) {
260 if (CompareIntersectionEdges(edges[winner], edges[d]) == -1)
261 winner = (EdgeDirection)d;
262 }
263 unsigned index = IntersectionToIndex(row, col);
264 // only set if our winner is really an edge
265 if (edges[winner].precedence_ != kBorderPrecedenceOff) {
266 unsigned width = 0;
267 unsigned height = 0;
268 if (winner == North || winner == South) {
269 width = edges[winner].border_.Width();
270 if (CompareIntersectionEdges(edges[East], edges[West]) < 1) // West won
271 height = edges[West].border_.Width();
272 else
273 height = edges[East].border_.Width();
274 } else { // winner == East || West
275 height = edges[winner].border_.Width();
276 if (CompareIntersectionEdges(edges[North], edges[South]) <
277 1) // South won
278 width = edges[South].border_.Width();
279 else
280 width = edges[North].border_.Width();
281 }
282 max_intersection_height_ = std::max(max_intersection_height_, height);
283 max_intersection_width_ = std::max(max_intersection_width_, width);
284 intersections_[index] =
285 Intersection(LayoutUnit(width), LayoutUnit(height), winner);
286 // LOG(INFO) << "In: " << row << " " << col << ": " << width << "px " <<
287 // height << "px " << DirectionToStr(winner);
288 }
289 }
290
291 void TableCollapsedBorderPainter::PopulateEdges(
292 const CellSpan& dirty_rows,
293 const CellSpan& dirty_columns,
294 const TableCollapsedBorderPainter& previous_painter) {
295 VisibleEdgeContainer edges;
296 // Iterate everything in reverse priority order
297 // populate adjacent edges from adjacent section
298 GetVisibleEdgesSiblingSection(edges, previous_painter);
299 MergeVisibleEdges(edges);
300 LayoutTable* table = layout_table_section_->Table();
301 // populate <table>
302 GetVisibleEdgesTable(edges, layout_table_section_->Table());
303 MergeVisibleEdges(edges);
304 // populate <colgroup>
305 Vector<const LayoutTableCol*> colgroups;
306 for (LayoutTableCol* colgroup = table->FirstColumn(); colgroup;
307 colgroup = colgroup->NextColumn())
308 colgroups.push_back(colgroup);
309 for (auto col_group = colgroups.rbegin(); col_group != colgroups.rend();
310 col_group++) {
311 if ((*col_group)->IsTableColumnGroup()) {
312 GetVisibleEdgesColgroup(edges, *col_group);
313 MergeVisibleEdges(edges);
314 }
315 }
316 // populate <col>
317 for (auto col = colgroups.rbegin(); col != colgroups.rend(); col++) {
318 if ((*col)->IsTableColumn()) {
319 GetVisibleEdgesCol(edges, *col);
320 MergeVisibleEdges(edges);
321 }
322 }
323 // populate <tbody>
324 GetVisibleEdgesSection(edges);
325 MergeVisibleEdges(edges);
326 // populate <tr>
327 for (int r = dirty_rows.end() - 1; r >= (int)dirty_rows.Start(); r--) {
328 const LayoutTableRow* row = layout_table_section_->RowLayoutObjectAt(r);
329 if (row) {
330 GetVisibleEdgesRow(edges, row);
331 MergeVisibleEdges(edges);
332 }
333 }
334 // populate <td>, iterate in reverse
335 TextDirection direction = layout_table_section_->Style()->Direction();
336 for (int r = dirty_rows.end() - 1; r >= (int)dirty_rows.Start(); r--) {
337 for (int c = dirty_columns.end() - 1; c >= (int)dirty_columns.Start();
338 c--) {
339 // HashSet for primary cell to eliminate duplicates
340 const LayoutTableCell* cell = layout_table_section_->PrimaryCellAt(r, c);
341 if (cell) {
342 GetVisibleEdgesCell(edges, cell, direction);
343 MergeVisibleEdges(edges);
344 }
345 }
346 }
347 // ShowEdges();
348 }
349
350 // Gets edges of the neighboring section
351 void TableCollapsedBorderPainter::GetVisibleEdgesSiblingSection(
352 VisibleEdgeContainer& edges,
353 const TableCollapsedBorderPainter& previous_painter) {
354 edges.clear();
355 bool is_above =
356 previous_painter.layout_table_section_ ==
357 layout_table_section_->Table()->SectionAbove(layout_table_section_);
358 bool is_below =
359 previous_painter.layout_table_section_ ==
360 layout_table_section_->Table()->SectionBelow(layout_table_section_);
361 if (!is_above && !is_below) {
362 // Happens if we are the first section
363 // LOG(INFO) << "not sure where sibling section is";
364 return;
365 }
366 unsigned siblingRow = is_above ? previous_painter.num_rows_ : 0;
367 unsigned my_row = is_above ? 0 : num_rows_;
368 for (unsigned c = previous_painter.start_visible_column_;
369 c <= previous_painter.end_visible_column_; c++) {
370 auto sibling_index = previous_painter.EdgeToIndex(siblingRow, c, East);
371 auto my_index = EdgeToIndex(my_row, c, East);
372 if (sibling_index != npos && my_index != npos) {
373 EdgeRecord sibling_edge = previous_painter.edges_[sibling_index];
374 edges.push_back(VisibleEdgeRecord(my_row, c, East, sibling_edge.border_,
375 sibling_edge.precedence_,
376 sibling_edge.resolved_color_));
377 }
378 }
379 }
380
381 void TableCollapsedBorderPainter::GetVisibleEdgesTable(
382 VisibleEdgeContainer& edges,
383 const LayoutTable* table) {
384 edges.clear();
385 Color resolved_color = table->ResolveColor(CSSPropertyColor);
386 const ComputedStyle* border_style = table->Style();
387 const BorderValue* top_border = &border_style->BorderTop();
388 const BorderValue* right_border = &border_style->BorderRight();
389 const BorderValue* bottom_border = &border_style->BorderBottom();
390 const BorderValue* left_border = &border_style->BorderLeft();
391 RotateBorders(layout_table_section_->Style()->Direction(),
392 table->Style()->GetWritingMode(), &top_border, &right_border,
393 &bottom_border, &left_border);
394 // top row, only if we abut table top
395 if (this->layout_table_section_ == table->TopNonEmptySection()) {
396 FillHorizontalEdges(edges, 0, 0, num_effective_columns_, *top_border,
397 kBorderPrecedenceTable, resolved_color);
398 }
399 // bottom row, only if we abut table bottom
400 if (this->layout_table_section_ == table->BottomNonEmptySection()) {
401 FillHorizontalEdges(edges, num_rows_, 0, num_effective_columns_,
402 *bottom_border, kBorderPrecedenceTable, resolved_color);
403 }
404 FillVerticalEdges(edges, 0, 0, num_rows_, *left_border,
405 kBorderPrecedenceTable, resolved_color);
406 FillVerticalEdges(edges, num_effective_columns_, 0, num_rows_, *right_border,
407 kBorderPrecedenceTable, resolved_color);
408 }
409
410 void TableCollapsedBorderPainter::GetVisibleEdgesSection(
411 VisibleEdgeContainer& edges) {
412 edges.clear();
413 Color resolved_color = layout_table_section_->ResolveColor(CSSPropertyColor);
414 // Traverse all the section edges, and assign them
415 FillVisibleRect(edges, 0, 0, num_rows_, num_effective_columns_,
416 layout_table_section_->Style(), TextDirection::kLtr,
417 layout_table_section_->Style()->GetWritingMode(),
418 resolved_color, kBorderPrecedenceRowGroup);
419 }
420
421 void TableCollapsedBorderPainter::GetVisibleEdgesColgroup(
422 VisibleEdgeContainer& edges,
423 const LayoutTableCol* colgroup) {
424 edges.clear();
425 Color resolved_color = colgroup->ResolveColor(CSSPropertyColor);
426 Vector<unsigned> indexes = colgroup->GetEffectiveColumnIndexes();
427 if (indexes.size() > 0) {
428 unsigned start_col_index = indexes[0];
429 unsigned end_col_index = indexes.back() + 1;
430 FillVisibleRect(edges, 0, start_col_index, num_rows_, end_col_index,
431 colgroup->Style(), colgroup->Style()->Direction(),
432 colgroup->Style()->GetWritingMode(), resolved_color,
433 kBorderPrecedenceColumnGroup);
434 }
435 }
436
437 void TableCollapsedBorderPainter::GetVisibleEdgesCol(
438 VisibleEdgeContainer& edges,
439 const LayoutTableCol* col) {
440 edges.clear();
441 Color resolved_color = col->ResolveColor(CSSPropertyColor);
442 LayoutTable* table = layout_table_section_->Table();
443 if (!table)
444 return;
445 Vector<unsigned> indexes = col->GetEffectiveColumnIndexes();
446 if (indexes.size() > 0) {
447 // fill multiple virtual columns
448 for (auto idx = indexes.rbegin(); idx != indexes.rend(); ++idx) {
449 FillVisibleRect(edges, 0, *idx, num_rows_, *idx + 1, col->Style(),
450 col->Style()->Direction(), col->Style()->GetWritingMode(),
451 resolved_color, kBorderPrecedenceColumn);
452 }
453 }
454 // unsigned startAbsoluteColIndex = table->colElementToAbsoluteColumn(col);
455 // unsigned endAbsoluteColIndex = startAbsoluteColIndex + col->span();
456 // unsigned start_col_index =
457 // table->absolute_columnToEffectiveColumn(startAbsoluteColIndex); unsigned
458 // end_col_index =
459 // table->absolute_columnToEffectiveColumn(endAbsoluteColIndex);
460 // // We replicat column span times. Weird, but that is the standard:
461 // // "For the purposes of the CSS table model, the col element is expected to
462 // be treated as if it was present as many times as its span attribute
463 // specifies." for (auto tmpEnd = end_col_index; tmpEnd > start_col_index;
464 // tmpEnd--) {
465 // FillVisibleRect(edges, 0, tmpEnd - 1, num_rows_, tmpEnd, col->Style(),
466 // col->Style()->Direction(), col->Style()->GetWritingMode(),
467 // resolved_color, BorderPrecedenceColumn);
468 // }
469 }
470
471 void TableCollapsedBorderPainter::GetVisibleEdgesRow(
472 VisibleEdgeContainer& edges,
473 const LayoutTableRow* row) {
474 edges.clear();
475 Color resolved_color = row->ResolveColor(CSSPropertyColor);
476 unsigned rowIndex = row->RowIndex();
477 // We get direction from section because row direction only applies to cells,
478 // not the entire row.
479 FillVisibleRect(edges, rowIndex, 0, rowIndex + 1, num_effective_columns_,
480 row->Style(), layout_table_section_->Style()->Direction(),
481 row->Style()->GetWritingMode(), resolved_color,
482 kBorderPrecedenceRow);
483 }
484
485 void TableCollapsedBorderPainter::GetVisibleEdgesCell(
486 VisibleEdgeContainer& edges,
487 const LayoutTableCell* cell,
488 TextDirection direction) {
489 edges.clear();
490 Color resolved_color = cell->ResolveColor(CSSPropertyColor);
491 if (!cell->Parent()) {
492 LOG(INFO) << "DETACHED CELL";
493 return;
494 }
495 const LayoutTable* table = layout_table_section_->Table();
496 unsigned start_row = cell->Parent() ? cell->RowIndex() : 65000;
497 unsigned absolute_col = cell->AbsoluteColumnIndex();
498 unsigned eff_start_col = table->AbsoluteColumnToEffectiveColumn(absolute_col);
499 unsigned eff_end_col =
500 table->AbsoluteColumnToEffectiveColumn(absolute_col + cell->ColSpan());
501 unsigned end_row = std::min(start_row + cell->RowSpan(), num_rows_);
502 // LOG(INFO) << "m_columns: " << table->effective_columns().size()
503 // << " start_row: " << start_row << " end_row: " << end_row
504 // << " startCol: " << eff_start_col << " endCol:" << eff_end_col
505 // << " abscol:" << absolute_col;
506 // Fill border
507 // cell's direction is LTR because we do not rotate cell's borders
508 FillVisibleRect(edges, start_row, eff_start_col, end_row, eff_end_col,
509 cell->Style(), direction, cell->Style()->GetWritingMode(),
510 resolved_color, kBorderPrecedenceCell);
511 // Hide row inner edges
512 for (unsigned row = start_row + 1; row < end_row; row++) {
513 if (row >= start_visible_row_ && row < end_visible_row_) {
514 for (unsigned effCol = eff_start_col; effCol < eff_end_col; effCol++) {
515 if (effCol >= start_visible_column_ && effCol < end_visible_column_) {
516 edges.push_back(VisibleEdgeRecord(row, effCol, East, hidden_border_,
517 kBorderPrecedenceCell,
518 resolved_color, true));
519 }
520 }
521 }
522 }
523 // Hide col inner edges
524 for (unsigned effCol = eff_start_col + 1; effCol < eff_end_col; effCol++) {
525 if (effCol >= start_visible_column_ && effCol < end_visible_column_) {
526 for (unsigned row = start_row; row < end_row; row++) {
527 if (row >= start_visible_row_ && row < end_visible_row_) {
528 edges.push_back(VisibleEdgeRecord(row, effCol, South, hidden_border_,
529 kBorderPrecedenceCell,
530 resolved_color, true));
531 }
532 }
533 }
534 }
535 // ShowVisibleEdges(edges);
536 }
537
538 void TableCollapsedBorderPainter::RotateBorders(
539 TextDirection text_direction,
540 WritingMode writing_mode,
541 const BorderValue** top,
542 const BorderValue** right,
543 const BorderValue** bottom,
544 const BorderValue** left) const {
545 bool is_ltr = blink::IsLeftToRightDirection(text_direction);
546 if (blink::IsHorizontalWritingMode(writing_mode)) {
547 if (is_ltr) {
548 } // do nothing
549 else {
550 std::swap(*right, *left);
551 }
552 } else if (blink::IsFlippedBlocksWritingMode(writing_mode)) {
553 if (is_ltr) {
554 auto tmp = *top;
555 *top = *right;
556 *right = *bottom;
557 *bottom = *left;
558 *left = tmp;
559 } else {
560 std::swap(*top, *right);
561 std::swap(*bottom, *left);
562 }
563 } else { // IsFlippedLinesWritingMode
564 if (is_ltr) {
565 std::swap(*bottom, *right);
566 std::swap(*left, *top);
567 } else {
568 auto tmp = *top;
569 *top = *left;
570 *left = *bottom;
571 *bottom = *right;
572 *right = tmp;
573 }
574 }
575 }
576
577 void TableCollapsedBorderPainter::FillVisibleRect(
578 VisibleEdgeContainer& edges,
579 unsigned start_row,
580 unsigned start_column,
581 unsigned end_row,
582 unsigned end_column,
583 const ComputedStyle* border_style,
584 TextDirection text_direction,
585 WritingMode writing_mode,
586 Color resolved_color,
587 EBorderPrecedence precedence) {
588 const BorderValue* top_border = &border_style->BorderTop();
589 const BorderValue* bottom_border = &border_style->BorderBottom();
590 const BorderValue* right_border = &border_style->BorderRight();
591 const BorderValue* left_border = &border_style->BorderLeft();
592 RotateBorders(text_direction, writing_mode, &top_border, &right_border,
593 &bottom_border, &left_border);
594 FillHorizontalEdges(edges, start_row, start_column, end_column, *top_border,
595 precedence, resolved_color);
596 FillHorizontalEdges(edges, end_row, start_column, end_column, *bottom_border,
597 precedence, resolved_color);
598 FillVerticalEdges(edges, start_column, start_row, end_row, *left_border,
599 precedence, resolved_color);
600 FillVerticalEdges(edges, end_column, start_row, end_row, *right_border,
601 precedence, resolved_color);
602 }
603
604 void TableCollapsedBorderPainter::FillHorizontalEdges(
605 VisibleEdgeContainer& edges,
606 unsigned row,
607 unsigned start_column,
608 unsigned end_column,
609 const BorderValue& border,
610 EBorderPrecedence precedence,
611 Color resolved_color) {
612 if (border.Style() == kBorderStyleNone)
613 return;
614 if (row >= start_visible_row_ && row < end_visible_row_) {
615 for (unsigned c = start_column; c < end_column; c++) {
616 // FIXME: modify for loop instead of comparing guard
617 if (c >= start_visible_column_ && c < end_visible_column_) {
618 edges.push_back(VisibleEdgeRecord(row, c, East, border, precedence,
619 resolved_color));
620 }
621 }
622 }
623 }
624
625 void TableCollapsedBorderPainter::FillVerticalEdges(
626 VisibleEdgeContainer& edges,
627 unsigned column,
628 unsigned start_row,
629 unsigned end_row,
630 const BorderValue& border,
631 EBorderPrecedence precedence,
632 Color resolved_color) {
633 if (border.Style() == kBorderStyleNone)
634 return;
635 if (column >= start_visible_column_ && column < end_visible_column_) {
636 for (unsigned r = start_row; r < end_row; r++) {
637 // FIXME: modify for loop instead of comparing guard
638 if (r >= start_visible_row_ && r < end_visible_row_) {
639 edges.push_back(VisibleEdgeRecord(r, column, South, border, precedence,
640 resolved_color));
641 }
642 }
643 }
644 }
645
646 void TableCollapsedBorderPainter::MergeVisibleEdges(
647 VisibleEdgeContainer& edges) {
648 for (auto edge = edges.begin(); edge < edges.end(); edge++) {
649 unsigned idx =
650 EdgeToIndex((*edge).m_row, (*edge).m_column, (*edge).direction_);
651 DCHECK(idx != npos);
652 EdgeRecord edge_record((*edge).border_, (*edge).precedence_,
653 (*edge).resolved_color_);
654 if ((*edge).force_removal_)
655 edges_[idx] = edge_record;
656 // if both edges are same priority, new edge wins
657 if (CompareEdges(edges_[idx], edge_record) != 1)
658 edges_[idx] = edge_record;
659 }
660 }
661
662 static EBorderStyle CollapsedBorderStyle(EBorderStyle style) {
663 if (style == kBorderStyleOutset)
664 return kBorderStyleGroove;
665 if (style == kBorderStyleInset)
666 return kBorderStyleRidge;
667 return style;
668 }
669
670 void TableCollapsedBorderPainter::PaintEdges(const PaintInfo& paint_info,
671 const LayoutPoint& paint_offset,
672 const CellSpan& rows,
673 const CellSpan& cols) {
674 // see TableCellPainter::paintCollapsedBorders
675 LayoutRect paint_rect = layout_table_section_->GetCellPhysicalPosition(
676 rows.Start(), cols.Start());
677 paint_rect.Unite(layout_table_section_->GetCellPhysicalPosition(
678 rows.end() > 0 ? rows.end() - 1 : 0,
679 cols.end() > 0 ? cols.end() - 1 : 0));
680 // paint_rect size calculation is not exact, we expand by maxborder, instead
681 // of exact border
682 paint_rect.Expand(LayoutSize(LayoutUnit(max_intersection_width_ * 2),
683 LayoutUnit(max_intersection_height_ * 2)));
684 paint_rect.MoveBy(paint_offset);
685 LayoutPoint location = layout_table_section_->Location();
686 paint_rect.MoveBy(location);
687 if (LayoutObjectDrawingRecorder::UseCachedDrawingIfPossible(
688 paint_info.context, *layout_table_section_,
689 DisplayItem::kTableCollapsedBorderBase))
690 return;
691 LayoutObjectDrawingRecorder recorder(
692 paint_info.context, *layout_table_section_,
693 DisplayItem::kTableCollapsedBorderBase, paint_rect);
694 // Paint edges carefully to get them all
695 // Every row paint : ┌┌┌┌┌, then |
696 // Bottom border paint: _____
697 WritingMode writing_mode = layout_table_section_->Style()->GetWritingMode();
698 TextDirection text_direction = layout_table_section_->Style()->Direction();
699 for (unsigned r = rows.Start(); r < rows.end(); r++) {
700 // const LayoutTableRow * row = layout_table_section_->rowLayoutObjectAt(r);
701 // if (row)
702 // text_direction = row->Style()->Direction();
703 for (unsigned c = cols.Start(); c < cols.end(); c++) {
704 PaintOneEdge(paint_info, paint_offset, r, c, East, writing_mode,
705 text_direction);
706 PaintOneEdge(paint_info, paint_offset, r, c, South, writing_mode,
707 text_direction);
708 }
709 // paint the last column on edge
710 PaintOneEdge(paint_info, paint_offset, r, cols.end(), South, writing_mode,
711 text_direction);
712 }
713 // Paint the last row
714 for (unsigned c = cols.Start(); c < cols.end(); c++) {
715 PaintOneEdge(paint_info, paint_offset, rows.end(), c, East, writing_mode,
716 text_direction);
717 }
718 }
719
720 // Returns a rect that encloses 'direction' border of the cell_rect
721 LayoutRect TableCollapsedBorderPainter::CellRectAsBorder(
722 const LayoutRect& cell_rect,
723 BoxSide side,
724 unsigned border_width,
725 WritingMode writing_mode,
726 TextDirection text_direction) {
727 LayoutUnit small_half(border_width / 2); // C++ always rounds down
728 // unsigned bigHalf = border_width - small_half;
729 LayoutUnit top_offset;
730 LayoutUnit left_offset;
731 /* Tricky: if the border width is odd, we need a consistent way of
732 * distributing the extra pixel. The rule is:
733 * - south and east edges always get the extra pixel on the inside
734 * of the cell
735 * */
736 bool is_ltr = blink::IsLeftToRightDirection(text_direction);
737 if (blink::IsHorizontalWritingMode(writing_mode)) {
738 if (is_ltr) {
739 top_offset = small_half;
740 left_offset = small_half;
741 } else {
742 top_offset = small_half;
743 left_offset = small_half;
744 }
745 } else { // vertical
746 if (blink::IsFlippedBlocksWritingMode(writing_mode)) {
747 if (is_ltr) {
748 top_offset = small_half;
749 left_offset = small_half;
750 } else {
751 top_offset = small_half;
752 left_offset = small_half;
753 }
754 } else { // flippedLines
755 if (is_ltr) {
756 top_offset = small_half;
757 left_offset = small_half;
758 } else {
759 top_offset = small_half;
760 left_offset = small_half;
761 }
762 }
763 }
764 switch (side) {
765 case kBSTop:
766 return LayoutRect(
767 LayoutPoint(cell_rect.X(), cell_rect.Y() - top_offset),
768 LayoutSize(cell_rect.Width(), LayoutUnit(border_width)));
769 case kBSBottom:
770 return LayoutRect(
771 LayoutPoint(cell_rect.X(), cell_rect.MaxY() - top_offset),
772 LayoutSize(cell_rect.Width(), LayoutUnit(border_width)));
773 case kBSLeft:
774 return LayoutRect(
775 LayoutPoint(cell_rect.X() - left_offset, cell_rect.Y()),
776 LayoutSize(LayoutUnit(border_width), cell_rect.Height()));
777 case kBSRight:
778 return LayoutRect(
779 LayoutPoint(cell_rect.MaxX() - left_offset, cell_rect.Y()),
780 LayoutSize(LayoutUnit(border_width), cell_rect.Height()));
781 }
782 }
783
784 //
785 LayoutRect TableCollapsedBorderPainter::EdgePaintPosition(
786 unsigned row,
787 unsigned col,
788 unsigned border_width,
789 EdgeDirection direction,
790 WritingMode writing_mode,
791 TextDirection text_direction) {
792 // Compute edge's size from size of the cell
793 LayoutRect position;
794 bool is_ltr = blink::IsLeftToRightDirection(text_direction);
795 BoxSide side = kBSLeft;
796 LayoutRect cell_rect;
797 // If this is the last row intersection, get size from cell in next to last
798 if (row == num_rows_) {
799 DCHECK(direction == East);
800 cell_rect = GetCellPhysicalPosition(row - 1, col);
801 if (blink::IsHorizontalWritingMode(writing_mode)) {
802 side = kBSBottom;
803 } else if (blink::IsFlippedBlocksWritingMode(writing_mode)) {
804 side = kBSLeft;
805 } else {
806 side = kBSRight;
807 }
808 } else if (col == num_effective_columns_) {
809 // If this is the last column, get size from the cell before
810 DCHECK(direction == South);
811 cell_rect = GetCellPhysicalPosition(row, col - 1);
812 if (blink::IsHorizontalWritingMode(writing_mode)) {
813 side = is_ltr ? kBSRight : kBSLeft;
814 } else if (blink::IsFlippedBlocksWritingMode(writing_mode)) {
815 side = is_ltr ? kBSBottom : kBSTop;
816 } else {
817 side = is_ltr ? kBSBottom : kBSTop;
818 }
819 } else {
820 cell_rect = GetCellPhysicalPosition(row, col);
821 if (direction == East) {
822 if (blink::IsHorizontalWritingMode(writing_mode)) {
823 side = kBSTop;
824 } else if (blink::IsFlippedBlocksWritingMode(writing_mode)) {
825 side = kBSRight;
826 } else {
827 side = kBSLeft;
828 }
829 } else { // direction == South
830 if (blink::IsHorizontalWritingMode(writing_mode)) {
831 side = is_ltr ? kBSLeft : kBSRight;
832 } else if (blink::IsFlippedBlocksWritingMode(writing_mode)) {
833 side = is_ltr ? kBSTop : kBSBottom;
834 } else { // flippedLines
835 side = is_ltr ? kBSTop : kBSBottom;
836 }
837 }
838 }
839 return CellRectAsBorder(cell_rect, side, border_width, writing_mode,
840 text_direction);
841 }
842
843 // Paints an edge starting from intersection[row, col] in direction
844 void TableCollapsedBorderPainter::PaintOneEdge(const PaintInfo& paint_info,
845 const LayoutPoint& paint_offset,
846 unsigned row,
847 unsigned col,
848 EdgeDirection direction,
849 WritingMode writing_mode,
850 TextDirection text_direction) {
851 DCHECK(direction == South || direction == East);
852 unsigned idx = EdgeToIndex(row, col, direction);
853 DCHECK(idx != npos);
854 const BorderValue& border = edges_[idx].border_;
855 if (border.Style() == kBorderStyleHidden || !border.NonZero())
856 return;
857 LayoutTableSection* section_above =
858 layout_table_section_->Table()->SectionAbove(layout_table_section_,
859 kSkipEmptySections);
860 if (!row && direction == East && section_above) {
861 return;
862 }
863 // EdgeRecord edge = edges_[idx];
864 // ShowEdge(row, col, direction, edge.precedence_, edge.border_,
865 // border.Color().Resolve(edges_[idx].resolved_color_));
866 LayoutRect position = EdgePaintPosition(row, col, border.Width(), direction,
867 writing_mode, text_direction);
868 AdjustForIntersections(position, row, col, direction, writing_mode,
869 text_direction);
870 // Offset by section_location
871 LayoutPoint section_location = layout_table_section_->Location();
872 position.MoveBy(section_location);
873 position.MoveBy(paint_offset);
874 BoxSide side;
875 if (blink::IsHorizontalWritingMode(writing_mode))
876 side = direction == East ? kBSTop : kBSLeft;
877 else
878 side = direction == East ? kBSLeft : kBSTop;
879 ObjectPainter::DrawLineForBoxSide(
880 paint_info.context, position.X(), position.Y(), position.MaxX(),
881 position.MaxY(), // left, top, right, bottom,
882 side, border.GetColor().Resolve(edges_[idx].resolved_color_),
883 CollapsedBorderStyle(border.Style()), 0, 0, true);
884 }
885
886 void TableCollapsedBorderPainter::AdjustForIntersections(
887 LayoutRect& position,
888 unsigned row,
889 unsigned col,
890 EdgeDirection direction,
891 WritingMode writing_mode,
892 TextDirection text_direction) {
893 DCHECK(direction == South || direction == East);
894 const Intersection* start_intersection = nullptr;
895 const Intersection* end_intersection = nullptr;
896 bool winner_start = false;
897 bool winner_end = false;
898 // START intersection
899 unsigned index = IntersectionToIndex(row, col);
900 if (index != npos) {
901 start_intersection = &intersections_[index];
902 winner_start = start_intersection->direction_ == direction;
903 }
904 // END intersection
905 if (direction == South)
906 row += 1;
907 else
908 col += 1;
909 index = IntersectionToIndex(row, col);
910 if (index != npos) {
911 end_intersection = &intersections_[index];
912 if (direction == South)
913 winner_end = end_intersection->direction_ == North;
914 else
915 winner_end = end_intersection->direction_ == West;
916 }
917 bool is_ltr = blink::IsLeftToRightDirection(text_direction);
918 if (blink::IsHorizontalWritingMode(writing_mode)) {
919 AdjustForIntersectionsHorizontal(position, direction, is_ltr,
920 start_intersection, winner_start,
921 end_intersection, winner_end);
922 } else if (blink::IsFlippedBlocksWritingMode(writing_mode)) {
923 AdjustForIntersectionsFlippedBlocks(position, direction, is_ltr,
924 start_intersection, winner_start,
925 end_intersection, winner_end);
926 } else if (blink::IsFlippedLinesWritingMode(writing_mode)) {
927 AdjustForIntersectionsFlippedLines(position, direction, is_ltr,
928 start_intersection, winner_start,
929 end_intersection, winner_end);
930 } else {
931 DCHECK(false);
932 }
933 }
934
935 /*
936 * writing-mode: HORIZONTAL-TB
937 * N
938 * compass: W--+--E intersection: <--width -->
939 * S
940 * start intersection
941 * South edge, win : expand top by height/2
942 * South edge, lose: shrink top by
943 * height/2 East edge, win : expand left by width/2 East edge, lose : shrink
944 * left by width/2 end
945 * intersection South
946 * edge, win :
947 * expand bottom by height/2 South edge lose : shrink bottom by height/2 East
948 * edge, win : expand right by width/2 East edge, lose : shrink right
949 * by
950 * width/2 writing-mode: HORIZONTAL(RTL)
951 * N
952 * compass:
953 * E--+--W intersection: <-- width -->
954 * S
955 * same
956 * as HORIZONTAL-TB in South direction start intersection South: same as LTR
957 * East
958 * edge, win : expand right by width/2 East
959 * edge, lose : shrink right by
960 * width/2 end intersection South: same as LTR East
961 * edge, win : expand left by width/2 East edge, lose : shrink left by width/2
962 * */
963 void TableCollapsedBorderPainter::AdjustForIntersectionsHorizontal(
964 LayoutRect& position,
965 EdgeDirection direction,
966 bool is_ltr,
967 const Intersection* start_intersection,
968 bool winner_start,
969 const Intersection* end_intersection,
970 bool winner_end) {
971 if (start_intersection) {
972 if (direction == South) {
973 unsigned small_delta = start_intersection->height_.ToUnsigned() / 2;
974 unsigned big_delta =
975 start_intersection->height_.ToUnsigned() - small_delta;
976 if (winner_start) {
977 position.ExpandEdges(LayoutUnit(small_delta), LayoutUnit(0),
978 LayoutUnit(0), LayoutUnit(0));
979 } else {
980 position.ContractEdges(LayoutUnit(big_delta), LayoutUnit(0),
981 LayoutUnit(0), LayoutUnit(0));
982 }
983 } else { // East
984 unsigned small_delta = start_intersection->width_.ToUnsigned() / 2;
985 unsigned big_delta =
986 start_intersection->width_.ToUnsigned() - small_delta;
987 if (is_ltr) {
988 if (winner_start) {
989 position.ExpandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0),
990 LayoutUnit(small_delta));
991 } else {
992 position.ContractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0),
993 LayoutUnit(big_delta));
994 }
995 } else { // RTL
996 if (winner_start) {
997 position.ExpandEdges(LayoutUnit(0), LayoutUnit(small_delta),
998 LayoutUnit(0), LayoutUnit(0));
999 } else {
1000 position.ContractEdges(LayoutUnit(0), LayoutUnit(big_delta),
1001 LayoutUnit(0), LayoutUnit(0));
1002 }
1003 }
1004 }
1005 }
1006 if (end_intersection) {
1007 if (direction == South) {
1008 unsigned small_delta = end_intersection->height_.ToUnsigned() / 2;
1009 unsigned big_delta = end_intersection->height_.ToUnsigned() - small_delta;
1010 if (winner_end) {
1011 position.ExpandEdges(LayoutUnit(0), LayoutUnit(0),
1012 LayoutUnit(big_delta), LayoutUnit(0));
1013 } else {
1014 position.ContractEdges(LayoutUnit(0), LayoutUnit(0),
1015 LayoutUnit(small_delta), LayoutUnit(0));
1016 }
1017 } else { // East
1018 unsigned small_delta = end_intersection->width_.ToUnsigned() / 2;
1019 unsigned big_delta = end_intersection->width_.ToUnsigned() - small_delta;
1020 if (is_ltr) {
1021 if (winner_end) {
1022 position.ExpandEdges(LayoutUnit(0), LayoutUnit(big_delta),
1023 LayoutUnit(0), LayoutUnit(0));
1024 } else { // loser
1025 position.ContractEdges(LayoutUnit(0), LayoutUnit(small_delta),
1026 LayoutUnit(0), LayoutUnit(0));
1027 }
1028 } else { // RTL
1029 if (winner_end) {
1030 position.ExpandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0),
1031 LayoutUnit(big_delta));
1032 } else {
1033 position.ContractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0),
1034 LayoutUnit(small_delta));
1035 }
1036 }
1037 }
1038 }
1039 }
1040
1041 /*
1042 * writing-mode: VERTICAL-RL (flipped blocks)
1043 * W
1044 * compass: vertical: S--+--N intersection: <--- height
1045 * ---->
1046 * E
1047 * start intersection
1048 * South edge, win :
1049 * expand right by height/2 South edge, lose: shrink right by height/2 East
1050 * edge, win
1051 * : expand top by width/2 East edge, lose : shrink top by width/2 end
1052 * intersection South edge, win : expand left by height/2 South
1053 * edge, lose:
1054 * shrink left by height/2 East edge, win :
1055 * expand bottom by
1056 * width/2 East edge, lose : shrink bottom by width/2
1057 * writing-mode:
1058 * VERTICAL-RL RTL
1059 * E
1060 * compass:
1061 * vertical: S--+--N intersection: <--- height ---->
1062 * W
1063 * start
1064 * intersection South edge, win : expand right by height/2 South
1065 * edge, lose:
1066 * shrink right by height/2 East
1067 * edge, win : expand bottom by
1068 * width/2 East
1069 * edge, lose : shrink bottom by
1070 * width/2 end intersection South
1071 * edge, win :
1072 * expand left by height/2 South edge, lose: shrink left by height/2
1073 * East
1074 * edge, win : expand top by width/2 East edge, lose : shrink top by width/2
1075 * */
1076 void TableCollapsedBorderPainter::AdjustForIntersectionsFlippedBlocks(
1077 LayoutRect& position,
1078 EdgeDirection direction,
1079 bool is_ltr,
1080 const Intersection* start_intersection,
1081 bool winner_start,
1082 const Intersection* end_intersection,
1083 bool winner_end) {
1084 if (start_intersection) {
1085 if (direction == South) {
1086 unsigned small_delta = start_intersection->height_.ToUnsigned() / 2;
1087 unsigned big_delta =
1088 start_intersection->height_.ToUnsigned() - small_delta;
1089 if (winner_start) {
1090 position.ExpandEdges(LayoutUnit(0), LayoutUnit(small_delta),
1091 LayoutUnit(0), LayoutUnit(0));
1092 } else {
1093 position.ContractEdges(LayoutUnit(0), LayoutUnit(big_delta),
1094 LayoutUnit(0), LayoutUnit(0));
1095 }
1096 } else { // East
1097 unsigned small_delta = start_intersection->width_.ToUnsigned() / 2;
1098 unsigned big_delta =
1099 start_intersection->width_.ToUnsigned() - small_delta;
1100 if (is_ltr) {
1101 if (winner_start) {
1102 position.ExpandEdges(LayoutUnit(small_delta), LayoutUnit(0),
1103 LayoutUnit(0), LayoutUnit(0));
1104 } else {
1105 position.ContractEdges(LayoutUnit(big_delta), LayoutUnit(0),
1106 LayoutUnit(0), LayoutUnit(0));
1107 }
1108 } else { // RTL
1109 if (winner_start) {
1110 position.ExpandEdges(LayoutUnit(0), LayoutUnit(0),
1111 LayoutUnit(big_delta), LayoutUnit(0));
1112 } else {
1113 position.ContractEdges(LayoutUnit(0), LayoutUnit(0),
1114 LayoutUnit(small_delta), LayoutUnit(0));
1115 }
1116 }
1117 }
1118 }
1119 if (end_intersection) {
1120 if (direction == South) {
1121 unsigned small_delta = end_intersection->height_.ToUnsigned() / 2;
1122 unsigned big_delta = end_intersection->height_.ToUnsigned() - small_delta;
1123 if (winner_end) {
1124 position.ExpandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0),
1125 LayoutUnit(big_delta));
1126 } else {
1127 position.ContractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0),
1128 LayoutUnit(small_delta));
1129 }
1130 } else { // East
1131 unsigned small_delta = end_intersection->width_.ToUnsigned() / 2;
1132 unsigned big_delta = end_intersection->width_.ToUnsigned() - small_delta;
1133 if (is_ltr) {
1134 if (winner_end) {
1135 position.ExpandEdges(LayoutUnit(0), LayoutUnit(0),
1136 LayoutUnit(big_delta), LayoutUnit(0));
1137 } else { // loser
1138 position.ContractEdges(LayoutUnit(0), LayoutUnit(0),
1139 LayoutUnit(small_delta), LayoutUnit(0));
1140 }
1141 } else { // RTL
1142 if (winner_end) {
1143 position.ExpandEdges(LayoutUnit(big_delta), LayoutUnit(0),
1144 LayoutUnit(0), LayoutUnit(0));
1145 } else {
1146 position.ContractEdges(LayoutUnit(small_delta), LayoutUnit(0),
1147 LayoutUnit(0), LayoutUnit(0));
1148 }
1149 }
1150 }
1151 }
1152 }
1153
1154 /*
1155 * writing-mode: VERTICAL-LR (flipped lines)
1156 * W
1157 * compass: rotated N--+--S
1158 * E
1159 * start intersection
1160 * East edge, win : expand
1161 * top by width/2 East edge, lose : shrink top by width/2 South edge, win :
1162 * expand
1163 * left by height/2 South edge, lose: shrink left by height/2 end intersection
1164 * East
1165 * edge, win : expand bottom by width/2 East edge, lose
1166 * : shrink bottom by
1167 * width/2 South edge, win : expand right by height/2 South
1168 * edge lose : shrink right by height/2 writing-mode: VERTICAL-LR, DIRECTION RTL
1169 * E
1170 * compass:
1171 * N-+-S intersection <--height -->
1172 * W
1173 * start
1174 * intersection East edge. win : expand bottom by width / 2 East
1175 * edge, lose:
1176 * shrink bottom by width / 2 end intersection East
1177 * edge, win :
1178 * expand top by width / 2 East edge, lose: expand top by width / 2
1179 * */
1180 void TableCollapsedBorderPainter::AdjustForIntersectionsFlippedLines(
1181 LayoutRect& position,
1182 EdgeDirection direction,
1183 bool is_ltr,
1184 const Intersection* start_intersection,
1185 bool winner_start,
1186 const Intersection* end_intersection,
1187 bool winner_end) {
1188 if (start_intersection) {
1189 if (direction == South) {
1190 unsigned small_delta = start_intersection->height_.ToUnsigned() / 2;
1191 unsigned big_delta =
1192 start_intersection->height_.ToUnsigned() - small_delta;
1193 if (winner_start) {
1194 position.ExpandEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0),
1195 LayoutUnit(small_delta));
1196 } else {
1197 position.ContractEdges(LayoutUnit(0), LayoutUnit(0), LayoutUnit(0),
1198 LayoutUnit(big_delta));
1199 }
1200 } else { // East
1201 unsigned small_delta = start_intersection->width_.ToUnsigned() / 2;
1202 unsigned big_delta =
1203 start_intersection->width_.ToUnsigned() - small_delta;
1204 if (is_ltr) {
1205 if (winner_start) {
1206 position.ExpandEdges(LayoutUnit(small_delta), LayoutUnit(0),
1207 LayoutUnit(0), LayoutUnit(0));
1208 } else {
1209 position.ContractEdges(LayoutUnit(big_delta), LayoutUnit(0),
1210 LayoutUnit(0), LayoutUnit(0));
1211 }
1212 } else { // RTL
1213 if (winner_start) {
1214 position.ExpandEdges(LayoutUnit(0), LayoutUnit(0),
1215 LayoutUnit(small_delta), LayoutUnit(0));
1216 } else {
1217 position.ContractEdges(LayoutUnit(0), LayoutUnit(0),
1218 LayoutUnit(big_delta), LayoutUnit(0));
1219 }
1220 }
1221 }
1222 }
1223 if (end_intersection) {
1224 if (direction == South) {
1225 unsigned small_delta = end_intersection->height_.ToUnsigned() / 2;
1226 unsigned big_delta = end_intersection->height_.ToUnsigned() - small_delta;
1227 if (winner_end) {
1228 position.ExpandEdges(LayoutUnit(0), LayoutUnit(big_delta),
1229 LayoutUnit(0), LayoutUnit(0));
1230 } else {
1231 position.ContractEdges(LayoutUnit(0), LayoutUnit(small_delta),
1232 LayoutUnit(0), LayoutUnit(0));
1233 }
1234 } else { // East
1235 unsigned small_delta = end_intersection->width_.ToUnsigned() / 2;
1236 unsigned big_delta = end_intersection->width_.ToUnsigned() - small_delta;
1237 if (is_ltr) {
1238 if (winner_end) {
1239 position.ExpandEdges(LayoutUnit(0), LayoutUnit(0),
1240 LayoutUnit(big_delta), LayoutUnit(0));
1241 } else { // loser
1242 position.ContractEdges(LayoutUnit(0), LayoutUnit(0),
1243 LayoutUnit(small_delta), LayoutUnit(0));
1244 }
1245 } else { // RTL
1246 if (winner_end) {
1247 position.ExpandEdges(LayoutUnit(big_delta), LayoutUnit(0),
1248 LayoutUnit(0), LayoutUnit(0));
1249 } else {
1250 position.ContractEdges(LayoutUnit(small_delta), LayoutUnit(0),
1251 LayoutUnit(0), LayoutUnit(0));
1252 }
1253 }
1254 }
1255 }
1256 }
1257
1258 // returns edge index for position, TableCollapsedBorderPainter::npos if out of
1259 // range topLeft intersection is 0, 0, bottomRight is numRows+1, numColumns + 1
1260 unsigned TableCollapsedBorderPainter::EdgeToIndex(
1261 unsigned intersection_row,
1262 unsigned intersection_column,
1263 EdgeDirection direction) const {
1264 /* Edges map to edges_ like this:
1265 * - each intersection 'stores' only two edges: east and south edges
1266 * - to map edge to index:
1267 * - find intersection so that requested edge is east or south
1268 * - edge is row * cols * 2 + (east ? 0 : 1)
1269 * - for example:
1270 * - North edge at intersection 5, 3, is also
1271 * South edge at intersection 4, 3 - its index is 4 (rows) * 3 (cols) * 2 + 1
1272 * (for South)
1273 * */
1274 switch (direction) {
1275 case North:
1276 intersection_row -= 1;
1277 direction = South;
1278 break;
1279 case West:
1280 intersection_column -= 1;
1281 direction = East;
1282 break;
1283 case South:
1284 case East:
1285 case None:
1286 break;
1287 }
1288 // Check if we are inside the covered area
1289 if (intersection_row < start_visible_row_ ||
1290 intersection_column < start_visible_column_ ||
1291 intersection_row >= end_visible_row_ ||
1292 intersection_column >= end_visible_column_) {
1293 // LOG(ERROR) << "GOT AN NPOS";
1294 return TableCollapsedBorderPainter::npos;
1295 }
1296 unsigned index = (intersection_row - start_visible_row_) *
1297 (end_visible_column_ - start_visible_column_) * 2;
1298 index += (intersection_column - start_visible_column_) * 2;
1299 return direction == East ? index
1300 : index + 1; // each vertex holds [East, South]
1301 }
1302
1303 unsigned TableCollapsedBorderPainter::IntersectionToIndex(
1304 unsigned row,
1305 unsigned column) const {
1306 if (row < start_visible_row_ || column < start_visible_column_ ||
1307 row >= end_visible_row_ || column >= end_visible_column_)
1308 return TableCollapsedBorderPainter::npos;
1309 return (row - start_visible_row_) *
1310 (end_visible_column_ - start_visible_column_) +
1311 column;
1312 }
1313 }
1314 // blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698