3630ee2a70deddfaa590bf90fac47ee342b79b27
[WebKit-https.git] / Source / WebCore / layout / displaytree / DisplayBox.h
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
34 namespace WebCore {
35
36 class RenderStyle;
37
38 namespace Layout {
39 class BlockFormattingContext;
40 class FloatAvoider;
41 class FloatBox;
42 class FormattingContext;
43 class FloatingContext;
44 class LayoutContext;
45 }
46
47 namespace Display {
48
49 class Box {
50     WTF_MAKE_ISO_ALLOCATED(Box);
51 public:
52     friend class Layout::BlockFormattingContext;
53     friend class Layout::FloatAvoider;
54     friend class Layout::FloatBox;
55     friend class Layout::FormattingContext;
56     friend class Layout::FloatingContext;
57     friend class Layout::LayoutContext;
58
59     Box(const RenderStyle&);
60     Box(const Box&);
61
62     class Rect {
63     public:
64         Rect() = default;
65         Rect(LayoutUnit top, LayoutUnit left, LayoutUnit width, LayoutUnit height);
66         
67         LayoutUnit top() const;
68         LayoutUnit left() const;
69         LayoutPoint topLeft() const;
70
71         LayoutUnit bottom() const;
72         LayoutUnit right() const;        
73         LayoutPoint bottomRight() const;
74
75         LayoutUnit width() const;
76         LayoutUnit height() const;
77         LayoutSize size() const;
78
79         void setTop(LayoutUnit);
80         void setLeft(LayoutUnit);
81         void setTopLeft(const LayoutPoint&);
82         void setWidth(LayoutUnit);
83         void setHeight(LayoutUnit);
84         void setSize(const LayoutSize&);
85
86         void shiftLeftTo(LayoutUnit);
87         void shiftRightTo(LayoutUnit);
88         void shiftTopTo(LayoutUnit);
89         void shiftBottomTo(LayoutUnit);
90
91         void moveHorizontally(LayoutUnit);
92         void moveVertically(LayoutUnit);
93
94         void expand(LayoutUnit, LayoutUnit);
95         bool intersects(const Rect& rect) const { return m_rect.intersects(rect); }
96
97         Rect clone() const;
98         operator LayoutRect() const;
99
100     private:
101 #if !ASSERT_DISABLED
102         void invalidateTop() { m_hasValidTop = false; }
103         void invalidateLeft() { m_hasValidLeft = false; }
104         void invalidateWidth() { m_hasValidWidth = false; }
105         void invalidateHeight() { m_hasValidHeight = false; }
106         void invalidatePosition();
107
108         bool hasValidPosition() const { return m_hasValidTop && m_hasValidLeft; }
109         bool hasValidSize() const { return m_hasValidWidth && m_hasValidHeight; }
110         bool hasValidGeometry() const { return hasValidPosition() && hasValidSize(); }
111     
112         void setHasValidPosition();
113         void setHasValidSize();
114
115         bool m_hasValidTop { false };
116         bool m_hasValidLeft { false };
117         bool m_hasValidWidth { false };
118         bool m_hasValidHeight { false };
119 #endif
120         LayoutRect m_rect;
121     };
122
123     ~Box();
124
125     LayoutUnit top() const;
126     LayoutUnit left() const;
127     LayoutUnit bottom() const { return top() + height(); }
128     LayoutUnit right() const { return left() + width(); }
129
130     LayoutPoint topLeft() const;
131     LayoutPoint bottomRight() const { return { right(), bottom() }; }
132
133     LayoutSize size() const { return { width(), height() }; }
134     LayoutUnit width() const { return borderLeft() + paddingLeft().value_or(0) + contentBoxWidth() + paddingRight().value_or(0) + borderRight(); }
135     LayoutUnit height() const { return borderTop() + paddingTop().value_or(0) + contentBoxHeight() + paddingBottom().value_or(0) + borderBottom(); }
136     Rect rect() const { return { top(), left(), width(), height() }; }
137     Rect rectWithMargin() const { return { top() - marginTop(), left() - marginLeft(), marginLeft() + width() + marginRight(), marginTop() + height() + marginBottom() }; }
138
139     LayoutUnit marginTop() const;
140     LayoutUnit marginLeft() const;
141     LayoutUnit marginBottom() const;
142     LayoutUnit marginRight() const;
143
144     LayoutUnit nonCollapsedMarginTop() const;
145     LayoutUnit nonCollapsedMarginBottom() const;
146     LayoutUnit nonComputedMarginLeft() const;
147     LayoutUnit nonComputedMarginRight() const;
148
149     std::optional<LayoutUnit> estimatedMarginTop() const { return m_estimatedMarginTop; }
150
151     LayoutUnit borderTop() const;
152     LayoutUnit borderLeft() const;
153     LayoutUnit borderBottom() const;
154     LayoutUnit borderRight() const;
155
156     std::optional<LayoutUnit> paddingTop() const;
157     std::optional<LayoutUnit> paddingLeft() const;
158     std::optional<LayoutUnit> paddingBottom() const;
159     std::optional<LayoutUnit> paddingRight() const;
160
161     LayoutUnit contentBoxTop() const { return borderTop() + paddingTop().value_or(0); }
162     LayoutUnit contentBoxLeft() const { return borderLeft() + paddingLeft().value_or(0); }
163     LayoutUnit contentBoxBottom() const { return contentBoxTop() + contentBoxHeight(); }
164     LayoutUnit contentBoxRight() const { return contentBoxLeft() + contentBoxWidth(); }
165     LayoutUnit contentBoxHeight() const;
166     LayoutUnit contentBoxWidth() const;
167
168     Rect marginBox() const;
169     Rect nonCollapsedMarginBox() const;
170
171     Rect borderBox() const;
172     Rect paddingBox() const;
173     Rect contentBox() const;
174
175 private:
176     struct Style {
177         Style(const RenderStyle&);
178
179         BoxSizing boxSizing { BoxSizing::ContentBox };
180     };
181
182     void setTopLeft(const LayoutPoint&);
183     void setTop(LayoutUnit);
184     void setLeft(LayoutUnit);
185     void moveHorizontally(LayoutUnit offset) { m_topLeft.move(offset, { }); }
186     void moveVertically(LayoutUnit offset) { m_topLeft.move({ }, offset); }
187
188     void setContentBoxHeight(LayoutUnit);
189     void setContentBoxWidth(LayoutUnit);
190
191     void setHorizontalMargin(Layout::HorizontalEdges);
192     void setVerticalMargin(Layout::VerticalEdges);
193     void setVerticalNonCollapsedMargin(Layout::VerticalEdges);
194     void setHorizontalNonComputedMargin(Layout::HorizontalEdges);
195     void setEstimatedMarginTop(LayoutUnit marginTop) { m_estimatedMarginTop = marginTop; }
196
197     void setBorder(Layout::Edges);
198     void setPadding(std::optional<Layout::Edges>);
199
200 #if !ASSERT_DISABLED
201     void invalidateMargin();
202     void invalidateBorder() { m_hasValidBorder = false; }
203     void invalidatePadding() { m_hasValidPadding = false; }
204
205     void setHasValidTop() { m_hasValidTop = true; }
206     void setHasValidLeft() { m_hasValidLeft = true; }
207     void setHasValidVerticalMargin() { m_hasValidVerticalMargin = true; }
208     void setHasValidVerticalNonCollapsedMargin() { m_hasValidVerticalNonCollapsedMargin = true; }
209     void setHasValidHorizontalNonComputedMargin() { m_hasValidHorizontalNonComputedMargin = true; }
210     void setHasValidHorizontalMargin() { m_hasValidHorizontalMargin = true; }
211
212     void setHasValidBorder() { m_hasValidBorder = true; }
213     void setHasValidPadding() { m_hasValidPadding = true; }
214
215     void setHasValidContentHeight() { m_hasValidContentHeight = true; }
216     void setHasValidContentWidth() { m_hasValidContentWidth = true; }
217 #endif
218
219     const Style m_style;
220
221     LayoutPoint m_topLeft;
222     LayoutUnit m_contentWidth;
223     LayoutUnit m_contentHeight;
224
225     Layout::Edges m_margin;
226     Layout::VerticalEdges m_verticalNonCollapsedMargin;
227     Layout::HorizontalEdges m_horizontalNonComputedMargin;
228     std::optional<LayoutUnit> m_estimatedMarginTop;
229
230     Layout::Edges m_border;
231     std::optional<Layout::Edges> m_padding;
232
233 #if !ASSERT_DISABLED
234     bool m_hasValidTop { false };
235     bool m_hasValidLeft { false };
236     bool m_hasValidHorizontalMargin { false };
237     bool m_hasValidVerticalMargin { false };
238     bool m_hasValidVerticalNonCollapsedMargin { false };
239     bool m_hasValidHorizontalNonComputedMargin { false };
240     bool m_hasValidBorder { false };
241     bool m_hasValidPadding { false };
242     bool m_hasValidContentHeight { false };
243     bool m_hasValidContentWidth { false };
244 #endif
245 };
246
247 #if !ASSERT_DISABLED
248 inline void Box::Rect::invalidatePosition()
249 {
250     invalidateTop();
251     invalidateLeft();
252 }
253
254 inline void Box::Rect::setHasValidPosition()
255 {
256     m_hasValidTop = true;
257     m_hasValidLeft = true;
258 }
259
260 inline void Box::Rect::setHasValidSize()
261 {
262     m_hasValidWidth = true;
263     m_hasValidHeight = true;
264 }
265
266 inline void Box::invalidateMargin()
267 {
268     m_hasValidHorizontalMargin = false;
269     m_hasValidVerticalMargin = false;
270 }
271 #endif
272
273 inline LayoutUnit Box::Rect::top() const
274 {
275     ASSERT(m_hasValidTop);
276     return m_rect.y();
277 }
278
279 inline LayoutUnit Box::Rect::left() const
280 {
281     ASSERT(m_hasValidLeft);
282     return m_rect.x();
283 }
284
285 inline LayoutUnit Box::Rect::bottom() const
286 {
287     ASSERT(m_hasValidTop && m_hasValidHeight);
288     return m_rect.maxY();
289 }
290
291 inline LayoutUnit Box::Rect::right() const
292 {
293     ASSERT(m_hasValidLeft && m_hasValidWidth);
294     return m_rect.maxX();
295 }
296
297 inline LayoutPoint Box::Rect::topLeft() const
298 {
299     ASSERT(hasValidPosition());
300     return m_rect.minXMinYCorner();
301 }
302
303 inline LayoutPoint Box::Rect::bottomRight() const
304 {
305     ASSERT(hasValidGeometry());
306     return m_rect.maxXMaxYCorner();
307 }
308
309 inline LayoutSize Box::Rect::size() const
310 {
311     ASSERT(hasValidSize());
312     return m_rect.size();
313 }
314
315 inline LayoutUnit Box::Rect::width() const
316 {
317     ASSERT(m_hasValidWidth);
318     return m_rect.width();
319 }
320
321 inline LayoutUnit Box::Rect::height() const
322 {
323     ASSERT(m_hasValidHeight);
324     return m_rect.height();
325 }
326
327 inline void Box::Rect::setTopLeft(const LayoutPoint& topLeft)
328 {
329 #if !ASSERT_DISABLED
330     setHasValidPosition();
331 #endif
332     m_rect.setLocation(topLeft);
333 }
334
335 inline void Box::Rect::setTop(LayoutUnit top)
336 {
337 #if !ASSERT_DISABLED
338     m_hasValidTop = true;
339 #endif
340     m_rect.setY(top);
341 }
342
343 inline void Box::Rect::setLeft(LayoutUnit left)
344 {
345 #if !ASSERT_DISABLED
346     m_hasValidLeft = true;
347 #endif
348     m_rect.setX(left);
349 }
350
351 inline void Box::Rect::setWidth(LayoutUnit width)
352 {
353 #if !ASSERT_DISABLED
354     m_hasValidWidth = true;
355 #endif
356     m_rect.setWidth(width);
357 }
358
359 inline void Box::Rect::setHeight(LayoutUnit height)
360 {
361 #if !ASSERT_DISABLED
362     m_hasValidHeight = true;
363 #endif
364     m_rect.setHeight(height);
365 }
366
367 inline void Box::Rect::setSize(const LayoutSize& size)
368 {
369 #if !ASSERT_DISABLED
370     setHasValidSize();
371 #endif
372     m_rect.setSize(size);
373 }
374
375 inline void Box::Rect::shiftLeftTo(LayoutUnit left)
376 {
377     ASSERT(m_hasValidLeft);
378     m_rect.shiftXEdgeTo(left);
379 }
380
381 inline void Box::Rect::shiftRightTo(LayoutUnit right)
382 {
383     ASSERT(m_hasValidLeft && m_hasValidWidth);
384     m_rect.shiftMaxXEdgeTo(right);
385 }
386
387 inline void Box::Rect::shiftTopTo(LayoutUnit top)
388 {
389     ASSERT(m_hasValidTop);
390     m_rect.shiftYEdgeTo(top);
391 }
392
393 inline void Box::Rect::shiftBottomTo(LayoutUnit bottom)
394 {
395     ASSERT(m_hasValidTop && m_hasValidHeight);
396     m_rect.shiftMaxYEdgeTo(bottom);
397 }
398
399 inline void Box::Rect::moveHorizontally(LayoutUnit offset)
400 {
401     ASSERT(m_hasValidLeft);
402     m_rect.move(offset, { });
403 }
404
405 inline void Box::Rect::moveVertically(LayoutUnit offset)
406 {
407     ASSERT(m_hasValidTop);
408     m_rect.move({ }, offset);
409 }
410
411 inline void Box::Rect::expand(LayoutUnit width, LayoutUnit height)
412 {
413     ASSERT(hasValidGeometry());
414     m_rect.expand(width, height);
415 }
416
417 inline Box::Rect Box::Rect::clone() const
418 {
419     Rect rect;
420 #if !ASSERT_DISABLED
421     rect.m_hasValidTop = m_hasValidTop;
422     rect.m_hasValidLeft = m_hasValidLeft;
423     rect.m_hasValidWidth = m_hasValidWidth;
424     rect.m_hasValidHeight  = m_hasValidHeight;
425 #endif 
426     rect.m_rect = m_rect;
427     return rect;
428 }
429
430 inline Box::Rect::operator LayoutRect() const
431 {
432     ASSERT(hasValidGeometry()); 
433     return m_rect;
434 }
435
436 inline LayoutUnit Box::top() const
437 {
438     ASSERT(m_hasValidTop && (m_estimatedMarginTop || m_hasValidVerticalMargin));
439     return m_topLeft.y();
440 }
441
442 inline LayoutUnit Box::left() const
443 {
444     ASSERT(m_hasValidLeft && m_hasValidHorizontalMargin);
445     return m_topLeft.x();
446 }
447
448 inline LayoutPoint Box::topLeft() const
449 {
450     ASSERT(m_hasValidTop && (m_estimatedMarginTop || m_hasValidVerticalMargin));
451     ASSERT(m_hasValidLeft && m_hasValidHorizontalMargin);
452     return m_topLeft;
453 }
454
455 inline void Box::setTopLeft(const LayoutPoint& topLeft)
456 {
457 #if !ASSERT_DISABLED
458     setHasValidTop();
459     setHasValidLeft();
460 #endif
461     m_topLeft = topLeft;
462 }
463
464 inline void Box::setTop(LayoutUnit top)
465 {
466 #if !ASSERT_DISABLED
467     setHasValidTop();
468 #endif
469     m_topLeft.setY(top);
470 }
471
472 inline void Box::setLeft(LayoutUnit left)
473 {
474 #if !ASSERT_DISABLED
475     setHasValidLeft();
476 #endif
477     m_topLeft.setX(left);
478 }
479
480 inline void Box::setContentBoxHeight(LayoutUnit height)
481
482 #if !ASSERT_DISABLED
483     setHasValidContentHeight();
484 #endif
485     m_contentHeight = height;
486 }
487
488 inline void Box::setContentBoxWidth(LayoutUnit width)
489
490 #if !ASSERT_DISABLED
491     setHasValidContentWidth();
492 #endif
493     m_contentWidth = width;
494 }
495
496 inline LayoutUnit Box::contentBoxHeight() const
497 {
498     ASSERT(m_hasValidContentHeight);
499     return m_contentHeight;
500 }
501
502 inline LayoutUnit Box::contentBoxWidth() const
503 {
504     ASSERT(m_hasValidContentWidth);
505     return m_contentWidth;
506 }
507
508 inline void Box::setHorizontalMargin(Layout::HorizontalEdges margin)
509 {
510 #if !ASSERT_DISABLED
511     setHasValidHorizontalMargin();
512 #endif
513     m_margin.horizontal = margin;
514 }
515
516 inline void Box::setVerticalMargin(Layout::VerticalEdges margin)
517 {
518 #if !ASSERT_DISABLED
519     setHasValidVerticalMargin();
520 #endif
521     ASSERT(!m_estimatedMarginTop || *m_estimatedMarginTop == margin.top);
522     m_margin.vertical = margin;
523 }
524
525 inline void Box::setVerticalNonCollapsedMargin(Layout::VerticalEdges margin)
526 {
527 #if !ASSERT_DISABLED
528     setHasValidVerticalNonCollapsedMargin();
529 #endif
530     m_verticalNonCollapsedMargin = margin;
531 }
532
533 inline void Box::setHorizontalNonComputedMargin(Layout::HorizontalEdges margin)
534 {
535 #if !ASSERT_DISABLED
536     setHasValidHorizontalNonComputedMargin();
537 #endif
538     m_horizontalNonComputedMargin = margin;
539 }
540
541 inline void Box::setBorder(Layout::Edges border)
542 {
543 #if !ASSERT_DISABLED
544     setHasValidBorder();
545 #endif
546     m_border = border;
547 }
548
549 inline void Box::setPadding(std::optional<Layout::Edges> padding)
550 {
551 #if !ASSERT_DISABLED
552     setHasValidPadding();
553 #endif
554     m_padding = padding;
555 }
556
557 inline LayoutUnit Box::marginTop() const
558 {
559     ASSERT(m_hasValidVerticalMargin);
560     return m_margin.vertical.top;
561 }
562
563 inline LayoutUnit Box::marginLeft() const
564 {
565     ASSERT(m_hasValidHorizontalMargin);
566     return m_margin.horizontal.left;
567 }
568
569 inline LayoutUnit Box::marginBottom() const
570 {
571     ASSERT(m_hasValidVerticalMargin);
572     return m_margin.vertical.bottom;
573 }
574
575 inline LayoutUnit Box::marginRight() const
576 {
577     ASSERT(m_hasValidHorizontalMargin);
578     return m_margin.horizontal.right;
579 }
580
581 inline LayoutUnit Box::nonCollapsedMarginTop() const
582 {
583     ASSERT(m_hasValidVerticalNonCollapsedMargin);
584     return m_verticalNonCollapsedMargin.top;
585 }
586
587 inline LayoutUnit Box::nonCollapsedMarginBottom() const
588 {
589     ASSERT(m_hasValidVerticalNonCollapsedMargin);
590     return m_verticalNonCollapsedMargin.bottom;
591 }
592
593 inline LayoutUnit Box::nonComputedMarginLeft() const
594 {
595     ASSERT(m_hasValidHorizontalNonComputedMargin);
596     return m_horizontalNonComputedMargin.left;
597 }
598
599 inline LayoutUnit Box::nonComputedMarginRight() const
600 {
601     ASSERT(m_hasValidHorizontalNonComputedMargin);
602     return m_horizontalNonComputedMargin.right;
603 }
604
605 inline std::optional<LayoutUnit> Box::paddingTop() const
606 {
607     ASSERT(m_hasValidPadding);
608     if (!m_padding)
609         return { };
610     return m_padding->vertical.top;
611 }
612
613 inline std::optional<LayoutUnit> Box::paddingLeft() const
614 {
615     ASSERT(m_hasValidPadding);
616     if (!m_padding)
617         return { };
618     return m_padding->horizontal.left;
619 }
620
621 inline std::optional<LayoutUnit> Box::paddingBottom() const
622 {
623     ASSERT(m_hasValidPadding);
624     if (!m_padding)
625         return { };
626     return m_padding->vertical.bottom;
627 }
628
629 inline std::optional<LayoutUnit> Box::paddingRight() const
630 {
631     ASSERT(m_hasValidPadding);
632     if (!m_padding)
633         return { };
634     return m_padding->horizontal.right;
635 }
636
637 inline LayoutUnit Box::borderTop() const
638 {
639     ASSERT(m_hasValidBorder);
640     return m_border.vertical.top;
641 }
642
643 inline LayoutUnit Box::borderLeft() const
644 {
645     ASSERT(m_hasValidBorder);
646     return m_border.horizontal.left;
647 }
648
649 inline LayoutUnit Box::borderBottom() const
650 {
651     ASSERT(m_hasValidBorder);
652     return m_border.vertical.bottom;
653 }
654
655 inline LayoutUnit Box::borderRight() const
656 {
657     ASSERT(m_hasValidBorder);
658     return m_border.horizontal.right;
659 }
660
661 }
662 }
663 #endif