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