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/layout_object_factory.h"
6
7 #include "third_party/blink/renderer/core/dom/element.h"
8 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
9 #include "third_party/blink/renderer/core/layout/layout_block_flow.h"
10 #include "third_party/blink/renderer/core/layout/layout_button.h"
11 #include "third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h"
12 #include "third_party/blink/renderer/core/layout/layout_fieldset.h"
13 #include "third_party/blink/renderer/core/layout/layout_file_upload_control.h"
14 #include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
15 #include "third_party/blink/renderer/core/layout/layout_grid.h"
16 #include "third_party/blink/renderer/core/layout/layout_inside_list_marker.h"
17 #include "third_party/blink/renderer/core/layout/layout_list_item.h"
18 #include "third_party/blink/renderer/core/layout/layout_list_marker.h"
19 #include "third_party/blink/renderer/core/layout/layout_outside_list_marker.h"
20 #include "third_party/blink/renderer/core/layout/layout_slider_track.h"
21 #include "third_party/blink/renderer/core/layout/layout_table.h"
22 #include "third_party/blink/renderer/core/layout/layout_table_caption.h"
23 #include "third_party/blink/renderer/core/layout/layout_table_cell.h"
24 #include "third_party/blink/renderer/core/layout/layout_table_col.h"
25 #include "third_party/blink/renderer/core/layout/layout_table_row.h"
26 #include "third_party/blink/renderer/core/layout/layout_table_section.h"
27 #include "third_party/blink/renderer/core/layout/layout_text.h"
28 #include "third_party/blink/renderer/core/layout/layout_text_control_multi_line.h"
29 #include "third_party/blink/renderer/core/layout/layout_text_control_single_line.h"
30 #include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
31 #include "third_party/blink/renderer/core/layout/layout_view.h"
32 #include "third_party/blink/renderer/core/layout/ng/flex/layout_ng_flexible_box.h"
33 #include "third_party/blink/renderer/core/layout/ng/grid/layout_ng_grid.h"
34 #include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h"
35 #include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_fragment.h"
36 #include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
37 #include "third_party/blink/renderer/core/layout/ng/layout_ng_button.h"
38 #include "third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h"
39 #include "third_party/blink/renderer/core/layout/ng/layout_ng_progress.h"
40 #include "third_party/blink/renderer/core/layout/ng/layout_ng_ruby_as_block.h"
41 #include "third_party/blink/renderer/core/layout/ng/layout_ng_ruby_text.h"
42 #include "third_party/blink/renderer/core/layout/ng/layout_ng_text_control_inner_editor.h"
43 #include "third_party/blink/renderer/core/layout/ng/layout_ng_text_control_multi_line.h"
44 #include "third_party/blink/renderer/core/layout/ng/layout_ng_text_control_single_line.h"
45 #include "third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h"
46 #include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
47 #include "third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h"
48 #include "third_party/blink/renderer/core/layout/ng/mathml/layout_ng_mathml_block.h"
49 #include "third_party/blink/renderer/core/layout/ng/mathml/layout_ng_mathml_block_flow.h"
50 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table.h"
51 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_caption.h"
52 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell.h"
53 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell_legacy.h"
54 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_column.h"
55 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_row.h"
56 #include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_section.h"
57 #include "third_party/blink/renderer/core/mathml/mathml_element.h"
58 #include "third_party/blink/renderer/core/style/computed_style.h"
59 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
60
61 namespace blink {
62
63 namespace {
64
GetElementForLayoutObject(Node & node)65 inline Element* GetElementForLayoutObject(Node& node) {
66 if (auto* element = DynamicTo<Element>(node))
67 return element;
68 // If |node| is a Document, the layout object is going to be anonymous.
69 DCHECK(node.IsDocumentNode());
70 return nullptr;
71 }
72
73 template <typename BaseType, typename NGType, typename LegacyType = BaseType>
CreateObject(Node & node,const ComputedStyle & style,LegacyLayout legacy,bool disable_ng_for_type=false)74 inline BaseType* CreateObject(Node& node,
75 const ComputedStyle& style,
76 LegacyLayout legacy,
77 bool disable_ng_for_type = false) {
78 Element* element = GetElementForLayoutObject(node);
79 bool force_legacy = false;
80
81 // If no reason has been found for disabling NG for this particular type,
82 // check if the NG feature is enabled at all, before considering creating an
83 // NG object.
84 if (!disable_ng_for_type && RuntimeEnabledFeatures::LayoutNGEnabled()) {
85 // The last thing to check is whether we should force legacy layout. This
86 // happens when the NG feature is enabled for the object in question, but
87 // we're dealing with something that isn't implemented in NG yet (such as
88 // editing or multicol). We then need to force legacy layout for the entire
89 // subtree.
90 force_legacy = legacy == LegacyLayout::kForce;
91
92 if (!force_legacy)
93 return new NGType(element);
94 }
95 BaseType* new_object = new LegacyType(element);
96 if (force_legacy)
97 new_object->SetForceLegacyLayout();
98 return new_object;
99 }
100
101 } // anonymous namespace
102
CreateBlockFlow(Node & node,const ComputedStyle & style,LegacyLayout legacy)103 LayoutBlockFlow* LayoutObjectFactory::CreateBlockFlow(
104 Node& node,
105 const ComputedStyle& style,
106 LegacyLayout legacy) {
107 if (style.Display() == EDisplay::kListItem) {
108 // Create a LayoutBlockFlow with a list marker
109 return CreateObject<LayoutBlockFlow, LayoutNGListItem, LayoutListItem>(
110 node, style, legacy);
111 }
112
113 // Create a plain LayoutBlockFlow
114 return CreateObject<LayoutBlockFlow, LayoutNGBlockFlow>(node, style, legacy);
115 }
116
117 // static
CreateBlockForLineClamp(Node & node,const ComputedStyle & style,LegacyLayout legacy)118 LayoutBlock* LayoutObjectFactory::CreateBlockForLineClamp(
119 Node& node,
120 const ComputedStyle& style,
121 LegacyLayout legacy) {
122 return CreateObject<LayoutBlock, LayoutNGBlockFlow,
123 LayoutDeprecatedFlexibleBox>(node, style, legacy);
124 }
125
CreateFlexibleBox(Node & node,const ComputedStyle & style,LegacyLayout legacy)126 LayoutBlock* LayoutObjectFactory::CreateFlexibleBox(Node& node,
127 const ComputedStyle& style,
128 LegacyLayout legacy) {
129 return CreateObject<LayoutBlock, LayoutNGFlexibleBox, LayoutFlexibleBox>(
130 node, style, legacy);
131 }
132
CreateGrid(Node & node,const ComputedStyle & style,LegacyLayout legacy)133 LayoutBlock* LayoutObjectFactory::CreateGrid(Node& node,
134 const ComputedStyle& style,
135 LegacyLayout legacy) {
136 bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGGridEnabled();
137 if (disable_ng_for_type)
138 UseCounter::Count(node.GetDocument(), WebFeature::kLegacyLayoutByGrid);
139 return CreateObject<LayoutBlock, LayoutNGGrid, LayoutGrid>(
140 node, style, legacy, disable_ng_for_type);
141 }
142
CreateMath(Node & node,const ComputedStyle & style,LegacyLayout legacy)143 LayoutBlock* LayoutObjectFactory::CreateMath(Node& node,
144 const ComputedStyle& style,
145 LegacyLayout legacy) {
146 DCHECK(IsA<MathMLElement>(node));
147 DCHECK_NE(legacy, LegacyLayout::kForce);
148 bool disable_ng_for_type = !RuntimeEnabledFeatures::MathMLCoreEnabled();
149 if (To<MathMLElement>(node).IsTokenElement()) {
150 return CreateObject<LayoutBlockFlow, LayoutNGMathMLBlockFlow,
151 LayoutBlockFlow>(node, style, legacy,
152 disable_ng_for_type);
153 }
154 return CreateObject<LayoutBlock, LayoutNGMathMLBlock, LayoutBlockFlow>(
155 node, style, legacy, disable_ng_for_type);
156 }
157
CreateListMarker(Node & node,const ComputedStyle & style,LegacyLayout legacy)158 LayoutObject* LayoutObjectFactory::CreateListMarker(Node& node,
159 const ComputedStyle& style,
160 LegacyLayout legacy) {
161 const Node* parent = node.parentNode();
162 const ComputedStyle* parent_style = parent->GetComputedStyle();
163 bool is_inside =
164 parent_style->ListStylePosition() == EListStylePosition::kInside ||
165 (IsA<HTMLLIElement>(parent) && !parent_style->IsInsideListElement());
166 if (style.ContentBehavesAsNormal()) {
167 if (is_inside) {
168 return CreateObject<LayoutObject, LayoutNGInsideListMarker,
169 LayoutListMarker>(node, style, legacy);
170 }
171 return CreateObject<LayoutObject, LayoutNGOutsideListMarker,
172 LayoutListMarker>(node, style, legacy);
173 }
174 if (is_inside) {
175 return CreateObject<LayoutObject, LayoutNGInsideListMarker,
176 LayoutInsideListMarker>(node, style, legacy);
177 }
178 return CreateObject<LayoutObject, LayoutNGOutsideListMarker,
179 LayoutOutsideListMarker>(node, style, legacy);
180 }
181
CreateTable(Node & node,const ComputedStyle & style,LegacyLayout legacy)182 LayoutBlock* LayoutObjectFactory::CreateTable(Node& node,
183 const ComputedStyle& style,
184 LegacyLayout legacy) {
185 bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGTableEnabled();
186 if (disable_ng_for_type)
187 UseCounter::Count(node.GetDocument(), WebFeature::kLegacyLayoutByTable);
188 return CreateObject<LayoutBlock, LayoutNGTable, LayoutTable>(
189 node, style, legacy, disable_ng_for_type);
190 }
191
CreateTableCaption(Node & node,const ComputedStyle & style,LegacyLayout legacy)192 LayoutTableCaption* LayoutObjectFactory::CreateTableCaption(
193 Node& node,
194 const ComputedStyle& style,
195 LegacyLayout legacy) {
196 return CreateObject<LayoutTableCaption, LayoutNGTableCaption>(node, style,
197 legacy);
198 }
199
CreateTableCell(Node & node,const ComputedStyle & style,LegacyLayout legacy)200 LayoutBlockFlow* LayoutObjectFactory::CreateTableCell(
201 Node& node,
202 const ComputedStyle& style,
203 LegacyLayout legacy) {
204 if (RuntimeEnabledFeatures::LayoutNGTableEnabled()) {
205 return CreateObject<LayoutBlockFlow, LayoutNGTableCell, LayoutTableCell>(
206 node, style, legacy);
207 } else {
208 return CreateObject<LayoutBlockFlow, LayoutNGTableCellLegacy,
209 LayoutTableCell>(node, style, legacy);
210 }
211 }
212
CreateTableColumn(Node & node,const ComputedStyle & style,LegacyLayout legacy)213 LayoutBox* LayoutObjectFactory::CreateTableColumn(Node& node,
214 const ComputedStyle& style,
215 LegacyLayout legacy) {
216 bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGTableEnabled();
217 if (disable_ng_for_type)
218 UseCounter::Count(node.GetDocument(), WebFeature::kLegacyLayoutByTable);
219 return CreateObject<LayoutBox, LayoutNGTableColumn, LayoutTableCol>(
220 node, style, legacy, disable_ng_for_type);
221 }
222
CreateTableRow(Node & node,const ComputedStyle & style,LegacyLayout legacy)223 LayoutBox* LayoutObjectFactory::CreateTableRow(Node& node,
224 const ComputedStyle& style,
225 LegacyLayout legacy) {
226 bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGTableEnabled();
227 if (disable_ng_for_type)
228 UseCounter::Count(node.GetDocument(), WebFeature::kLegacyLayoutByTable);
229 return CreateObject<LayoutBox, LayoutNGTableRow, LayoutTableRow>(
230 node, style, legacy, disable_ng_for_type);
231 }
232
CreateTableSection(Node & node,const ComputedStyle & style,LegacyLayout legacy)233 LayoutBox* LayoutObjectFactory::CreateTableSection(Node& node,
234 const ComputedStyle& style,
235 LegacyLayout legacy) {
236 bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGTableEnabled();
237 if (disable_ng_for_type)
238 UseCounter::Count(node.GetDocument(), WebFeature::kLegacyLayoutByTable);
239 return CreateObject<LayoutBox, LayoutNGTableSection, LayoutTableSection>(
240 node, style, legacy, disable_ng_for_type);
241 }
242
CreateButton(Node & node,const ComputedStyle & style,LegacyLayout legacy)243 LayoutObject* LayoutObjectFactory::CreateButton(Node& node,
244 const ComputedStyle& style,
245 LegacyLayout legacy) {
246 return CreateObject<LayoutBlock, LayoutNGButton, LayoutButton>(node, style,
247 legacy);
248 }
249
CreateFieldset(Node & node,const ComputedStyle & style,LegacyLayout legacy)250 LayoutBlock* LayoutObjectFactory::CreateFieldset(Node& node,
251 const ComputedStyle& style,
252 LegacyLayout legacy) {
253 bool disable_ng_for_type = !RuntimeEnabledFeatures::LayoutNGFieldsetEnabled();
254 if (disable_ng_for_type)
255 UseCounter::Count(node.GetDocument(), WebFeature::kLegacyLayoutByFieldSet);
256 return CreateObject<LayoutBlock, LayoutNGFieldset, LayoutFieldset>(
257 node, style, legacy, disable_ng_for_type);
258 }
259
CreateFileUploadControl(Node & node,const ComputedStyle & style,LegacyLayout legacy)260 LayoutBlockFlow* LayoutObjectFactory::CreateFileUploadControl(
261 Node& node,
262 const ComputedStyle& style,
263 LegacyLayout legacy) {
264 return CreateObject<LayoutBlockFlow, LayoutNGBlockFlow,
265 LayoutFileUploadControl>(node, style, legacy);
266 }
267
CreateSliderTrack(Node & node,const ComputedStyle & style,LegacyLayout legacy)268 LayoutObject* LayoutObjectFactory::CreateSliderTrack(Node& node,
269 const ComputedStyle& style,
270 LegacyLayout legacy) {
271 return CreateObject<LayoutBlock, LayoutNGBlockFlow, LayoutSliderTrack>(
272 node, style, legacy);
273 }
274
CreateTextControlInnerEditor(Node & node,const ComputedStyle & style,LegacyLayout legacy)275 LayoutObject* LayoutObjectFactory::CreateTextControlInnerEditor(
276 Node& node,
277 const ComputedStyle& style,
278 LegacyLayout legacy) {
279 return CreateObject<LayoutBlockFlow, LayoutNGTextControlInnerEditor,
280 LayoutTextControlInnerEditor>(node, style, legacy);
281 }
282
CreateTextControlMultiLine(Node & node,const ComputedStyle & style,LegacyLayout legacy)283 LayoutObject* LayoutObjectFactory::CreateTextControlMultiLine(
284 Node& node,
285 const ComputedStyle& style,
286 LegacyLayout legacy) {
287 return CreateObject<LayoutBlockFlow, LayoutNGTextControlMultiLine,
288 LayoutTextControlMultiLine>(node, style, legacy);
289 }
290
CreateTextControlSingleLine(Node & node,const ComputedStyle & style,LegacyLayout legacy)291 LayoutObject* LayoutObjectFactory::CreateTextControlSingleLine(
292 Node& node,
293 const ComputedStyle& style,
294 LegacyLayout legacy) {
295 return CreateObject<LayoutBlockFlow, LayoutNGTextControlSingleLine,
296 LayoutTextControlSingleLine>(node, style, legacy);
297 }
298
CreateText(Node * node,scoped_refptr<StringImpl> str,LegacyLayout legacy)299 LayoutText* LayoutObjectFactory::CreateText(Node* node,
300 scoped_refptr<StringImpl> str,
301 LegacyLayout legacy) {
302 bool force_legacy = false;
303 if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
304 force_legacy = legacy == LegacyLayout::kForce;
305 if (!force_legacy)
306 return new LayoutNGText(node, str);
307 }
308 LayoutText* layout_text = new LayoutText(node, str);
309 if (force_legacy)
310 layout_text->SetForceLegacyLayout();
311 return layout_text;
312 }
313
CreateTextFragment(Node * node,StringImpl * str,int start_offset,int length,LegacyLayout legacy)314 LayoutTextFragment* LayoutObjectFactory::CreateTextFragment(
315 Node* node,
316 StringImpl* str,
317 int start_offset,
318 int length,
319 LegacyLayout legacy) {
320 bool force_legacy = false;
321 if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
322 force_legacy = legacy == LegacyLayout::kForce;
323 if (!force_legacy)
324 return new LayoutNGTextFragment(node, str, start_offset, length);
325 }
326 LayoutTextFragment* layout_text_fragment =
327 new LayoutTextFragment(node, str, start_offset, length);
328 if (force_legacy)
329 layout_text_fragment->SetForceLegacyLayout();
330 return layout_text_fragment;
331 }
332
CreateProgress(Node * node,const ComputedStyle & style,LegacyLayout legacy)333 LayoutProgress* LayoutObjectFactory::CreateProgress(Node* node,
334 const ComputedStyle& style,
335 LegacyLayout legacy) {
336 return CreateObject<LayoutProgress, LayoutNGProgress>(*node, style, legacy);
337 }
338
CreateRubyAsBlock(Node * node,const ComputedStyle & style,LegacyLayout legacy)339 LayoutRubyAsBlock* LayoutObjectFactory::CreateRubyAsBlock(
340 Node* node,
341 const ComputedStyle& style,
342 LegacyLayout legacy) {
343 return CreateObject<LayoutRubyAsBlock, LayoutNGRubyAsBlock>(*node, style,
344 legacy);
345 }
346
CreateRubyText(Node * node,const ComputedStyle & style,LegacyLayout legacy)347 LayoutObject* LayoutObjectFactory::CreateRubyText(Node* node,
348 const ComputedStyle& style,
349 LegacyLayout legacy) {
350 return CreateObject<LayoutRubyText, LayoutNGRubyText>(*node, style, legacy);
351 }
352
CreateAnonymousTableWithParent(const LayoutObject & parent)353 LayoutBox* LayoutObjectFactory::CreateAnonymousTableWithParent(
354 const LayoutObject& parent) {
355 scoped_refptr<ComputedStyle> new_style =
356 ComputedStyle::CreateAnonymousStyleWithDisplay(
357 parent.StyleRef(),
358 parent.IsLayoutInline() ? EDisplay::kInlineTable : EDisplay::kTable);
359 LegacyLayout legacy =
360 parent.ForceLegacyLayout() ? LegacyLayout::kForce : LegacyLayout::kAuto;
361
362 LayoutBlock* new_table =
363 CreateTable(parent.GetDocument(), *new_style, legacy);
364 new_table->SetDocumentForAnonymous(&parent.GetDocument());
365 new_table->SetStyle(std::move(new_style));
366 return new_table;
367 }
368
CreateAnonymousTableSectionWithParent(const LayoutObject & parent)369 LayoutBox* LayoutObjectFactory::CreateAnonymousTableSectionWithParent(
370 const LayoutObject& parent) {
371 scoped_refptr<ComputedStyle> new_style =
372 ComputedStyle::CreateAnonymousStyleWithDisplay(parent.StyleRef(),
373 EDisplay::kTableRowGroup);
374 LegacyLayout legacy =
375 parent.ForceLegacyLayout() ? LegacyLayout::kForce : LegacyLayout::kAuto;
376
377 LayoutBox* new_section =
378 CreateTableSection(parent.GetDocument(), *new_style, legacy);
379 new_section->SetDocumentForAnonymous(&parent.GetDocument());
380 new_section->SetStyle(std::move(new_style));
381 return new_section;
382 }
383
CreateAnonymousTableRowWithParent(const LayoutObject & parent)384 LayoutBox* LayoutObjectFactory::CreateAnonymousTableRowWithParent(
385 const LayoutObject& parent) {
386 scoped_refptr<ComputedStyle> new_style =
387 ComputedStyle::CreateAnonymousStyleWithDisplay(parent.StyleRef(),
388 EDisplay::kTableRow);
389 LegacyLayout legacy =
390 parent.ForceLegacyLayout() ? LegacyLayout::kForce : LegacyLayout::kAuto;
391 LayoutBox* new_row = CreateTableRow(parent.GetDocument(), *new_style, legacy);
392 new_row->SetDocumentForAnonymous(&parent.GetDocument());
393 new_row->SetStyle(std::move(new_style));
394 return new_row;
395 }
396
CreateAnonymousTableCellWithParent(const LayoutObject & parent)397 LayoutBlockFlow* LayoutObjectFactory::CreateAnonymousTableCellWithParent(
398 const LayoutObject& parent) {
399 scoped_refptr<ComputedStyle> new_style =
400 ComputedStyle::CreateAnonymousStyleWithDisplay(parent.StyleRef(),
401 EDisplay::kTableCell);
402 LegacyLayout legacy =
403 parent.ForceLegacyLayout() ? LegacyLayout::kForce : LegacyLayout::kAuto;
404 LayoutBlockFlow* new_cell =
405 CreateTableCell(parent.GetDocument(), *new_style, legacy);
406 new_cell->SetDocumentForAnonymous(&parent.GetDocument());
407 new_cell->SetStyle(std::move(new_style));
408 return new_cell;
409 }
410
411 } // namespace blink
412