1 // Copyright 2018 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h"
6
7 #include "third_party/blink/renderer/core/layout/layout_fieldset.h"
8 #include "third_party/blink/renderer/core/layout/layout_object_factory.h"
9
10 namespace blink {
11
LayoutNGFieldset(Element * element)12 LayoutNGFieldset::LayoutNGFieldset(Element* element)
13 : LayoutNGBlockFlow(element) {
14 SetChildrenInline(false);
15 }
16
AddChild(LayoutObject * new_child,LayoutObject * before_child)17 void LayoutNGFieldset::AddChild(LayoutObject* new_child,
18 LayoutObject* before_child) {
19 LayoutBlock* fieldset_content = To<LayoutBlock>(FirstChild());
20 if (!fieldset_content) {
21 // We wrap everything inside an anonymous child, which will take care of the
22 // fieldset contents. This parent will only be responsible for the fieldset
23 // border and the rendered legend, if there is one. Everything else will be
24 // done by the anonymous child. This includes display type, multicol,
25 // scrollbars, and even padding. Note that the rendered legend (if any) will
26 // also be a child of the anonymous object, although it'd be more natural to
27 // have it as the first child of this object. The reason is that our layout
28 // object tree builder cannot handle such discrepancies between DOM tree and
29 // layout tree. Inserting anonymous wrappers is one thing (that is
30 // supported). Removing it from its actual DOM siblings and putting it
31 // elsewhere, on the other hand, does not work well.
32
33 // TODO(crbug.com/875235): Consider other display types not mentioned in the
34 // spec (ex. EDisplay::kLayoutCustom).
35 EDisplay display = EDisplay::kFlowRoot;
36 switch (StyleRef().Display()) {
37 case EDisplay::kFlex:
38 case EDisplay::kInlineFlex:
39 display = EDisplay::kFlex;
40 break;
41 case EDisplay::kGrid:
42 case EDisplay::kInlineGrid:
43 display = EDisplay::kGrid;
44 break;
45 default:
46 break;
47 }
48
49 fieldset_content =
50 LayoutBlock::CreateAnonymousWithParentAndDisplay(this, display);
51 LayoutBox::AddChild(fieldset_content);
52 }
53 fieldset_content->AddChild(new_child, before_child);
54 }
55
56 // TODO(mstensho): Should probably remove the anonymous child if it becomes
57 // childless. While an empty anonymous child should have no effect, it doesn't
58 // seem right to leave it around.
59
UpdateAnonymousChildStyle(const LayoutObject *,ComputedStyle & child_style) const60 void LayoutNGFieldset::UpdateAnonymousChildStyle(
61 const LayoutObject*,
62 ComputedStyle& child_style) const {
63 // Inherit all properties listed here:
64 // https://html.spec.whatwg.org/C/#anonymous-fieldset-content-box
65
66 child_style.SetAlignContent(StyleRef().AlignContent());
67 child_style.SetAlignItems(StyleRef().AlignItems());
68
69 child_style.SetBorderBottomLeftRadius(StyleRef().BorderBottomLeftRadius());
70 child_style.SetBorderBottomRightRadius(StyleRef().BorderBottomRightRadius());
71 child_style.SetBorderTopLeftRadius(StyleRef().BorderTopLeftRadius());
72 child_style.SetBorderTopRightRadius(StyleRef().BorderTopRightRadius());
73
74 child_style.SetPaddingTop(StyleRef().PaddingTop());
75 child_style.SetPaddingRight(StyleRef().PaddingRight());
76 child_style.SetPaddingBottom(StyleRef().PaddingBottom());
77 child_style.SetPaddingLeft(StyleRef().PaddingLeft());
78
79 if (StyleRef().SpecifiesColumns()) {
80 child_style.SetColumnCount(StyleRef().ColumnCount());
81 child_style.SetColumnWidth(StyleRef().ColumnWidth());
82 } else {
83 child_style.SetHasAutoColumnCount();
84 child_style.SetHasAutoColumnWidth();
85 }
86 child_style.SetColumnGap(StyleRef().ColumnGap());
87 child_style.SetColumnFill(StyleRef().GetColumnFill());
88 child_style.SetColumnRuleColor(StyleColor(
89 LayoutObject::ResolveColor(StyleRef(), GetCSSPropertyColumnRuleColor())));
90 child_style.SetColumnRuleStyle(StyleRef().ColumnRuleStyle());
91 child_style.SetColumnRuleWidth(StyleRef().ColumnRuleWidth());
92
93 child_style.SetFlexDirection(StyleRef().FlexDirection());
94 child_style.SetFlexWrap(StyleRef().FlexWrap());
95
96 child_style.SetGridAutoColumns(StyleRef().GridAutoColumns());
97 child_style.SetGridAutoFlow(StyleRef().GetGridAutoFlow());
98 child_style.SetGridAutoRows(StyleRef().GridAutoRows());
99 child_style.SetGridColumnEnd(StyleRef().GridColumnEnd());
100 child_style.SetGridColumnStart(StyleRef().GridColumnStart());
101 child_style.SetGridRowEnd(StyleRef().GridRowEnd());
102 child_style.SetGridRowStart(StyleRef().GridRowStart());
103 child_style.SetGridTemplateColumns(StyleRef().GridTemplateColumns());
104 child_style.SetGridTemplateRows(StyleRef().GridTemplateRows());
105 child_style.SetNamedGridArea(StyleRef().NamedGridArea());
106 child_style.SetNamedGridAreaColumnCount(
107 StyleRef().NamedGridAreaColumnCount());
108 child_style.SetNamedGridAreaRowCount(StyleRef().NamedGridAreaRowCount());
109 child_style.SetRowGap(StyleRef().RowGap());
110
111 child_style.SetJustifyContent(StyleRef().JustifyContent());
112 child_style.SetJustifyItems(StyleRef().JustifyItems());
113 child_style.SetOverflowX(StyleRef().OverflowX());
114 child_style.SetOverflowY(StyleRef().OverflowY());
115 child_style.SetUnicodeBidi(StyleRef().GetUnicodeBidi());
116
117 // If the FIELDSET is an OOF container, the anonymous content box should be
118 // an OOF container to steal OOF objects under the FIELDSET.
119 if (CanContainFixedPositionObjects())
120 child_style.SetContain(kContainsPaint);
121 else if (StyleRef().CanContainAbsolutePositionObjects())
122 child_style.SetPosition(EPosition::kRelative);
123 }
124
IsOfType(LayoutObjectType type) const125 bool LayoutNGFieldset::IsOfType(LayoutObjectType type) const {
126 return type == kLayoutObjectNGFieldset || LayoutNGBlockFlow::IsOfType(type);
127 }
128
InvalidatePaint(const PaintInvalidatorContext & context) const129 void LayoutNGFieldset::InvalidatePaint(
130 const PaintInvalidatorContext& context) const {
131 // Fieldset's box decoration painting depends on the legend geometry.
132 const LayoutBox* legend_box = LayoutFieldset::FindInFlowLegend(*this);
133 if (legend_box && legend_box->ShouldCheckGeometryForPaintInvalidation()) {
134 GetMutableForPainting().SetShouldDoFullPaintInvalidation(
135 PaintInvalidationReason::kGeometry);
136 }
137 LayoutNGBlockFlow::InvalidatePaint(context);
138 }
139
BackgroundIsKnownToBeOpaqueInRect(const PhysicalRect & local_rect) const140 bool LayoutNGFieldset::BackgroundIsKnownToBeOpaqueInRect(
141 const PhysicalRect& local_rect) const {
142 // If the field set has a legend, then it probably does not completely fill
143 // its background.
144 if (LayoutFieldset::FindInFlowLegend(*this))
145 return false;
146
147 return LayoutBlockFlow::BackgroundIsKnownToBeOpaqueInRect(local_rect);
148 }
149
HitTestChildren(HitTestResult & result,const HitTestLocation & hit_test_location,const PhysicalOffset & accumulated_offset,HitTestAction hit_test_action)150 bool LayoutNGFieldset::HitTestChildren(HitTestResult& result,
151 const HitTestLocation& hit_test_location,
152 const PhysicalOffset& accumulated_offset,
153 HitTestAction hit_test_action) {
154 if (LayoutNGBlockFlow::HitTestChildren(result, hit_test_location,
155 accumulated_offset, hit_test_action))
156 return true;
157
158 DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentTraversalEnabled());
159 LayoutBox* legend = LayoutFieldset::FindInFlowLegend(*this);
160 if (!legend || legend->HasSelfPaintingLayer() || legend->IsColumnSpanAll())
161 return false;
162 if (legend->NodeAtPoint(result, hit_test_location,
163 accumulated_offset + legend->PhysicalLocation(this),
164 hit_test_action == kHitTestChildBlockBackgrounds
165 ? kHitTestChildBlockBackground
166 : hit_test_action)) {
167 UpdateHitTestResult(result, hit_test_location.Point() - accumulated_offset);
168 return true;
169 }
170 return false;
171 }
172
ScrollWidth() const173 LayoutUnit LayoutNGFieldset::ScrollWidth() const {
174 const LayoutObject* child = FirstChild();
175 if (child && child->IsAnonymous())
176 return To<LayoutBox>(child)->ScrollWidth();
177 return LayoutNGBlockFlow::ScrollWidth();
178 }
179
ScrollHeight() const180 LayoutUnit LayoutNGFieldset::ScrollHeight() const {
181 const LayoutObject* child = FirstChild();
182 if (child && child->IsAnonymous())
183 return To<LayoutBox>(child)->ScrollHeight();
184 return LayoutNGBlockFlow::ScrollHeight();
185 }
186
187 } // namespace blink
188