1/*
2 * Copyright (C) 2018 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
29
30#include "LayoutUnits.h"
31#include "RenderStyleConstants.h"
32#include <wtf/IsoMalloc.h>
33
34namespace WebCore {
35
36class RenderStyle;
37
38namespace Layout {
39class BlockFormattingContext;
40class FloatAvoider;
41class FloatBox;
42class FormattingContext;
43class FloatingContext;
44class InlineFormattingContext;
45class LayoutState;
46}
47
48namespace Display {
49
50class Box {
51 WTF_MAKE_ISO_ALLOCATED(Box);
52public:
53 friend class Layout::BlockFormattingContext;
54 friend class Layout::FloatAvoider;
55 friend class Layout::FloatBox;
56 friend class Layout::FormattingContext;
57 friend class Layout::FloatingContext;
58 friend class Layout::InlineFormattingContext;
59 friend class Layout::LayoutState;
60
61 Box(const RenderStyle&);
62 Box(const Box&);
63
64 class Rect {
65 public:
66 Rect() = default;
67 Rect(LayoutUnit top, LayoutUnit left, LayoutUnit width, LayoutUnit height);
68
69 LayoutUnit top() const;
70 LayoutUnit left() const;
71 LayoutPoint topLeft() const;
72
73 LayoutUnit bottom() const;
74 LayoutUnit right() const;
75 LayoutPoint bottomRight() const;
76
77 LayoutUnit width() const;
78 LayoutUnit height() const;
79 LayoutSize size() const;
80
81 void setTop(LayoutUnit);
82 void setLeft(LayoutUnit);
83 void setTopLeft(const LayoutPoint&);
84 void setWidth(LayoutUnit);
85 void setHeight(LayoutUnit);
86 void setSize(const LayoutSize&);
87
88 void shiftLeftTo(LayoutUnit);
89 void shiftRightTo(LayoutUnit);
90 void shiftTopTo(LayoutUnit);
91 void shiftBottomTo(LayoutUnit);
92
93 void moveHorizontally(LayoutUnit);
94 void moveVertically(LayoutUnit);
95
96 void expand(LayoutUnit, LayoutUnit);
97 bool intersects(const Rect& rect) const { return m_rect.intersects(rect); }
98
99 Rect clone() const;
100 operator LayoutRect() const;
101
102 private:
103#if !ASSERT_DISABLED
104 void invalidateTop() { m_hasValidTop = false; }
105 void invalidateLeft() { m_hasValidLeft = false; }
106 void invalidateWidth() { m_hasValidWidth = false; }
107 void invalidateHeight() { m_hasValidHeight = false; }
108 void invalidatePosition();
109
110 bool hasValidPosition() const { return m_hasValidTop && m_hasValidLeft; }
111 bool hasValidSize() const { return m_hasValidWidth && m_hasValidHeight; }
112 bool hasValidGeometry() const { return hasValidPosition() && hasValidSize(); }
113
114 void setHasValidPosition();
115 void setHasValidSize();
116
117 bool m_hasValidTop { false };
118 bool m_hasValidLeft { false };
119 bool m_hasValidWidth { false };
120 bool m_hasValidHeight { false };
121#endif
122 LayoutRect m_rect;
123 };
124
125 ~Box();
126
127 LayoutUnit top() const;
128 LayoutUnit left() const;
129 LayoutUnit bottom() const { return top() + height(); }
130 LayoutUnit right() const { return left() + width(); }
131
132 LayoutPoint topLeft() const;
133 LayoutPoint bottomRight() const { return { right(), bottom() }; }
134
135 LayoutSize size() const { return { width(), height() }; }
136 LayoutUnit width() const { return borderLeft() + paddingBoxWidth() + borderRight(); }
137 LayoutUnit height() const { return borderTop() + paddingBoxHeight() + borderBottom(); }
138 Rect rect() const { return { top(), left(), width(), height() }; }
139 Rect rectWithMargin() const;
140
141 Layout::UsedVerticalMargin verticalMargin() const;
142 LayoutUnit marginBefore() const;
143 LayoutUnit marginStart() const;
144 LayoutUnit marginAfter() const;
145 LayoutUnit marginEnd() const;
146 bool hasCollapsedThroughMargin() const { return m_verticalMargin.isCollapsedThrough(); }
147 bool hasClearance() const { return m_hasClearance; }
148
149 LayoutUnit nonCollapsedMarginBefore() const;
150 LayoutUnit nonCollapsedMarginAfter() const;
151 Optional<LayoutUnit> computedMarginStart() const;
152 Optional<LayoutUnit> computedMarginEnd() const;
153
154 LayoutUnit borderTop() const;
155 LayoutUnit borderLeft() const;
156 LayoutUnit borderBottom() const;
157 LayoutUnit borderRight() const;
158 LayoutUnit verticalBorder() const { return borderTop() + borderBottom(); }
159 LayoutUnit horizontalBorder() const { return borderLeft() + borderRight(); }
160
161 Optional<LayoutUnit> paddingTop() const;
162 Optional<LayoutUnit> paddingLeft() const;
163 Optional<LayoutUnit> paddingBottom() const;
164 Optional<LayoutUnit> paddingRight() const;
165 Optional<LayoutUnit> verticalPadding() const;
166 Optional<LayoutUnit> horizontalPadding() const;
167
168 LayoutUnit contentBoxTop() const { return paddingBoxTop() + paddingTop().valueOr(0); }
169 LayoutUnit contentBoxLeft() const { return paddingBoxLeft() + paddingLeft().valueOr(0); }
170 LayoutUnit contentBoxBottom() const { return contentBoxTop() + contentBoxHeight(); }
171 LayoutUnit contentBoxRight() const { return contentBoxLeft() + contentBoxWidth(); }
172 LayoutUnit contentBoxHeight() const;
173 LayoutUnit contentBoxWidth() const;
174
175 LayoutUnit paddingBoxTop() const { return borderTop(); }
176 LayoutUnit paddingBoxLeft() const { return borderLeft(); }
177 LayoutUnit paddingBoxBottom() const { return paddingBoxTop() + paddingBoxHeight(); }
178 LayoutUnit paddingBoxRight() const { return paddingBoxLeft() + paddingBoxWidth(); }
179 LayoutUnit paddingBoxHeight() const { return paddingTop().valueOr(0) + contentBoxHeight() + paddingBottom().valueOr(0); }
180 LayoutUnit paddingBoxWidth() const { return paddingLeft().valueOr(0) + contentBoxWidth() + paddingRight().valueOr(0); }
181
182 Rect marginBox() const;
183 Rect nonCollapsedMarginBox() const;
184
185 Rect borderBox() const;
186 Rect paddingBox() const;
187 Rect contentBox() const;
188
189#if !ASSERT_DISABLED
190 void setHasEstimatedMarginBefore() { m_hasEstimatedMarginBefore = true; }
191#endif
192
193private:
194 struct Style {
195 Style(const RenderStyle&);
196
197 BoxSizing boxSizing { BoxSizing::ContentBox };
198 };
199
200 void setTopLeft(const LayoutPoint&);
201 void setTop(LayoutUnit);
202 void setLeft(LayoutUnit);
203 void moveHorizontally(LayoutUnit offset) { m_topLeft.move(offset, { }); }
204 void moveVertically(LayoutUnit offset) { m_topLeft.move({ }, offset); }
205
206 void setContentBoxHeight(LayoutUnit);
207 void setContentBoxWidth(LayoutUnit);
208
209 void setHorizontalMargin(Layout::UsedHorizontalMargin);
210 void setVerticalMargin(Layout::UsedVerticalMargin);
211 void setHorizontalComputedMargin(Layout::ComputedHorizontalMargin);
212 void setHasClearance() { m_hasClearance = true; }
213
214 void setBorder(Layout::Edges);
215 void setPadding(Optional<Layout::Edges>);
216
217#if !ASSERT_DISABLED
218 void invalidateMargin();
219 void invalidateBorder() { m_hasValidBorder = false; }
220 void invalidatePadding() { m_hasValidPadding = false; }
221 void invalidateEstimatedMarginBefore() { m_hasEstimatedMarginBefore = false; }
222
223 void setHasValidTop() { m_hasValidTop = true; }
224 void setHasValidLeft() { m_hasValidLeft = true; }
225 void setHasValidVerticalMargin() { m_hasValidVerticalMargin = true; }
226 void setHasValidVerticalNonCollapsedMargin() { m_hasValidVerticalNonCollapsedMargin = true; }
227 void setHasValidHorizontalComputedMargin() { m_hasValidHorizontalComputedMargin = true; }
228 void setHasValidHorizontalMargin() { m_hasValidHorizontalMargin = true; }
229
230 void setHasValidBorder() { m_hasValidBorder = true; }
231 void setHasValidPadding() { m_hasValidPadding = true; }
232
233 void setHasValidContentHeight() { m_hasValidContentHeight = true; }
234 void setHasValidContentWidth() { m_hasValidContentWidth = true; }
235#endif
236
237 const Style m_style;
238
239 LayoutPoint m_topLeft;
240 LayoutUnit m_contentWidth;
241 LayoutUnit m_contentHeight;
242
243 Layout::UsedHorizontalMargin m_horizontalMargin;
244 Layout::UsedVerticalMargin m_verticalMargin;
245 Layout::ComputedHorizontalMargin m_horizontalComputedMargin;
246 bool m_hasClearance { false };
247
248 Layout::Edges m_border;
249 Optional<Layout::Edges> m_padding;
250
251#if !ASSERT_DISABLED
252 bool m_hasValidTop { false };
253 bool m_hasValidLeft { false };
254 bool m_hasValidHorizontalMargin { false };
255 bool m_hasValidVerticalMargin { false };
256 bool m_hasValidVerticalNonCollapsedMargin { false };
257 bool m_hasValidHorizontalComputedMargin { false };
258 bool m_hasValidBorder { false };
259 bool m_hasValidPadding { false };
260 bool m_hasValidContentHeight { false };
261 bool m_hasValidContentWidth { false };
262 bool m_hasEstimatedMarginBefore { false };
263#endif
264};
265
266#if !ASSERT_DISABLED
267inline void Box::Rect::invalidatePosition()
268{
269 invalidateTop();
270 invalidateLeft();
271}
272
273inline void Box::Rect::setHasValidPosition()
274{
275 m_hasValidTop = true;
276 m_hasValidLeft = true;
277}
278
279inline void Box::Rect::setHasValidSize()
280{
281 m_hasValidWidth = true;
282 m_hasValidHeight = true;
283}
284
285inline void Box::invalidateMargin()
286{
287 m_hasValidHorizontalMargin = false;
288 m_hasValidVerticalMargin = false;
289}
290#endif
291
292inline LayoutUnit Box::Rect::top() const
293{
294 ASSERT(m_hasValidTop);
295 return m_rect.y();
296}
297
298inline LayoutUnit Box::Rect::left() const
299{
300 ASSERT(m_hasValidLeft);
301 return m_rect.x();
302}
303
304inline LayoutUnit Box::Rect::bottom() const
305{
306 ASSERT(m_hasValidTop && m_hasValidHeight);
307 return m_rect.maxY();
308}
309
310inline LayoutUnit Box::Rect::right() const
311{
312 ASSERT(m_hasValidLeft && m_hasValidWidth);
313 return m_rect.maxX();
314}
315
316inline LayoutPoint Box::Rect::topLeft() const
317{
318 ASSERT(hasValidPosition());
319 return m_rect.minXMinYCorner();
320}
321
322inline LayoutPoint Box::Rect::bottomRight() const
323{
324 ASSERT(hasValidGeometry());
325 return m_rect.maxXMaxYCorner();
326}
327
328inline LayoutSize Box::Rect::size() const
329{
330 ASSERT(hasValidSize());
331 return m_rect.size();
332}
333
334inline LayoutUnit Box::Rect::width() const
335{
336 ASSERT(m_hasValidWidth);
337 return m_rect.width();
338}
339
340inline LayoutUnit Box::Rect::height() const
341{
342 ASSERT(m_hasValidHeight);
343 return m_rect.height();
344}
345
346inline void Box::Rect::setTopLeft(const LayoutPoint& topLeft)
347{
348#if !ASSERT_DISABLED
349 setHasValidPosition();
350#endif
351 m_rect.setLocation(topLeft);
352}
353
354inline void Box::Rect::setTop(LayoutUnit top)
355{
356#if !ASSERT_DISABLED
357 m_hasValidTop = true;
358#endif
359 m_rect.setY(top);
360}
361
362inline void Box::Rect::setLeft(LayoutUnit left)
363{
364#if !ASSERT_DISABLED
365 m_hasValidLeft = true;
366#endif
367 m_rect.setX(left);
368}
369
370inline void Box::Rect::setWidth(LayoutUnit width)
371{
372#if !ASSERT_DISABLED
373 m_hasValidWidth = true;
374#endif
375 m_rect.setWidth(width);
376}
377
378inline void Box::Rect::setHeight(LayoutUnit height)
379{
380#if !ASSERT_DISABLED
381 m_hasValidHeight = true;
382#endif
383 m_rect.setHeight(height);
384}
385
386inline void Box::Rect::setSize(const LayoutSize& size)
387{
388#if !ASSERT_DISABLED
389 setHasValidSize();
390#endif
391 m_rect.setSize(size);
392}
393
394inline void Box::Rect::shiftLeftTo(LayoutUnit left)
395{
396 ASSERT(m_hasValidLeft);
397 m_rect.shiftXEdgeTo(left);
398}
399
400inline void Box::Rect::shiftRightTo(LayoutUnit right)
401{
402 ASSERT(m_hasValidLeft && m_hasValidWidth);
403 m_rect.shiftMaxXEdgeTo(right);
404}
405
406inline void Box::Rect::shiftTopTo(LayoutUnit top)
407{
408 ASSERT(m_hasValidTop);
409 m_rect.shiftYEdgeTo(top);
410}
411
412inline void Box::Rect::shiftBottomTo(LayoutUnit bottom)
413{
414 ASSERT(m_hasValidTop && m_hasValidHeight);
415 m_rect.shiftMaxYEdgeTo(bottom);
416}
417
418inline void Box::Rect::moveHorizontally(LayoutUnit offset)
419{
420 ASSERT(m_hasValidLeft);
421 m_rect.move(offset, { });
422}
423
424inline void Box::Rect::moveVertically(LayoutUnit offset)
425{
426 ASSERT(m_hasValidTop);
427 m_rect.move({ }, offset);
428}
429
430inline void Box::Rect::expand(LayoutUnit width, LayoutUnit height)
431{
432 ASSERT(hasValidGeometry());
433 m_rect.expand(width, height);
434}
435
436inline Box::Rect Box::Rect::clone() const
437{
438 Rect rect;
439#if !ASSERT_DISABLED
440 rect.m_hasValidTop = m_hasValidTop;
441 rect.m_hasValidLeft = m_hasValidLeft;
442 rect.m_hasValidWidth = m_hasValidWidth;
443 rect.m_hasValidHeight = m_hasValidHeight;
444#endif
445 rect.m_rect = m_rect;
446 return rect;
447}
448
449inline Box::Rect::operator LayoutRect() const
450{
451 ASSERT(hasValidGeometry());
452 return m_rect;
453}
454
455inline LayoutUnit Box::top() const
456{
457 ASSERT(m_hasValidTop && (m_hasEstimatedMarginBefore || m_hasValidVerticalMargin));
458 return m_topLeft.y();
459}
460
461inline LayoutUnit Box::left() const
462{
463 ASSERT(m_hasValidLeft && m_hasValidHorizontalMargin);
464 return m_topLeft.x();
465}
466
467inline LayoutPoint Box::topLeft() const
468{
469 ASSERT(m_hasValidTop && (m_hasEstimatedMarginBefore || m_hasValidVerticalMargin));
470 ASSERT(m_hasValidLeft && m_hasValidHorizontalMargin);
471 return m_topLeft;
472}
473
474inline void Box::setTopLeft(const LayoutPoint& topLeft)
475{
476#if !ASSERT_DISABLED
477 setHasValidTop();
478 setHasValidLeft();
479#endif
480 m_topLeft = topLeft;
481}
482
483inline void Box::setTop(LayoutUnit top)
484{
485#if !ASSERT_DISABLED
486 setHasValidTop();
487#endif
488 m_topLeft.setY(top);
489}
490
491inline void Box::setLeft(LayoutUnit left)
492{
493#if !ASSERT_DISABLED
494 setHasValidLeft();
495#endif
496 m_topLeft.setX(left);
497}
498
499inline void Box::setContentBoxHeight(LayoutUnit height)
500{
501#if !ASSERT_DISABLED
502 setHasValidContentHeight();
503#endif
504 m_contentHeight = height;
505}
506
507inline void Box::setContentBoxWidth(LayoutUnit width)
508{
509#if !ASSERT_DISABLED
510 setHasValidContentWidth();
511#endif
512 m_contentWidth = width;
513}
514
515inline LayoutUnit Box::contentBoxHeight() const
516{
517 ASSERT(m_hasValidContentHeight);
518 return m_contentHeight;
519}
520
521inline LayoutUnit Box::contentBoxWidth() const
522{
523 ASSERT(m_hasValidContentWidth);
524 return m_contentWidth;
525}
526
527inline void Box::setHorizontalMargin(Layout::UsedHorizontalMargin margin)
528{
529#if !ASSERT_DISABLED
530 setHasValidHorizontalMargin();
531#endif
532 m_horizontalMargin = margin;
533}
534
535inline void Box::setVerticalMargin(Layout::UsedVerticalMargin margin)
536{
537#if !ASSERT_DISABLED
538 setHasValidVerticalMargin();
539 setHasValidVerticalNonCollapsedMargin();
540 invalidateEstimatedMarginBefore();
541#endif
542 m_verticalMargin = margin;
543}
544
545inline void Box::setHorizontalComputedMargin(Layout::ComputedHorizontalMargin margin)
546{
547#if !ASSERT_DISABLED
548 setHasValidHorizontalComputedMargin();
549#endif
550 m_horizontalComputedMargin = margin;
551}
552
553inline void Box::setBorder(Layout::Edges border)
554{
555#if !ASSERT_DISABLED
556 setHasValidBorder();
557#endif
558 m_border = border;
559}
560
561inline void Box::setPadding(Optional<Layout::Edges> padding)
562{
563#if !ASSERT_DISABLED
564 setHasValidPadding();
565#endif
566 m_padding = padding;
567}
568
569inline Box::Rect Box::rectWithMargin() const
570{
571 auto marginAfter = this->marginAfter();
572 if (m_verticalMargin.collapsedValues().isCollapsedThrough)
573 marginAfter = 0;
574 return { top() - marginBefore(), left() - marginStart(), marginStart() + width() + marginEnd(), marginBefore() + height() + marginAfter };
575}
576
577inline Layout::UsedVerticalMargin Box::verticalMargin() const
578{
579 ASSERT(m_hasValidVerticalMargin);
580 return m_verticalMargin;
581}
582
583inline LayoutUnit Box::marginBefore() const
584{
585 ASSERT(m_hasValidVerticalMargin);
586 return m_verticalMargin.before();
587}
588
589inline LayoutUnit Box::marginStart() const
590{
591 ASSERT(m_hasValidHorizontalMargin);
592 return m_horizontalMargin.start;
593}
594
595inline LayoutUnit Box::marginAfter() const
596{
597 ASSERT(m_hasValidVerticalMargin);
598 return m_verticalMargin.after();
599}
600
601inline LayoutUnit Box::marginEnd() const
602{
603 ASSERT(m_hasValidHorizontalMargin);
604 return m_horizontalMargin.end;
605}
606
607inline LayoutUnit Box::nonCollapsedMarginBefore() const
608{
609 ASSERT(m_hasValidVerticalNonCollapsedMargin);
610 return m_verticalMargin.nonCollapsedValues().before;
611}
612
613inline LayoutUnit Box::nonCollapsedMarginAfter() const
614{
615 ASSERT(m_hasValidVerticalNonCollapsedMargin);
616 return m_verticalMargin.nonCollapsedValues().after;
617}
618
619inline Optional<LayoutUnit> Box::computedMarginStart() const
620{
621 ASSERT(m_hasValidHorizontalComputedMargin);
622 return m_horizontalComputedMargin.start;
623}
624
625inline Optional<LayoutUnit> Box::computedMarginEnd() const
626{
627 ASSERT(m_hasValidHorizontalComputedMargin);
628 return m_horizontalComputedMargin.end;
629}
630
631inline Optional<LayoutUnit> Box::paddingTop() const
632{
633 ASSERT(m_hasValidPadding);
634 if (!m_padding)
635 return { };
636 return m_padding->vertical.top;
637}
638
639inline Optional<LayoutUnit> Box::paddingLeft() const
640{
641 ASSERT(m_hasValidPadding);
642 if (!m_padding)
643 return { };
644 return m_padding->horizontal.left;
645}
646
647inline Optional<LayoutUnit> Box::paddingBottom() const
648{
649 ASSERT(m_hasValidPadding);
650 if (!m_padding)
651 return { };
652 return m_padding->vertical.bottom;
653}
654
655inline Optional<LayoutUnit> Box::paddingRight() const
656{
657 ASSERT(m_hasValidPadding);
658 if (!m_padding)
659 return { };
660 return m_padding->horizontal.right;
661}
662
663inline Optional<LayoutUnit> Box::verticalPadding() const
664{
665 auto paddingTop = this->paddingTop();
666 auto paddingBottom = this->paddingBottom();
667 if (!paddingTop && !paddingBottom)
668 return { };
669 return paddingTop.valueOr(0) + paddingBottom.valueOr(0);
670}
671
672inline Optional<LayoutUnit> Box::horizontalPadding() const
673{
674 auto paddingLeft = this->paddingLeft();
675 auto paddingRight = this->paddingRight();
676 if (!paddingLeft && !paddingRight)
677 return { };
678 return paddingLeft.valueOr(0) + paddingRight.valueOr(0);
679}
680
681inline LayoutUnit Box::borderTop() const
682{
683 ASSERT(m_hasValidBorder);
684 return m_border.vertical.top;
685}
686
687inline LayoutUnit Box::borderLeft() const
688{
689 ASSERT(m_hasValidBorder);
690 return m_border.horizontal.left;
691}
692
693inline LayoutUnit Box::borderBottom() const
694{
695 ASSERT(m_hasValidBorder);
696 return m_border.vertical.bottom;
697}
698
699inline LayoutUnit Box::borderRight() const
700{
701 ASSERT(m_hasValidBorder);
702 return m_border.horizontal.right;
703}
704
705}
706}
707#endif
708