summaryrefslogtreecommitdiffstats
path: root/third_party/WebKit/Source/core/layout/LayoutMultiColumnSpannerPlaceholder.cpp
blob: 60aadea98424975cb18ce6d9fc25ff6b85bc8799 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "core/layout/LayoutMultiColumnSpannerPlaceholder.h"

namespace blink {

static void copyMarginProperties(ComputedStyle& placeholderStyle, const ComputedStyle& spannerStyle)
{
    // We really only need the block direction margins, but there are no setters for that in
    // ComputedStyle. Just copy all margin sides. The inline ones don't matter anyway.
    placeholderStyle.setMarginLeft(spannerStyle.marginLeft());
    placeholderStyle.setMarginRight(spannerStyle.marginRight());
    placeholderStyle.setMarginTop(spannerStyle.marginTop());
    placeholderStyle.setMarginBottom(spannerStyle.marginBottom());
}

LayoutMultiColumnSpannerPlaceholder* LayoutMultiColumnSpannerPlaceholder::createAnonymous(const ComputedStyle& parentStyle, LayoutBox& layoutObjectInFlowThread)
{
    LayoutMultiColumnSpannerPlaceholder* newSpanner = new LayoutMultiColumnSpannerPlaceholder(&layoutObjectInFlowThread);
    Document& document = layoutObjectInFlowThread.document();
    newSpanner->setDocumentForAnonymous(&document);
    RefPtr<ComputedStyle> newStyle = ComputedStyle::createAnonymousStyleWithDisplay(parentStyle, BLOCK);
    copyMarginProperties(*newStyle, layoutObjectInFlowThread.styleRef());
    newSpanner->setStyle(newStyle);
    return newSpanner;
}

LayoutMultiColumnSpannerPlaceholder::LayoutMultiColumnSpannerPlaceholder(LayoutBox* layoutObjectInFlowThread)
    : LayoutBox(nullptr)
    , m_layoutObjectInFlowThread(layoutObjectInFlowThread)
{
}

void LayoutMultiColumnSpannerPlaceholder::layoutObjectInFlowThreadStyleDidChange(const ComputedStyle* oldStyle)
{
    LayoutBox* objectInFlowThread = m_layoutObjectInFlowThread;
    if (flowThread()->removeSpannerPlaceholderIfNoLongerValid(objectInFlowThread)) {
        // No longer a valid spanner, due to style changes. |this| is now dead.
        if (objectInFlowThread->style()->hasOutOfFlowPosition() && !oldStyle->hasOutOfFlowPosition()) {
            // We went from being a spanner to being out-of-flow positioned. When an object becomes
            // out-of-flow positioned, we need to lay out its parent, since that's where the
            // now-out-of-flow object gets added to the right containing block for out-of-flow
            // positioned objects. Since neither a spanner nor an out-of-flow object is guaranteed
            // to have this parent in its containing block chain, we need to mark it here, or we
            // risk that the object isn't laid out.
            objectInFlowThread->parent()->setNeedsLayout(LayoutInvalidationReason::ColumnsChanged);
        }
        return;
    }
    updateMarginProperties();
}

void LayoutMultiColumnSpannerPlaceholder::updateMarginProperties()
{
    RefPtr<ComputedStyle> newStyle = ComputedStyle::clone(styleRef());
    copyMarginProperties(*newStyle, m_layoutObjectInFlowThread->styleRef());
    setStyle(newStyle);
}

void LayoutMultiColumnSpannerPlaceholder::willBeRemovedFromTree()
{
    if (m_layoutObjectInFlowThread) {
        LayoutBox* exSpanner = m_layoutObjectInFlowThread;
        m_layoutObjectInFlowThread->clearSpannerPlaceholder();
        // Even if the placeholder is going away, the object in the flow thread might live on. Since
        // it's not a spanner anymore, it needs to be relaid out.
        exSpanner->setNeedsLayoutAndPrefWidthsRecalc(LayoutInvalidationReason::ColumnsChanged);
    }
    LayoutBox::willBeRemovedFromTree();
}

bool LayoutMultiColumnSpannerPlaceholder::needsPreferredWidthsRecalculation() const
{
    return m_layoutObjectInFlowThread->needsPreferredWidthsRecalculation();
}

LayoutUnit LayoutMultiColumnSpannerPlaceholder::minPreferredLogicalWidth() const
{
    return m_layoutObjectInFlowThread->minPreferredLogicalWidth();
}

LayoutUnit LayoutMultiColumnSpannerPlaceholder::maxPreferredLogicalWidth() const
{
    return m_layoutObjectInFlowThread->maxPreferredLogicalWidth();
}

void LayoutMultiColumnSpannerPlaceholder::layout()
{
    ASSERT(needsLayout());

    // The placeholder, like any other block level object, has its logical top calculated and set
    // before layout. Copy this to the actual column-span:all object before laying it out, so that
    // it gets paginated correctly, in case we have an enclosing fragmentation context.
    m_layoutObjectInFlowThread->setLogicalTop(logicalTop());

    // Lay out the actual column-span:all element.
    m_layoutObjectInFlowThread->layoutIfNeeded();

    // The spanner has now been laid out, so its height is known. Time to update the placeholder's
    // height as well, so that we take up the correct amount of space in the multicol container.
    updateLogicalHeight();

    // Take the overflow from the spanner, so that it gets
    // propagated to the multicol container and beyond.
    m_overflow.clear();
    addVisualOverflow(m_layoutObjectInFlowThread->visualOverflowRect());
    addLayoutOverflow(m_layoutObjectInFlowThread->layoutOverflowRect());

    clearNeedsLayout();
}

void LayoutMultiColumnSpannerPlaceholder::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const
{
    computedValues.m_extent = m_layoutObjectInFlowThread->logicalHeight();
    computedValues.m_position = logicalTop;
    computedValues.m_margins.m_before = marginBefore();
    computedValues.m_margins.m_after = marginAfter();
}

void LayoutMultiColumnSpannerPlaceholder::invalidateTreeIfNeeded(const PaintInvalidationState& paintInvalidationState)
{
    PaintInvalidationState newPaintInvalidationState(paintInvalidationState, *this);
    newPaintInvalidationState.updatePaintOffsetAndClipForChildren();
    m_layoutObjectInFlowThread->invalidateTreeIfNeeded(newPaintInvalidationState);
    LayoutBox::invalidateTreeIfNeeded(paintInvalidationState);
}

void LayoutMultiColumnSpannerPlaceholder::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset) const
{
    if (!m_layoutObjectInFlowThread->hasSelfPaintingLayer())
        m_layoutObjectInFlowThread->paint(paintInfo, paintOffset);
}

bool LayoutMultiColumnSpannerPlaceholder::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
{
    return !m_layoutObjectInFlowThread->hasSelfPaintingLayer() && m_layoutObjectInFlowThread->nodeAtPoint(result, locationInContainer, accumulatedOffset, action);
}

} // namespace blink