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