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 #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 |
OLD | NEW |