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