1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_EXCLUSION_SPACE_H_ 6 #define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_EXCLUSION_SPACE_H_ 7 8 #include "third_party/blink/renderer/core/core_export.h" 9 #include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion.h" 10 #include "third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h" 11 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h" 12 #include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_rect.h" 13 #include "third_party/blink/renderer/core/style/computed_style_constants.h" 14 #include "third_party/blink/renderer/platform/geometry/layout_unit.h" 15 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" 16 #include "third_party/blink/renderer/platform/wtf/vector.h" 17 18 namespace blink { 19 20 typedef Vector<NGLayoutOpportunity, 8> LayoutOpportunityVector; 21 typedef base::RefCountedData<WTF::Vector<scoped_refptr<const NGExclusion>>> 22 NGExclusionPtrArray; 23 24 // This class is an implementation detail. For use of the exclusion space, 25 // see NGExclusionSpace below. NGExclusionSpace was designed to be cheap 26 // to construct and cheap to copy if empty. 27 class CORE_EXPORT NGExclusionSpaceInternal { 28 USING_FAST_MALLOC(NGExclusionSpaceInternal); 29 30 public: 31 NGExclusionSpaceInternal(); 32 NGExclusionSpaceInternal(const NGExclusionSpaceInternal&); 33 NGExclusionSpaceInternal(NGExclusionSpaceInternal&&) noexcept; 34 NGExclusionSpaceInternal& operator=(const NGExclusionSpaceInternal&); 35 NGExclusionSpaceInternal& operator=(NGExclusionSpaceInternal&&) noexcept; ~NGExclusionSpaceInternal()36 ~NGExclusionSpaceInternal() {} 37 38 void Add(scoped_refptr<const NGExclusion> exclusion); 39 FindLayoutOpportunity(const NGBfcOffset & offset,const LayoutUnit available_inline_size,const LayoutUnit minimum_inline_size)40 NGLayoutOpportunity FindLayoutOpportunity( 41 const NGBfcOffset& offset, 42 const LayoutUnit available_inline_size, 43 const LayoutUnit minimum_inline_size) const { 44 // If the area clears all floats, we can just return the layout opportunity 45 // which matches the available space. 46 if (offset.block_offset >= 47 std::max(left_clear_offset_, right_clear_offset_)) { 48 NGBfcOffset end_offset( 49 offset.line_offset + available_inline_size.ClampNegativeToZero(), 50 LayoutUnit::Max()); 51 return NGLayoutOpportunity(NGBfcRect(offset, end_offset), nullptr); 52 } 53 54 return GetDerivedGeometry(offset.block_offset) 55 .FindLayoutOpportunity(offset, available_inline_size, 56 minimum_inline_size); 57 } 58 AllLayoutOpportunities(const NGBfcOffset & offset,const LayoutUnit available_inline_size)59 LayoutOpportunityVector AllLayoutOpportunities( 60 const NGBfcOffset& offset, 61 const LayoutUnit available_inline_size) const { 62 // If the area clears all floats, we can just return a single layout 63 // opportunity which matches the available space. 64 if (offset.block_offset >= 65 std::max(left_clear_offset_, right_clear_offset_)) { 66 NGBfcOffset end_offset( 67 offset.line_offset + available_inline_size.ClampNegativeToZero(), 68 LayoutUnit::Max()); 69 return LayoutOpportunityVector( 70 {NGLayoutOpportunity(NGBfcRect(offset, end_offset), nullptr)}); 71 } 72 73 return GetDerivedGeometry(offset.block_offset) 74 .AllLayoutOpportunities(offset, available_inline_size); 75 } 76 ClearanceOffset(EClear clear_type)77 LayoutUnit ClearanceOffset(EClear clear_type) const { 78 switch (clear_type) { 79 case EClear::kNone: 80 return LayoutUnit::Min(); 81 case EClear::kLeft: 82 return left_clear_offset_; 83 case EClear::kRight: 84 return right_clear_offset_; 85 case EClear::kBoth: 86 return std::max(left_clear_offset_, right_clear_offset_); 87 default: 88 NOTREACHED(); 89 return LayoutUnit::Min(); 90 } 91 } 92 LastFloatBlockStart()93 LayoutUnit LastFloatBlockStart() const { return last_float_block_start_; } 94 IsEmpty()95 bool IsEmpty() const { return !num_exclusions_; } 96 97 // Pre-initializes the exclusions vector to something used in a previous 98 // layout pass, however keeps the number of exclusions as zero. PreInitialize(const NGExclusionSpaceInternal & other)99 void PreInitialize(const NGExclusionSpaceInternal& other) { 100 DCHECK(exclusions_->data.IsEmpty()); 101 DCHECK_GT(other.exclusions_->data.size(), 0u); 102 103 exclusions_ = other.exclusions_; 104 } 105 106 // See |NGExclusionSpace::MoveAndUpdateDerivedGeometry|. MoveAndUpdateDerivedGeometry(const NGExclusionSpaceInternal & other)107 void MoveAndUpdateDerivedGeometry(const NGExclusionSpaceInternal& other) { 108 if (!other.derived_geometry_) 109 return; 110 111 MoveDerivedGeometry(other); 112 113 // Iterate through all the exclusions which were added by the layout, and 114 // update the DerivedGeometry. 115 for (wtf_size_t i = other.num_exclusions_; i < num_exclusions_; ++i) { 116 const NGExclusion& exclusion = *exclusions_->data.at(i); 117 118 // If we come across an exclusion with shape data, we opt-out of this 119 // optimization. 120 if (!track_shape_exclusions_ && exclusion.shape_data) { 121 track_shape_exclusions_ = true; 122 derived_geometry_ = nullptr; 123 return; 124 } 125 126 derived_geometry_->Add(exclusion); 127 } 128 } 129 130 // See |NGExclusionSpace::MoveDerivedGeometry|. MoveDerivedGeometry(const NGExclusionSpaceInternal & other)131 void MoveDerivedGeometry(const NGExclusionSpaceInternal& other) { 132 if (!other.derived_geometry_) 133 return; 134 135 track_shape_exclusions_ = other.track_shape_exclusions_; 136 derived_geometry_ = std::move(other.derived_geometry_); 137 other.derived_geometry_ = nullptr; 138 } 139 140 // See |NGExclusionSpace::MergeExclusionSpaces|. MergeExclusionSpaces(const NGBfcDelta & offset_delta,const NGExclusionSpaceInternal & previous_output,const NGExclusionSpaceInternal * previous_input)141 void MergeExclusionSpaces(const NGBfcDelta& offset_delta, 142 const NGExclusionSpaceInternal& previous_output, 143 const NGExclusionSpaceInternal* previous_input) { 144 // We need to copy all the exclusions over which were added by the cached 145 // layout result. 146 for (wtf_size_t i = previous_input ? previous_input->num_exclusions_ : 0; 147 i < previous_output.num_exclusions_; ++i) { 148 Add(previous_output.exclusions_->data.at(i)->CopyWithOffset( 149 offset_delta)); 150 } 151 } 152 153 bool operator==(const NGExclusionSpaceInternal& other) const; 154 bool operator!=(const NGExclusionSpaceInternal& other) const { 155 return !(*this == other); 156 } 157 158 #if DCHECK_IS_ON() CheckSameForSimplifiedLayout(const NGExclusionSpaceInternal & other)159 void CheckSameForSimplifiedLayout( 160 const NGExclusionSpaceInternal& other) const { 161 DCHECK_EQ(num_exclusions_, other.num_exclusions_); 162 for (wtf_size_t i = 0; i < num_exclusions_; ++i) { 163 const auto& exclusion = *exclusions_->data.at(i); 164 const auto& other_exclusion = *other.exclusions_->data.at(i); 165 DCHECK(exclusion.rect == other_exclusion.rect); 166 DCHECK_EQ(exclusion.type, other_exclusion.type); 167 DCHECK_EQ((bool)exclusion.shape_data, (bool)other_exclusion.shape_data); 168 } 169 } 170 #endif 171 172 // This struct represents the side of a float against the "edge" of a shelf. 173 struct NGShelfEdge { NGShelfEdgeNGShelfEdge174 NGShelfEdge(LayoutUnit block_start, LayoutUnit block_end) 175 : block_start(block_start), block_end(block_end) {} 176 177 LayoutUnit block_start; 178 LayoutUnit block_end; 179 }; 180 181 // The shelf is an internal data-structure representing the bottom of a 182 // float. A shelf has a inline-size which is defined by the line_left and 183 // line_right members. E.g. 184 // 185 // 0 1 2 3 4 5 6 7 8 186 // 0 +---++--+ +---+ 187 // |xxx||xx| |xxx| 188 // 10 |xxx|X-------Xxxx| 189 // +---+ +---+ 190 // 20 191 // 192 // In the above diagram the shelf is at the block-end edge of the smallest 193 // float. It would have the internal values of: 194 // { 195 // block_offset: 10, 196 // line_left: 20, 197 // line_right: 65, 198 // line_left_edges: [{0, 15}], 199 // line_right_edges: [{0, 15}], 200 // } 201 // The line_left_edges and line_right_edges are all the floats which are 202 // "against" the shelf at the line_left and line_right offset respectively. 203 // 204 // An opportunity has a "solid" edge if there is at least one float adjacent 205 // to the line-left or line-right edge. If an opportunity has no adjacent 206 // floats it is invalid. 207 // 208 // These are used for: 209 // - When we create an opportunity, making sure it has "solid" edges. 210 // - The opportunity also holds onto a list of these edges to support 211 // css-shapes. 212 struct NGShelf { NGShelfNGShelf213 NGShelf(LayoutUnit block_offset, bool track_shape_exclusions) 214 : block_offset(block_offset), 215 line_left(LayoutUnit::Min()), 216 line_right(LayoutUnit::Max()), 217 shape_exclusions(track_shape_exclusions 218 ? base::AdoptRef(new NGShapeExclusions) 219 : nullptr), 220 has_shape_exclusions(false) {} 221 222 // The copy constructor explicitly copies the shape_exclusions member. NGShelfNGShelf223 NGShelf(const NGShelf& other) 224 : block_offset(other.block_offset), 225 line_left(other.line_left), 226 line_right(other.line_right), 227 line_left_edges(other.line_left_edges), 228 line_right_edges(other.line_right_edges), 229 shape_exclusions(other.shape_exclusions 230 ? base::AdoptRef(new NGShapeExclusions( 231 *other.shape_exclusions)) 232 : nullptr), 233 has_shape_exclusions(other.has_shape_exclusions) {} 234 235 NGShelf(NGShelf&& other) noexcept = default; 236 NGShelf& operator=(NGShelf&& other) noexcept = default; 237 238 LayoutUnit block_offset; 239 LayoutUnit line_left; 240 LayoutUnit line_right; 241 242 Vector<NGShelfEdge, 1> line_left_edges; 243 Vector<NGShelfEdge, 1> line_right_edges; 244 245 // shape_exclusions contains all the floats which sit below this shelf. The 246 // has_shape_exclusions member will be true if shape_exclusions contains an 247 // exclusion with shape-outside specified (and therefore should be copied 248 // to any layout opportunity). 249 scoped_refptr<NGShapeExclusions> shape_exclusions; 250 bool has_shape_exclusions; 251 }; 252 253 // The closed-off area is an internal data-structure representing an area 254 // above a float. It contains a layout opportunity, and two vectors of 255 // |NGShelfEdge|. E.g. 256 // 257 // 0 1 2 3 4 5 6 7 8 258 // 0 +---+. .+---+ 259 // |xxx|. .|xxx| 260 // 10 |xxx|. .|xxx| 261 // +---+. .+---+ 262 // 20 ........ 263 // +---+ 264 // 30 |xxx| 265 // |xxx| 266 // 40 +---+ 267 // 268 // In the above example the closed-off area is represented with the dotted 269 // line. 270 // 271 // It has the internal values of: 272 // { 273 // opportunity: { 274 // start_offset: {20, LayoutUnit::Min()}, 275 // end_offset: {65, 25}, 276 // } 277 // line_left_edges: [{0, 15}], 278 // line_right_edges: [{0, 15}], 279 // } 280 // 281 // Once a closed-off area has been created, it can never be changed due to 282 // the property that floats always align their block-start edges. 283 struct NGClosedArea { NGClosedAreaNGClosedArea284 NGClosedArea(NGLayoutOpportunity opportunity, 285 const Vector<NGShelfEdge, 1>& line_left_edges, 286 const Vector<NGShelfEdge, 1>& line_right_edges) 287 : opportunity(opportunity), 288 line_left_edges(line_left_edges), 289 line_right_edges(line_right_edges) {} 290 291 const NGLayoutOpportunity opportunity; 292 const Vector<NGShelfEdge, 1> line_left_edges; 293 const Vector<NGShelfEdge, 1> line_right_edges; 294 }; 295 296 private: 297 // In order to reduce the amount of Vector copies, instances of a 298 // NGExclusionSpaceInternal can share the same exclusions_ Vector. See the 299 // copy constructor. 300 // 301 // We implement a copy-on-write behaviour when adding an exclusion (if 302 // exclusions_.size(), and num_exclusions_ differs). 303 // 304 // num_exclusions_ is how many exclusions *this* instance of an exclusion 305 // space has, which may differ to the number of exclusions in the Vector. 306 scoped_refptr<NGExclusionPtrArray> exclusions_; 307 wtf_size_t num_exclusions_; 308 309 // These members are used for keeping track of the "lowest" offset for each 310 // type of float. This is used for implementing float clearance. 311 LayoutUnit left_clear_offset_ = LayoutUnit::Min(); 312 LayoutUnit right_clear_offset_ = LayoutUnit::Min(); 313 314 // This member is used for implementing the "top edge alignment rule" for 315 // floats. Floats can be positioned at negative offsets, hence is initialized 316 // the minimum value. 317 LayoutUnit last_float_block_start_ = LayoutUnit::Min(); 318 319 // In order to reduce the amount of copies related to bookkeeping shape data, 320 // we initially ignore exclusions with shape data. When we first see an 321 // exclusion with shape data, we set this flag, and rebuild the 322 // DerivedGeometry data-structure, to perform the additional bookkeeping. 323 bool track_shape_exclusions_; 324 325 // The derived geometry struct, is the data-structure which handles all of the 326 // queries on the exclusion space. It can always be rebuilt from exclusions_ 327 // and num_exclusions_. This is mutable as it is passed down a chain of 328 // exclusion spaces inside the copy constructor. E.g. 329 // 330 // NGExclusionSpace space1; 331 // space1.Add(exclusion1); 332 // space1.FindLayoutOpportunity(); // Builds derived_geometry_. 333 // 334 // NGExclusionSpace space2(space1); // Moves derived_geometry_ to space2. 335 // space2.Add(exclusion2); // Modifies derived_geometry_. 336 // 337 // space1.FindLayoutOpportunity(); // Re-builds derived_geometry_. 338 // 339 // This is efficient (desirable) as the common usage pattern is only the last 340 // exclusion space in the copy-chain is used for answering queries. Only when 341 // we trigger a (rare) re-layout case will we need to rebuild the 342 // derived_geometry_ data-structure. 343 struct CORE_EXPORT DerivedGeometry { 344 USING_FAST_MALLOC(DerivedGeometry); 345 346 public: 347 // |block_offset_limit| represents the highest block-offset for which the 348 // geometry is valid. |FindLayoutOpportunity| and |AllLayoutOpportunities| 349 // should not be called for a block-offset higher than this. 350 // If |NGExclusionSpaceInternal::GetDerivedGeometry| is called with a 351 // higher limit the geometry is rebuilt. 352 // 353 // |track_shape_exclusions| is used to tell the geometry to track shape 354 // exclusions. Tracking shape exclusions is expensive, and uncommon, so 355 // when an exclusion with a shape is added we rebuilt the geometry to track 356 // this. 357 DerivedGeometry(LayoutUnit block_offset_limit, bool track_shape_exclusions); 358 DerivedGeometry(DerivedGeometry&& o) noexcept = default; 359 360 void Add(const NGExclusion& exclusion); 361 362 NGLayoutOpportunity FindLayoutOpportunity( 363 const NGBfcOffset& offset, 364 const LayoutUnit available_inline_size, 365 const LayoutUnit minimum_inline_size) const; 366 367 LayoutOpportunityVector AllLayoutOpportunities( 368 const NGBfcOffset& offset, 369 const LayoutUnit available_inline_size) const; 370 371 template <typename LambdaFunc> 372 void IterateAllLayoutOpportunities(const NGBfcOffset& offset, 373 const LayoutUnit available_inline_size, 374 const LambdaFunc&) const; 375 376 // See |NGShelf| for a broad description of what shelves are. We always 377 // begin with one, which has the internal value of: 378 // { 379 // block_offset: LayoutUnit::Min(), 380 // line_left: LayoutUnit::Min(), 381 // line_right: LayoutUnit::Max(), 382 // } 383 // 384 Vector<NGShelf, 4> shelves_; 385 386 // See |NGClosedArea| for a broad description of what closed-off areas are. 387 // 388 // Floats always align their block-start edges. We exploit this property by 389 // keeping a list of closed-off areas. Once a closed-off area has been 390 // created, it can never change. 391 Vector<NGClosedArea, 4> areas_; 392 393 // This represents the highest block-offset for which the geometry is valid 394 // for. If |NGExclusionSpaceInternal::GetDerivedGeometry| is called with a 395 // higher limit it is rebuilt. 396 LayoutUnit block_offset_limit_; 397 398 bool track_shape_exclusions_; 399 }; 400 401 // Returns the derived_geometry_ member, potentially re-built from the 402 // exclusions_, and num_exclusions_ members. 403 const DerivedGeometry& GetDerivedGeometry( 404 LayoutUnit block_offset_limit) const; 405 406 // See DerivedGeometry struct description. 407 mutable std::unique_ptr<DerivedGeometry> derived_geometry_; 408 }; 409 410 // The exclusion space represents all of the exclusions within a block 411 // formatting context. 412 // 413 // The space is mutated simply by adding exclusions, and various information 414 // can be queried based on the exclusions. 415 class CORE_EXPORT NGExclusionSpace { 416 DISALLOW_NEW(); 417 418 public: 419 NGExclusionSpace() = default; NGExclusionSpace(const NGExclusionSpace & other)420 NGExclusionSpace(const NGExclusionSpace& other) 421 : exclusion_space_(other.exclusion_space_ ? new NGExclusionSpaceInternal( 422 *other.exclusion_space_) 423 : nullptr) {} 424 NGExclusionSpace(NGExclusionSpace&& other) noexcept = default; 425 426 NGExclusionSpace& operator=(const NGExclusionSpace& other) { 427 exclusion_space_ = other.exclusion_space_ 428 ? std::make_unique<NGExclusionSpaceInternal>( 429 *other.exclusion_space_) 430 : nullptr; 431 return *this; 432 } 433 NGExclusionSpace& operator=(NGExclusionSpace&& other) = default; 434 Add(scoped_refptr<const NGExclusion> exclusion)435 void Add(scoped_refptr<const NGExclusion> exclusion) { 436 if (!exclusion_space_) 437 exclusion_space_ = std::make_unique<NGExclusionSpaceInternal>(); 438 exclusion_space_->Add(std::move(exclusion)); 439 } 440 441 // Returns a layout opportunity, within the BFC. 442 // The area to search for layout opportunities is defined by the given offset, 443 // and |available_inline_size|. The layout opportunity must be greater than 444 // the given |minimum_inline_size|. 445 NGLayoutOpportunity FindLayoutOpportunity( 446 const NGBfcOffset& offset, 447 const LayoutUnit available_inline_size, 448 const LayoutUnit minimum_inline_size = LayoutUnit()) const { 449 if (!exclusion_space_) { 450 NGBfcOffset end_offset( 451 offset.line_offset + available_inline_size.ClampNegativeToZero(), 452 LayoutUnit::Max()); 453 return NGLayoutOpportunity(NGBfcRect(offset, end_offset), nullptr); 454 } 455 return exclusion_space_->FindLayoutOpportunity( 456 offset, available_inline_size, minimum_inline_size); 457 } 458 459 // If possible prefer FindLayoutOpportunity over this function. AllLayoutOpportunities(const NGBfcOffset & offset,const LayoutUnit available_inline_size)460 LayoutOpportunityVector AllLayoutOpportunities( 461 const NGBfcOffset& offset, 462 const LayoutUnit available_inline_size) const { 463 if (!exclusion_space_) { 464 NGBfcOffset end_offset( 465 offset.line_offset + available_inline_size.ClampNegativeToZero(), 466 LayoutUnit::Max()); 467 return LayoutOpportunityVector( 468 {NGLayoutOpportunity(NGBfcRect(offset, end_offset), nullptr)}); 469 } 470 return exclusion_space_->AllLayoutOpportunities(offset, 471 available_inline_size); 472 } 473 474 // Returns the clearance offset based on the provided {@code clear_type}. ClearanceOffset(EClear clear_type)475 LayoutUnit ClearanceOffset(EClear clear_type) const { 476 if (!exclusion_space_) 477 return LayoutUnit::Min(); 478 return exclusion_space_->ClearanceOffset(clear_type); 479 } 480 481 // Returns the block start offset of the last float added. LastFloatBlockStart()482 LayoutUnit LastFloatBlockStart() const { 483 if (!exclusion_space_) 484 return LayoutUnit::Min(); 485 return exclusion_space_->LastFloatBlockStart(); 486 } 487 IsEmpty()488 bool IsEmpty() const { 489 return !exclusion_space_ || exclusion_space_->IsEmpty(); 490 } 491 492 // See |NGExclusionSpaceInternal::PreInitialize|. PreInitialize(const NGExclusionSpace & other)493 void PreInitialize(const NGExclusionSpace& other) const { 494 // Don't pre-initialize if we've already got an exclusions vector. 495 if (exclusion_space_) 496 return; 497 498 // Don't pre-initialize if the other exclusion space didn't have an 499 // exclusions vector. 500 if (!other.exclusion_space_) 501 return; 502 503 exclusion_space_ = std::make_unique<NGExclusionSpaceInternal>(); 504 exclusion_space_->PreInitialize(*other.exclusion_space_); 505 } 506 507 // Shifts the |DerivedGeometry| data-structure to this exclusion space, and 508 // adds any new exclusions. MoveAndUpdateDerivedGeometry(const NGExclusionSpace & other)509 void MoveAndUpdateDerivedGeometry(const NGExclusionSpace& other) const { 510 if (!exclusion_space_ || !other.exclusion_space_) 511 return; 512 513 exclusion_space_->MoveAndUpdateDerivedGeometry(*other.exclusion_space_); 514 } 515 516 // Shifts the |DerivedGeometry| data-structure to this exclusion space. MoveDerivedGeometry(const NGExclusionSpace & other)517 void MoveDerivedGeometry(const NGExclusionSpace& other) const { 518 DCHECK(*this == other); 519 if (!exclusion_space_ || !other.exclusion_space_) 520 return; 521 522 exclusion_space_->MoveDerivedGeometry(*other.exclusion_space_); 523 } 524 525 // This produces a new exclusion space for a |NGLayoutResult| which is being 526 // re-used for caching purposes. 527 // 528 // It takes: 529 // - |old_output| The exclusion space associated with the cached layout 530 // result (the output of layout). 531 // - |old_input| The exclusion space which produced the cached layout result 532 // (the input into layout). 533 // - |new_input| The exclusion space which is being used to produce a new 534 // layout result (the new input into layout). 535 // - |offset_delta| the amount that the layout result was moved in BFC 536 // coordinate space. 537 // 538 // |old_output| should contain the *at least* same exclusions as |old_input| 539 // however may have added some more exclusions during its layout. 540 // 541 // This function takes those exclusions added by the cached layout-result 542 // (the difference between |old_output| and |old_input|), and adds them to 543 // |new_input|. It will additionally shift them by |offset_delta|. 544 // 545 // This produces the correct exclusion space "new_output" for the new reused 546 // layout result. MergeExclusionSpaces(const NGExclusionSpace & old_output,const NGExclusionSpace & old_input,const NGExclusionSpace & new_input,const NGBfcDelta & offset_delta)547 static NGExclusionSpace MergeExclusionSpaces( 548 const NGExclusionSpace& old_output, 549 const NGExclusionSpace& old_input, 550 const NGExclusionSpace& new_input, 551 const NGBfcDelta& offset_delta) { 552 // We start building the new exclusion space from the new input, this 553 // (should) have the derived geometry which will move to |new_output|. 554 NGExclusionSpace new_output = new_input; 555 556 // If we didn't have any floats previously, we don't need to add any new 557 // ones, just return the new output. 558 if (!old_output.exclusion_space_) 559 return new_output; 560 561 // If the layout didn't add any new exclusions, we can just return the new 562 // output. 563 if (old_input == old_output) 564 return new_output; 565 566 if (!new_output.exclusion_space_) { 567 new_output.exclusion_space_ = 568 std::make_unique<NGExclusionSpaceInternal>(); 569 } 570 571 new_output.exclusion_space_->MergeExclusionSpaces( 572 offset_delta, *old_output.exclusion_space_, 573 old_input.exclusion_space_.get()); 574 575 return new_output; 576 } 577 578 bool operator==(const NGExclusionSpace& other) const { 579 if (exclusion_space_ == other.exclusion_space_) 580 return true; 581 if (exclusion_space_ && other.exclusion_space_) 582 return *exclusion_space_ == *other.exclusion_space_; 583 return false; 584 } 585 bool operator!=(const NGExclusionSpace& other) const { 586 return !(*this == other); 587 } 588 589 #if DCHECK_IS_ON() CheckSameForSimplifiedLayout(const NGExclusionSpace & other)590 void CheckSameForSimplifiedLayout(const NGExclusionSpace& other) const { 591 DCHECK_EQ((bool)exclusion_space_, (bool)other.exclusion_space_); 592 if (exclusion_space_) 593 exclusion_space_->CheckSameForSimplifiedLayout(*other.exclusion_space_); 594 } 595 #endif 596 597 private: 598 mutable std::unique_ptr<NGExclusionSpaceInternal> exclusion_space_; 599 }; 600 601 } // namespace blink 602 603 WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS( 604 blink::NGExclusionSpaceInternal::NGShelfEdge) 605 606 #endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_EXCLUSION_SPACE_H_ 607