OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "core/layout/ng/ng_constraint_space.h" | 5 #include "core/layout/ng/ng_constraint_space.h" |
6 | 6 |
7 #include "core/layout/ng/ng_units.h" | 7 #include "core/layout/ng/ng_units.h" |
| 8 #include "wtf/NonCopyingSort.h" |
| 9 #include <climits> |
8 | 10 |
9 namespace blink { | 11 namespace blink { |
10 | 12 |
11 // TODO: This should set the size of the NGPhysicalConstraintSpace. Or we could | 13 // TODO: This should set the size of the NGPhysicalConstraintSpace. Or we could |
12 // remove it requiring that a NGConstraintSpace is created from a | 14 // remove it requiring that a NGConstraintSpace is created from a |
13 // NGPhysicalConstraintSpace. | 15 // NGPhysicalConstraintSpace. |
14 NGConstraintSpace::NGConstraintSpace(NGWritingMode writing_mode, | 16 NGConstraintSpace::NGConstraintSpace(NGWritingMode writing_mode, |
15 NGLogicalSize container_size) | 17 NGLogicalSize container_size) |
16 : physical_space_(new NGPhysicalConstraintSpace( | 18 : physical_space_(new NGPhysicalConstraintSpace( |
17 container_size.ConvertToPhysical(writing_mode))), | 19 container_size.ConvertToPhysical(writing_mode))), |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
107 return static_cast<NGFragmentationType>( | 109 return static_cast<NGFragmentationType>( |
108 writing_mode_ == HorizontalTopBottom | 110 writing_mode_ == HorizontalTopBottom |
109 ? physical_space_->height_direction_fragmentation_type_ | 111 ? physical_space_->height_direction_fragmentation_type_ |
110 : physical_space_->width_direction_fragmentation_type_); | 112 : physical_space_->width_direction_fragmentation_type_); |
111 } | 113 } |
112 | 114 |
113 void NGConstraintSpace::Subtract(const NGFragment*) { | 115 void NGConstraintSpace::Subtract(const NGFragment*) { |
114 // TODO(layout-ng): Implement. | 116 // TODO(layout-ng): Implement. |
115 } | 117 } |
116 | 118 |
117 NGLayoutOpportunityIterator NGConstraintSpace::LayoutOpportunities( | 119 NGLayoutOpportunityIterator* NGConstraintSpace::LayoutOpportunities( |
118 unsigned clear, | 120 unsigned clear, |
119 bool for_inline_or_bfc) { | 121 bool for_inline_or_bfc) { |
120 NGLayoutOpportunityIterator iterator(this, clear, for_inline_or_bfc); | 122 NGLayoutOpportunityIterator* iterator = |
| 123 new NGLayoutOpportunityIterator(this, clear, for_inline_or_bfc); |
121 return iterator; | 124 return iterator; |
122 } | 125 } |
123 | 126 |
124 void NGConstraintSpace::SetOverflowTriggersScrollbar(bool inline_triggers, | 127 void NGConstraintSpace::SetOverflowTriggersScrollbar(bool inline_triggers, |
125 bool block_triggers) { | 128 bool block_triggers) { |
126 if (writing_mode_ == HorizontalTopBottom) { | 129 if (writing_mode_ == HorizontalTopBottom) { |
127 physical_space_->width_direction_triggers_scrollbar_ = inline_triggers; | 130 physical_space_->width_direction_triggers_scrollbar_ = inline_triggers; |
128 physical_space_->height_direction_triggers_scrollbar_ = block_triggers; | 131 physical_space_->height_direction_triggers_scrollbar_ = block_triggers; |
129 } else { | 132 } else { |
130 physical_space_->width_direction_triggers_scrollbar_ = block_triggers; | 133 physical_space_->width_direction_triggers_scrollbar_ = block_triggers; |
(...skipping 24 matching lines...) Expand all Loading... |
155 physical_space_->width_direction_triggers_scrollbar_ = type; | 158 physical_space_->width_direction_triggers_scrollbar_ = type; |
156 } | 159 } |
157 } | 160 } |
158 | 161 |
159 String NGConstraintSpace::toString() const { | 162 String NGConstraintSpace::toString() const { |
160 return String::format("Size: %s, %s", | 163 return String::format("Size: %s, %s", |
161 size_.inline_size.toString().ascii().data(), | 164 size_.inline_size.toString().ascii().data(), |
162 size_.block_size.toString().ascii().data()); | 165 size_.block_size.toString().ascii().data()); |
163 } | 166 } |
164 | 167 |
| 168 static inline bool AscendingTopCompare(const NGExclusion& a, |
| 169 const NGExclusion& b) { |
| 170 return a.Top() > b.Top(); |
| 171 } |
| 172 |
| 173 NGLayoutOpportunityIterator::NGLayoutOpportunityIterator( |
| 174 NGConstraintSpace* space, |
| 175 unsigned clear, |
| 176 bool for_inline_or_bfc) |
| 177 : constraint_space_(space), |
| 178 clear_(clear), |
| 179 for_inline_or_bfc_(for_inline_or_bfc), |
| 180 current_exclusion_idx_(0) { |
| 181 for (const auto& item : constraint_space_->PhysicalSpace()->Exclusions()) |
| 182 filtered_exclusions_.append(item); |
| 183 |
| 184 nonCopyingSort(filtered_exclusions_.begin(), filtered_exclusions_.end(), |
| 185 AscendingTopCompare); |
| 186 |
| 187 // TODO(eae): Set based on offset. |
| 188 LayoutUnit left; |
| 189 LayoutUnit top; |
| 190 |
| 191 unsigned i = filtered_exclusions_.size(); |
| 192 while (i--) { |
| 193 const NGExclusion& exclusion = filtered_exclusions_[i]; |
| 194 |
| 195 // Remove items above OR to the left of the start offset as they have no |
| 196 // effect on layout opportunities within this view. |
| 197 if (exclusion.Right() <= left || exclusion.Bottom() <= top) { |
| 198 filtered_exclusions_.remove(i); |
| 199 continue; |
| 200 } |
| 201 |
| 202 // Remove items below AND to the right of the current exclusions as they're |
| 203 // occluded and won't affect the layout opportunities. |
| 204 for (unsigned j = filtered_exclusions_.size() - 1; j > i; j--) { |
| 205 const NGExclusion& item = filtered_exclusions_[j]; |
| 206 if (item.Top() > exclusion.Top() && item.Left() > exclusion.Left()) |
| 207 filtered_exclusions_.remove(j); |
| 208 } |
| 209 } |
| 210 } |
| 211 |
165 NGConstraintSpace* NGLayoutOpportunityIterator::Next() { | 212 NGConstraintSpace* NGLayoutOpportunityIterator::Next() { |
166 auto* exclusions = constraint_space_->PhysicalSpace()->Exclusions(); | 213 if (current_opportunities_.isEmpty() && |
167 if (!exclusions->head()) | 214 current_exclusion_idx_ < filtered_exclusions_.size()) { |
| 215 computeForExclusion(current_exclusion_idx_); |
| 216 current_exclusion_idx_++; |
| 217 } |
| 218 |
| 219 if (!current_opportunities_.isEmpty()) { |
| 220 NGConstraintSpace* opportunity = current_opportunities_.last(); |
| 221 current_opportunities_.removeLast(); |
| 222 return opportunity; |
| 223 } |
| 224 |
| 225 if (filtered_exclusions_.isEmpty() && current_exclusion_idx_ == 0) { |
| 226 current_exclusion_idx_++; |
168 return new NGConstraintSpace(constraint_space_->WritingMode(), | 227 return new NGConstraintSpace(constraint_space_->WritingMode(), |
169 constraint_space_->PhysicalSpace()); | 228 constraint_space_->PhysicalSpace()); |
| 229 } |
| 230 |
170 return nullptr; | 231 return nullptr; |
171 } | 232 } |
172 | 233 |
| 234 static inline bool DescendingWidthCompare(const NGConstraintSpace* a, |
| 235 const NGConstraintSpace* b) { |
| 236 return a->Size().inline_size > b->Size().inline_size; |
| 237 } |
| 238 |
| 239 void NGLayoutOpportunityIterator::computeForExclusion(unsigned index) { |
| 240 current_opportunities_.clear(); |
| 241 |
| 242 // TODO(eae): Set based on index. |
| 243 LayoutUnit left; |
| 244 LayoutUnit top; |
| 245 |
| 246 // TODO(eae): Writing modes. |
| 247 LayoutUnit right = constraint_space_->Size().inline_size; |
| 248 LayoutUnit bottom = constraint_space_->Size().block_size; |
| 249 |
| 250 // TODO(eae): Filter based on clear_ and for_inline_or_bfc_. Return early for |
| 251 // now to make it clear neither are supported yet. |
| 252 if (clear_ != NGClearNone || !for_inline_or_bfc_) |
| 253 return; |
| 254 |
| 255 // Compute opportunity for the full width from the start position to the right |
| 256 // edge of the NGConstraintSpace. |
| 257 LayoutUnit opportunityHeight = heightForOpportunity(left, top, right, bottom); |
| 258 if (opportunityHeight && right > left) |
| 259 addLayoutOpportunity(left, top, right - left, opportunityHeight); |
| 260 |
| 261 // Compute the maximum available height between the current position and the |
| 262 // left edge of each exclusion. The distance between the current horizontal |
| 263 // position and the left edge of the exclusion determines the width of the |
| 264 // opportunity. |
| 265 for (const NGExclusion& exclusion : filtered_exclusions_) { |
| 266 opportunityHeight = |
| 267 heightForOpportunity(left, top, exclusion.Left(), bottom); |
| 268 if (opportunityHeight && exclusion.Left() > left) |
| 269 addLayoutOpportunity(left, top, exclusion.Left() - left, |
| 270 opportunityHeight); |
| 271 } |
| 272 |
| 273 nonCopyingSort(current_opportunities_.begin(), current_opportunities_.end(), |
| 274 DescendingWidthCompare); |
| 275 } |
| 276 |
| 277 // For the given 2D range (opportunity), this will return a height which makes |
| 278 // it bounded by the highest exclusion in the filtered exclusion list within the |
| 279 // range. Returns 0-height for an invalid opportunity (which has zero area). |
| 280 LayoutUnit NGLayoutOpportunityIterator::heightForOpportunity( |
| 281 LayoutUnit left, |
| 282 LayoutUnit top, |
| 283 LayoutUnit right, |
| 284 LayoutUnit bottom) { |
| 285 LayoutUnit lowestBottom = bottom; |
| 286 for (const NGExclusion& exclusion : filtered_exclusions_) { |
| 287 if (exclusion.Left() < right && exclusion.Right() > left && |
| 288 exclusion.Bottom() > top && exclusion.Top() <= lowestBottom) |
| 289 lowestBottom = exclusion.Top(); |
| 290 } |
| 291 return std::max(lowestBottom - top, LayoutUnit()); |
| 292 } |
| 293 |
| 294 void NGLayoutOpportunityIterator::addLayoutOpportunity(LayoutUnit left, |
| 295 LayoutUnit top, |
| 296 LayoutUnit right, |
| 297 LayoutUnit bottom) { |
| 298 current_opportunities_.append( |
| 299 new NGConstraintSpace(*constraint_space_, NGLogicalOffset(left, top), |
| 300 NGLogicalSize(right - left, bottom - top))); |
| 301 } |
| 302 |
173 } // namespace blink | 303 } // namespace blink |
OLD | NEW |