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#include "config.h"
27#include "FloatAvoider.h"
28
29#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
30
31#include "LayoutBox.h"
32#include "LayoutContainer.h"
33#include "LayoutState.h"
34#include <wtf/IsoMallocInlines.h>
35
36namespace WebCore {
37namespace Layout {
38
39WTF_MAKE_ISO_ALLOCATED_IMPL(FloatAvoider);
40
41FloatAvoider::FloatAvoider(const Box& layoutBox, const FloatingState& floatingState, const LayoutState& layoutState)
42 : m_layoutBox(makeWeakPtr(layoutBox))
43 , m_floatingState(floatingState)
44 , m_absoluteDisplayBox(FormattingContext::mapBoxToAncestor(layoutState, layoutBox, downcast<Container>(floatingState.root())))
45 , m_containingBlockAbsoluteDisplayBox(layoutBox.containingBlock() == &floatingState.root() ? Display::Box(layoutState.displayBoxForLayoutBox(*layoutBox.containingBlock())) : FormattingContext::mapBoxToAncestor(layoutState, *layoutBox.containingBlock(), downcast<Container>(floatingState.root())))
46{
47 ASSERT(m_layoutBox->establishesBlockFormattingContext());
48 m_absoluteDisplayBox.setLeft({ initialHorizontalPosition() });
49}
50
51void FloatAvoider::setHorizontalConstraints(HorizontalConstraints horizontalConstraints)
52{
53 if ((isLeftAligned() && !horizontalConstraints.left) || (!isLeftAligned() && !horizontalConstraints.right)) {
54 // No constraints? Set horizontal position back to the inital value.
55 m_absoluteDisplayBox.setLeft(initialHorizontalPosition());
56 return;
57 }
58
59 auto constrainWithContainingBlock = [&](auto left) -> PositionInContextRoot {
60 // Horizontal position is constrained by the containing block's content box.
61 // Compute the horizontal position for the new floating by taking both the contining block and the current left/right floats into account.
62 auto containingBlockContentBoxLeft = m_containingBlockAbsoluteDisplayBox.left() + m_containingBlockAbsoluteDisplayBox.contentBoxLeft();
63 if (isLeftAligned())
64 return std::max<PositionInContextRoot>({ containingBlockContentBoxLeft + marginStart() }, left);
65
66 // Make sure it does not overflow the containing block on the right.
67 auto containingBlockContentBoxRight = containingBlockContentBoxLeft + m_containingBlockAbsoluteDisplayBox.contentBoxWidth();
68 return std::min<PositionInContextRoot>(left, { containingBlockContentBoxRight - marginBoxWidth() + marginStart() });
69 };
70
71 auto positionCandidate = horizontalPositionCandidate(horizontalConstraints);
72 m_absoluteDisplayBox.setLeft(constrainWithContainingBlock(positionCandidate));
73}
74
75void FloatAvoider::setVerticalConstraint(PositionInContextRoot verticalConstraint)
76{
77 m_absoluteDisplayBox.setTop(verticalPositionCandidate(verticalConstraint));
78}
79
80PositionInContextRoot FloatAvoider::horizontalPositionCandidate(HorizontalConstraints horizontalConstraints)
81{
82 return { isLeftAligned() ? *horizontalConstraints.left : *horizontalConstraints.right - rect().width() };
83}
84
85PositionInContextRoot FloatAvoider::verticalPositionCandidate(PositionInContextRoot verticalConstraint)
86{
87 return verticalConstraint;
88}
89
90PositionInContextRoot FloatAvoider::initialHorizontalPosition() const
91{
92 // Align the box with the containing block's content box.
93 auto containingBlockContentBoxLeft = m_containingBlockAbsoluteDisplayBox.left() + m_containingBlockAbsoluteDisplayBox.contentBoxLeft();
94 auto containingBlockContentBoxRight = containingBlockContentBoxLeft + m_containingBlockAbsoluteDisplayBox.contentBoxWidth();
95
96 auto left = isLeftAligned() ? containingBlockContentBoxLeft : containingBlockContentBoxRight - marginBoxWidth();
97 left += marginStart();
98
99 return { left };
100}
101
102bool FloatAvoider::overflowsContainingBlock() const
103{
104 auto containingBlockContentBoxLeft = m_containingBlockAbsoluteDisplayBox.left() + m_containingBlockAbsoluteDisplayBox.contentBoxLeft();
105 auto left = displayBox().left() - marginStart();
106
107 if (containingBlockContentBoxLeft > left)
108 return true;
109
110 auto containingBlockContentBoxRight = containingBlockContentBoxLeft + m_containingBlockAbsoluteDisplayBox.contentBoxWidth();
111 auto right = displayBox().right() + marginEnd();
112
113 return containingBlockContentBoxRight < right;
114}
115
116Display::Box::Rect FloatAvoider::rectInContainingBlock() const
117{
118 // From formatting root coordinate system back to containing block's.
119 if (layoutBox().containingBlock() == &floatingState().root())
120 return m_absoluteDisplayBox.rect();
121
122 return {
123 m_absoluteDisplayBox.top() - m_containingBlockAbsoluteDisplayBox.top(),
124 m_absoluteDisplayBox.left() - m_containingBlockAbsoluteDisplayBox.left(),
125 m_absoluteDisplayBox.width(),
126 m_absoluteDisplayBox.height()
127 };
128}
129
130}
131}
132#endif
133