OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "core/layout/ng/ng_layout_opportunity_iterator.h" |
| 6 |
| 7 #include "core/layout/ng/ng_physical_constraint_space.h" |
| 8 #include "core/layout/ng/ng_units.h" |
| 9 #include "wtf/NonCopyingSort.h" |
| 10 |
| 11 namespace blink { |
| 12 |
| 13 static inline bool AscendingTopCompare(const NGExclusion& a, |
| 14 const NGExclusion& b) { |
| 15 return a.Top() > b.Top(); |
| 16 } |
| 17 |
| 18 NGLayoutOpportunityIterator::NGLayoutOpportunityIterator( |
| 19 NGConstraintSpace* space, |
| 20 unsigned clear, |
| 21 bool for_inline_or_bfc) |
| 22 : constraint_space_(space), |
| 23 clear_(clear), |
| 24 for_inline_or_bfc_(for_inline_or_bfc), |
| 25 current_exclusion_idx_(0) { |
| 26 for (const auto& item : constraint_space_->PhysicalSpace()->Exclusions()) |
| 27 filtered_exclusions_.append(item); |
| 28 |
| 29 nonCopyingSort(filtered_exclusions_.begin(), filtered_exclusions_.end(), |
| 30 AscendingTopCompare); |
| 31 |
| 32 // TODO(eae): Set based on offset. |
| 33 LayoutUnit left; |
| 34 LayoutUnit top; |
| 35 |
| 36 unsigned i = filtered_exclusions_.size(); |
| 37 while (i--) { |
| 38 const NGExclusion& exclusion = filtered_exclusions_[i]; |
| 39 |
| 40 // Remove items above OR to the left of the start offset as they have no |
| 41 // effect on layout opportunities within this view. |
| 42 if (exclusion.Right() <= left || exclusion.Bottom() <= top) { |
| 43 filtered_exclusions_.remove(i); |
| 44 continue; |
| 45 } |
| 46 |
| 47 // Remove items below AND to the right of the current exclusions as they're |
| 48 // occluded and won't affect the layout opportunities. |
| 49 for (unsigned j = filtered_exclusions_.size() - 1; j > i; j--) { |
| 50 const NGExclusion& item = filtered_exclusions_[j]; |
| 51 if (item.Top() > exclusion.Top() && item.Left() > exclusion.Left()) |
| 52 filtered_exclusions_.remove(j); |
| 53 } |
| 54 } |
| 55 } |
| 56 |
| 57 NGConstraintSpace* NGLayoutOpportunityIterator::Next() { |
| 58 if (current_opportunities_.isEmpty() && |
| 59 current_exclusion_idx_ < filtered_exclusions_.size()) { |
| 60 computeForExclusion(current_exclusion_idx_); |
| 61 current_exclusion_idx_++; |
| 62 } |
| 63 |
| 64 if (!current_opportunities_.isEmpty()) { |
| 65 NGConstraintSpace* opportunity = current_opportunities_.last(); |
| 66 current_opportunities_.removeLast(); |
| 67 return opportunity; |
| 68 } |
| 69 |
| 70 if (filtered_exclusions_.isEmpty() && current_exclusion_idx_ == 0) { |
| 71 current_exclusion_idx_++; |
| 72 return new NGConstraintSpace(constraint_space_->WritingMode(), |
| 73 constraint_space_->PhysicalSpace()); |
| 74 } |
| 75 |
| 76 return nullptr; |
| 77 } |
| 78 |
| 79 static inline bool DescendingWidthCompare(const NGConstraintSpace* a, |
| 80 const NGConstraintSpace* b) { |
| 81 return a->Size().inline_size > b->Size().inline_size; |
| 82 } |
| 83 |
| 84 void NGLayoutOpportunityIterator::computeForExclusion(unsigned index) { |
| 85 current_opportunities_.clear(); |
| 86 |
| 87 // TODO(eae): Set based on index. |
| 88 LayoutUnit left; |
| 89 LayoutUnit top; |
| 90 |
| 91 // TODO(eae): Writing modes. |
| 92 LayoutUnit right = constraint_space_->Size().inline_size; |
| 93 LayoutUnit bottom = constraint_space_->Size().block_size; |
| 94 |
| 95 // TODO(eae): Filter based on clear_ and for_inline_or_bfc_. Return early for |
| 96 // now to make it clear neither are supported yet. |
| 97 if (clear_ != NGClearNone || !for_inline_or_bfc_) |
| 98 return; |
| 99 |
| 100 // Compute opportunity for the full width from the start position to the right |
| 101 // edge of the NGConstraintSpace. |
| 102 LayoutUnit opportunityHeight = heightForOpportunity(left, top, right, bottom); |
| 103 if (opportunityHeight && right > left) |
| 104 addLayoutOpportunity(left, top, right - left, opportunityHeight); |
| 105 |
| 106 // Compute the maximum available height between the current position and the |
| 107 // left edge of each exclusion. The distance between the current horizontal |
| 108 // position and the left edge of the exclusion determines the width of the |
| 109 // opportunity. |
| 110 for (const NGExclusion& exclusion : filtered_exclusions_) { |
| 111 opportunityHeight = |
| 112 heightForOpportunity(left, top, exclusion.Left(), bottom); |
| 113 if (opportunityHeight && exclusion.Left() > left) |
| 114 addLayoutOpportunity(left, top, exclusion.Left() - left, |
| 115 opportunityHeight); |
| 116 } |
| 117 |
| 118 nonCopyingSort(current_opportunities_.begin(), current_opportunities_.end(), |
| 119 DescendingWidthCompare); |
| 120 } |
| 121 |
| 122 // For the given 2D range (opportunity), this will return a height which makes |
| 123 // it bounded by the highest exclusion in the filtered exclusion list within the |
| 124 // range. Returns 0-height for an invalid opportunity (which has zero area). |
| 125 LayoutUnit NGLayoutOpportunityIterator::heightForOpportunity( |
| 126 LayoutUnit left, |
| 127 LayoutUnit top, |
| 128 LayoutUnit right, |
| 129 LayoutUnit bottom) { |
| 130 LayoutUnit lowestBottom = bottom; |
| 131 for (const NGExclusion& exclusion : filtered_exclusions_) { |
| 132 if (exclusion.Left() < right && exclusion.Right() > left && |
| 133 exclusion.Bottom() > top && exclusion.Top() <= lowestBottom) |
| 134 lowestBottom = exclusion.Top(); |
| 135 } |
| 136 return std::max(lowestBottom - top, LayoutUnit()); |
| 137 } |
| 138 |
| 139 void NGLayoutOpportunityIterator::addLayoutOpportunity(LayoutUnit left, |
| 140 LayoutUnit top, |
| 141 LayoutUnit right, |
| 142 LayoutUnit bottom) { |
| 143 current_opportunities_.append( |
| 144 new NGConstraintSpace(*constraint_space_, NGLogicalOffset(left, top), |
| 145 NGLogicalSize(right - left, bottom - top))); |
| 146 } |
| 147 |
| 148 } // namespace blink |
OLD | NEW |