summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
blob: 97f9fff388a4dd9d00e1aa22d750dc93d714a4e7 (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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// 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 "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h"

#include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h"

namespace blink {

static void CopyMarginProperties(ComputedStyle& placeholder_style,
                                 const ComputedStyle& spanner_style) {
  // 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.
  placeholder_style.SetMarginLeft(spanner_style.MarginLeft());
  placeholder_style.SetMarginRight(spanner_style.MarginRight());
  placeholder_style.SetMarginTop(spanner_style.MarginTop());
  placeholder_style.SetMarginBottom(spanner_style.MarginBottom());
}

LayoutMultiColumnSpannerPlaceholder*
LayoutMultiColumnSpannerPlaceholder::CreateAnonymous(
    const ComputedStyle& parent_style,
    LayoutBox& layout_object_in_flow_thread) {
  LayoutMultiColumnSpannerPlaceholder* new_spanner =
      new LayoutMultiColumnSpannerPlaceholder(&layout_object_in_flow_thread);
  Document& document = layout_object_in_flow_thread.GetDocument();
  new_spanner->SetDocumentForAnonymous(&document);
  scoped_refptr<ComputedStyle> new_style =
      ComputedStyle::CreateAnonymousStyleWithDisplay(parent_style,
                                                     EDisplay::kBlock);
  CopyMarginProperties(*new_style, layout_object_in_flow_thread.StyleRef());
  new_spanner->SetStyle(new_style);
  return new_spanner;
}

LayoutMultiColumnSpannerPlaceholder::LayoutMultiColumnSpannerPlaceholder(
    LayoutBox* layout_object_in_flow_thread)
    : LayoutBox(nullptr),
      layout_object_in_flow_thread_(layout_object_in_flow_thread) {}

void LayoutMultiColumnSpannerPlaceholder::
    LayoutObjectInFlowThreadStyleDidChange(const ComputedStyle* old_style) {
  LayoutBox* object_in_flow_thread = layout_object_in_flow_thread_;
  if (FlowThread()->RemoveSpannerPlaceholderIfNoLongerValid(
          object_in_flow_thread)) {
    // No longer a valid spanner, due to style changes. |this| is now dead.
    if (object_in_flow_thread->StyleRef().HasOutOfFlowPosition() &&
        !old_style->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.
      object_in_flow_thread->Parent()->SetNeedsLayout(
          LayoutInvalidationReason::kColumnsChanged);
    }
    return;
  }
  UpdateMarginProperties();
}

void LayoutMultiColumnSpannerPlaceholder::UpdateMarginProperties() {
  scoped_refptr<ComputedStyle> new_style = ComputedStyle::Clone(StyleRef());
  CopyMarginProperties(*new_style, layout_object_in_flow_thread_->StyleRef());
  SetStyle(new_style);
}

void LayoutMultiColumnSpannerPlaceholder::InsertedIntoTree() {
  LayoutBox::InsertedIntoTree();
  // The object may previously have been laid out as a non-spanner, but since
  // it's a spanner now, it needs to be relaid out.
  layout_object_in_flow_thread_->SetNeedsLayoutAndPrefWidthsRecalc(
      LayoutInvalidationReason::kColumnsChanged);
}

void LayoutMultiColumnSpannerPlaceholder::WillBeRemovedFromTree() {
  if (layout_object_in_flow_thread_) {
    LayoutBox* ex_spanner = layout_object_in_flow_thread_;
    layout_object_in_flow_thread_->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.
    ex_spanner->SetNeedsLayoutAndPrefWidthsRecalc(
        LayoutInvalidationReason::kColumnsChanged);
  }
  LayoutBox::WillBeRemovedFromTree();
}

bool LayoutMultiColumnSpannerPlaceholder::NeedsPreferredWidthsRecalculation()
    const {
  return layout_object_in_flow_thread_->NeedsPreferredWidthsRecalculation();
}

LayoutUnit LayoutMultiColumnSpannerPlaceholder::MinPreferredLogicalWidth()
    const {
  return layout_object_in_flow_thread_->MinPreferredLogicalWidth();
}

LayoutUnit LayoutMultiColumnSpannerPlaceholder::MaxPreferredLogicalWidth()
    const {
  return layout_object_in_flow_thread_->MaxPreferredLogicalWidth();
}

void LayoutMultiColumnSpannerPlaceholder::UpdateLayout() {
  DCHECK(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.
  layout_object_in_flow_thread_->SetLogicalTop(LogicalTop());

  // Lay out the actual column-span:all element.
  layout_object_in_flow_thread_->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.
  overflow_.reset();
  AddContentsVisualOverflow(
      layout_object_in_flow_thread_->VisualOverflowRect());
  AddLayoutOverflow(layout_object_in_flow_thread_->LayoutOverflowRect());

  ClearNeedsLayout();
}

void LayoutMultiColumnSpannerPlaceholder::ComputeLogicalHeight(
    LayoutUnit,
    LayoutUnit logical_top,
    LogicalExtentComputedValues& computed_values) const {
  computed_values.extent_ = layout_object_in_flow_thread_->LogicalHeight();
  computed_values.position_ = logical_top;
  computed_values.margins_.before_ = MarginBefore();
  computed_values.margins_.after_ = MarginAfter();
}

void LayoutMultiColumnSpannerPlaceholder::Paint(
    const PaintInfo& paint_info) const {
  if (!layout_object_in_flow_thread_->HasSelfPaintingLayer())
    layout_object_in_flow_thread_->Paint(paint_info);
}

bool LayoutMultiColumnSpannerPlaceholder::NodeAtPoint(
    HitTestResult& result,
    const HitTestLocation& location_in_container,
    const LayoutPoint& accumulated_offset,
    HitTestAction action) {
  return !layout_object_in_flow_thread_->HasSelfPaintingLayer() &&
         layout_object_in_flow_thread_->NodeAtPoint(
             result, location_in_container, accumulated_offset, action);
}

}  // namespace blink