[LFC][BFC] Display::Box interface should reflect that padding is optional.
[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 { return m_topLeft.y(); }
121     LayoutUnit left() const { return m_topLeft.x(); }
122     LayoutUnit bottom() const { return top() + height(); }
123     LayoutUnit right() const { return left() + width(); }
124
125     LayoutPoint topLeft() const { return m_topLeft; }
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
142     LayoutUnit borderTop() const;
143     LayoutUnit borderLeft() const;
144     LayoutUnit borderBottom() const;
145     LayoutUnit borderRight() const;
146
147     std::optional<LayoutUnit> paddingTop() const;
148     std::optional<LayoutUnit> paddingLeft() const;
149     std::optional<LayoutUnit> paddingBottom() const;
150     std::optional<LayoutUnit> paddingRight() const;
151
152     LayoutUnit contentBoxTop() const { return borderTop() + paddingTop().value_or(0); }
153     LayoutUnit contentBoxLeft() const { return borderLeft() + paddingLeft().value_or(0); }
154     LayoutUnit contentBoxBottom() const { return contentBoxTop() + contentBoxHeight(); }
155     LayoutUnit contentBoxRight() const { return contentBoxLeft() + contentBoxWidth(); }
156     LayoutUnit contentBoxHeight() const;
157     LayoutUnit contentBoxWidth() const;
158
159     Rect marginBox() const;
160     Rect nonCollapsedMarginBox() const;
161
162     Rect borderBox() const;
163     Rect paddingBox() const;
164     Rect contentBox() const;
165
166 private:
167     Box(const RenderStyle&);
168
169     struct Style {
170         Style(const RenderStyle&);
171
172         BoxSizing boxSizing { BoxSizing::ContentBox };
173     };
174
175     void setTopLeft(const LayoutPoint& topLeft) { m_topLeft = topLeft; }
176     void setTop(LayoutUnit top) { m_topLeft.setY(top); }
177     void setLeft(LayoutUnit left) { m_topLeft.setX(left); }
178     void moveHorizontally(LayoutUnit offset) { m_topLeft.move(offset, { }); }
179     void moveVertically(LayoutUnit offset) { m_topLeft.move({ }, offset); }
180
181     void setContentBoxHeight(LayoutUnit);
182     void setContentBoxWidth(LayoutUnit);
183
184     void setHorizontalMargin(Layout::HorizontalEdges);
185     void setVerticalMargin(Layout::VerticalEdges);
186     void setVerticalNonCollapsedMargin(Layout::VerticalEdges);
187
188     void setBorder(Layout::Edges);
189     void setPadding(std::optional<Layout::Edges>);
190
191 #if !ASSERT_DISABLED
192     void invalidateMargin();
193     void invalidateBorder() { m_hasValidBorder = false; }
194     void invalidatePadding() { m_hasValidPadding = false; }
195
196     void setHasValidVerticalMargin() { m_hasValidVerticalMargin = true; }
197     void setHasValidVerticalNonCollapsedMargin() { m_hasValidVerticalNonCollapsedMargin = true; }
198     void setHasValidHorizontalMargin() { m_hasValidHorizontalMargin = true; }
199
200     void setHasValidBorder() { m_hasValidBorder = true; }
201     void setHasValidPadding() { m_hasValidPadding = true; }
202
203     void setHasValidContentHeight() { m_hasValidContentHeight = true; }
204     void setHasValidContentWidth() { m_hasValidContentWidth = true; }
205 #endif
206
207     const Style m_style;
208
209     LayoutPoint m_topLeft;
210     LayoutUnit m_contentWidth;
211     LayoutUnit m_contentHeight;
212
213     Layout::Edges m_margin;
214     Layout::VerticalEdges m_verticalNonCollapsedMargin;
215
216     Layout::Edges m_border;
217     std::optional<Layout::Edges> m_padding;
218
219 #if !ASSERT_DISABLED
220     bool m_hasValidHorizontalMargin { false };
221     bool m_hasValidVerticalMargin { false };
222     bool m_hasValidVerticalNonCollapsedMargin { false };
223     bool m_hasValidBorder { false };
224     bool m_hasValidPadding { false };
225     bool m_hasValidContentHeight { false };
226     bool m_hasValidContentWidth { false };
227 #endif
228 };
229
230 #if !ASSERT_DISABLED
231 inline void Box::Rect::invalidatePosition()
232 {
233     invalidateTop();
234     invalidateLeft();
235 }
236
237 inline void Box::Rect::setHasValidPosition()
238 {
239     m_hasValidTop = true;
240     m_hasValidLeft = true;
241 }
242
243 inline void Box::Rect::setHasValidSize()
244 {
245     m_hasValidWidth = true;
246     m_hasValidHeight = true;
247 }
248
249 inline void Box::invalidateMargin()
250 {
251     m_hasValidHorizontalMargin = false;
252     m_hasValidVerticalMargin = false;
253 }
254 #endif
255
256 inline LayoutUnit Box::Rect::top() const
257 {
258     ASSERT(m_hasValidTop);
259     return m_rect.y();
260 }
261
262 inline LayoutUnit Box::Rect::left() const
263 {
264     ASSERT(m_hasValidLeft);
265     return m_rect.x();
266 }
267
268 inline LayoutUnit Box::Rect::bottom() const
269 {
270     ASSERT(m_hasValidTop && m_hasValidHeight);
271     return m_rect.maxY();
272 }
273
274 inline LayoutUnit Box::Rect::right() const
275 {
276     ASSERT(m_hasValidLeft && m_hasValidWidth);
277     return m_rect.maxX();
278 }
279
280 inline LayoutPoint Box::Rect::topLeft() const
281 {
282     ASSERT(hasValidPosition());
283     return m_rect.minXMinYCorner();
284 }
285
286 inline LayoutPoint Box::Rect::bottomRight() const
287 {
288     ASSERT(hasValidGeometry());
289     return m_rect.maxXMaxYCorner();
290 }
291
292 inline LayoutSize Box::Rect::size() const
293 {
294     ASSERT(hasValidSize());
295     return m_rect.size();
296 }
297
298 inline LayoutUnit Box::Rect::width() const
299 {
300     ASSERT(m_hasValidWidth);
301     return m_rect.width();
302 }
303
304 inline LayoutUnit Box::Rect::height() const
305 {
306     ASSERT(m_hasValidHeight);
307     return m_rect.height();
308 }
309
310 inline void Box::Rect::setTopLeft(const LayoutPoint& topLeft)
311 {
312 #if !ASSERT_DISABLED
313     setHasValidPosition();
314 #endif
315     m_rect.setLocation(topLeft);
316 }
317
318 inline void Box::Rect::setTop(LayoutUnit top)
319 {
320 #if !ASSERT_DISABLED
321     m_hasValidTop = true;
322 #endif
323     m_rect.setY(top);
324 }
325
326 inline void Box::Rect::setLeft(LayoutUnit left)
327 {
328 #if !ASSERT_DISABLED
329     m_hasValidLeft = true;
330 #endif
331     m_rect.setX(left);
332 }
333
334 inline void Box::Rect::setWidth(LayoutUnit width)
335 {
336 #if !ASSERT_DISABLED
337     m_hasValidWidth = true;
338 #endif
339     m_rect.setWidth(width);
340 }
341
342 inline void Box::Rect::setHeight(LayoutUnit height)
343 {
344 #if !ASSERT_DISABLED
345     m_hasValidHeight = true;
346 #endif
347     m_rect.setHeight(height);
348 }
349
350 inline void Box::Rect::setSize(const LayoutSize& size)
351 {
352 #if !ASSERT_DISABLED
353     setHasValidSize();
354 #endif
355     m_rect.setSize(size);
356 }
357
358 inline void Box::Rect::shiftLeftTo(LayoutUnit left)
359 {
360     ASSERT(m_hasValidLeft);
361     m_rect.shiftXEdgeTo(left);
362 }
363
364 inline void Box::Rect::shiftRightTo(LayoutUnit right)
365 {
366     ASSERT(m_hasValidLeft && m_hasValidWidth);
367     m_rect.shiftMaxXEdgeTo(right);
368 }
369
370 inline void Box::Rect::shiftTopTo(LayoutUnit top)
371 {
372     ASSERT(m_hasValidTop);
373     m_rect.shiftYEdgeTo(top);
374 }
375
376 inline void Box::Rect::shiftBottomTo(LayoutUnit bottom)
377 {
378     ASSERT(m_hasValidTop && m_hasValidHeight);
379     m_rect.shiftMaxYEdgeTo(bottom);
380 }
381
382 inline void Box::Rect::moveHorizontally(LayoutUnit offset)
383 {
384     ASSERT(m_hasValidLeft);
385     m_rect.move(offset, { });
386 }
387
388 inline void Box::Rect::moveVertically(LayoutUnit offset)
389 {
390     ASSERT(m_hasValidTop);
391     m_rect.move({ }, offset);
392 }
393
394 inline void Box::Rect::expand(LayoutUnit width, LayoutUnit height)
395 {
396     ASSERT(hasValidGeometry());
397     m_rect.expand(width, height);
398 }
399
400 inline Box::Rect Box::Rect::clone() const
401 {
402     Rect rect;
403 #if !ASSERT_DISABLED
404     rect.m_hasValidTop = m_hasValidTop;
405     rect.m_hasValidLeft = m_hasValidLeft;
406     rect.m_hasValidWidth = m_hasValidWidth;
407     rect.m_hasValidHeight  = m_hasValidHeight;
408 #endif 
409     rect.m_rect = m_rect;
410     return rect;
411 }
412
413 inline Box::Rect::operator LayoutRect() const
414 {
415     ASSERT(hasValidGeometry()); 
416     return m_rect;
417 }
418
419 inline void Box::setContentBoxHeight(LayoutUnit height)
420
421 #if !ASSERT_DISABLED
422     setHasValidContentHeight();
423 #endif
424     m_contentHeight = height;
425 }
426
427 inline void Box::setContentBoxWidth(LayoutUnit width)
428
429 #if !ASSERT_DISABLED
430     setHasValidContentWidth();
431 #endif
432     m_contentWidth = width;
433 }
434
435 inline LayoutUnit Box::contentBoxHeight() const
436 {
437     ASSERT(m_hasValidContentHeight);
438     return m_contentHeight;
439 }
440
441 inline LayoutUnit Box::contentBoxWidth() const
442 {
443     ASSERT(m_hasValidContentWidth);
444     return m_contentWidth;
445 }
446
447 inline void Box::setHorizontalMargin(Layout::HorizontalEdges margin)
448 {
449 #if !ASSERT_DISABLED
450     setHasValidHorizontalMargin();
451 #endif
452     m_margin.horizontal = margin;
453 }
454
455 inline void Box::setVerticalMargin(Layout::VerticalEdges margin)
456 {
457 #if !ASSERT_DISABLED
458     setHasValidVerticalMargin();
459 #endif
460     m_margin.vertical = margin;
461 }
462
463 inline void Box::setVerticalNonCollapsedMargin(Layout::VerticalEdges margin)
464 {
465 #if !ASSERT_DISABLED
466     setHasValidVerticalNonCollapsedMargin();
467 #endif
468     m_verticalNonCollapsedMargin = margin;
469 }
470
471 inline void Box::setBorder(Layout::Edges border)
472 {
473 #if !ASSERT_DISABLED
474     setHasValidBorder();
475 #endif
476     m_border = border;
477 }
478
479 inline void Box::setPadding(std::optional<Layout::Edges> padding)
480 {
481 #if !ASSERT_DISABLED
482     setHasValidPadding();
483 #endif
484     m_padding = padding;
485 }
486
487 inline LayoutUnit Box::marginTop() const
488 {
489     ASSERT(m_hasValidVerticalMargin);
490     return m_margin.vertical.top;
491 }
492
493 inline LayoutUnit Box::marginLeft() const
494 {
495     ASSERT(m_hasValidHorizontalMargin);
496     return m_margin.horizontal.left;
497 }
498
499 inline LayoutUnit Box::marginBottom() const
500 {
501     ASSERT(m_hasValidVerticalMargin);
502     return m_margin.vertical.bottom;
503 }
504
505 inline LayoutUnit Box::marginRight() const
506 {
507     ASSERT(m_hasValidHorizontalMargin);
508     return m_margin.horizontal.right;
509 }
510
511 inline LayoutUnit Box::nonCollapsedMarginTop() const
512 {
513     ASSERT(m_hasValidVerticalNonCollapsedMargin);
514     return m_verticalNonCollapsedMargin.top;
515 }
516
517 inline LayoutUnit Box::nonCollapsedMarginBottom() const
518 {
519     ASSERT(m_hasValidVerticalNonCollapsedMargin);
520     return m_verticalNonCollapsedMargin.bottom;
521 }
522
523 inline std::optional<LayoutUnit> Box::paddingTop() const
524 {
525     ASSERT(m_hasValidPadding);
526     if (!m_padding)
527         return { };
528     return m_padding->vertical.top;
529 }
530
531 inline std::optional<LayoutUnit> Box::paddingLeft() const
532 {
533     ASSERT(m_hasValidPadding);
534     if (!m_padding)
535         return { };
536     return m_padding->horizontal.left;
537 }
538
539 inline std::optional<LayoutUnit> Box::paddingBottom() const
540 {
541     ASSERT(m_hasValidPadding);
542     if (!m_padding)
543         return { };
544     return m_padding->vertical.bottom;
545 }
546
547 inline std::optional<LayoutUnit> Box::paddingRight() const
548 {
549     ASSERT(m_hasValidPadding);
550     if (!m_padding)
551         return { };
552     return m_padding->horizontal.right;
553 }
554
555 inline LayoutUnit Box::borderTop() const
556 {
557     ASSERT(m_hasValidBorder);
558     return m_border.vertical.top;
559 }
560
561 inline LayoutUnit Box::borderLeft() const
562 {
563     ASSERT(m_hasValidBorder);
564     return m_border.horizontal.left;
565 }
566
567 inline LayoutUnit Box::borderBottom() const
568 {
569     ASSERT(m_hasValidBorder);
570     return m_border.vertical.bottom;
571 }
572
573 inline LayoutUnit Box::borderRight() const
574 {
575     ASSERT(m_hasValidBorder);
576     return m_border.horizontal.right;
577 }
578
579 }
580 }
581 #endif