summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-07-16 11:45:35 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-07-17 08:59:23 +0000
commit552906b0f222c5d5dd11b9fd73829d510980461a (patch)
tree3a11e6ed0538a81dd83b20cf3a4783e297f26d91 /chromium/third_party/blink/renderer/core/layout
parent1b05827804eaf047779b597718c03e7d38344261 (diff)
downloadqtwebengine-chromium-552906b0f222c5d5dd11b9fd73829d510980461a.tar.gz
BASELINE: Update Chromium to 83.0.4103.122
Change-Id: Ie3a82f5bb0076eec2a7c6a6162326b4301ee291e Reviewed-by: Michael Brüning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/core/layout')
-rw-r--r--chromium/third_party/blink/renderer/core/layout/BUILD.gn38
-rw-r--r--chromium/third_party/blink/renderer/core/layout/DEPS2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/api/line_layout_list_marker.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom_scrollbar.cc63
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom_scrollbar.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc235
-rw-r--r--chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.h49
-rw-r--r--chromium/third_party/blink/renderer/core/layout/floating_objects.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/floating_objects.h9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/generated_children.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/geometry/physical_offset.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.h9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc54
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_cache.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_cache.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_canvas_result.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_canvas_result.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_location.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_location.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_result.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_result.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block.cc179
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block.h28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc542
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_flow.h44
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc80
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box.cc680
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box.h195
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc59
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_button.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_button.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_counter.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc430
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_details_marker.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_embedded_content.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_embedded_content.h9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_fieldset.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.cc155
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.h23
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc134
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_flexible_box_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_flow_thread.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_frame_set.h14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_geometry_map.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_grid.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_grid.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_html_canvas.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_iframe.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image_resource.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_inline.cc96
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_inline.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_inline_test.cc129
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_inside_list_marker.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_inside_list_marker.h33
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_box.cc156
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_box.h76
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_item.cc147
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_item.h15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc224
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_marker.h32
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_media.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_media.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_menu_list.cc374
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_menu_list.h127
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object.cc468
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object.h305
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object_factory.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object_factory.h9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.h33
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_replaced.cc72
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_replaced.h10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_replaced_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_ruby_base.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_ruby_text.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_search_field.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_search_field.h51
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.cc226
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.h52
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_slider.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_slider.h17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_slider_container.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_slider_container.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_state.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_state.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table.cc99
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_caption.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_cell.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_cell_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_col.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_col.h14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_row.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_row.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_section.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_section.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_test.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text.cc162
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text.h15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_combine.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control.cc66
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control.h42
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control_multi_line.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.h21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line_test.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_fragment_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme.cc85
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme.h30
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_default.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_default.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_mac.h10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_mac.mm292
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_test.cc94
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_video.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_video.h9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_view.cc83
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_view.h34
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_view_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_vtt_cue.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box_test.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/inline_box.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/inline_box.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/map_coordinates_test.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/layout/min_max_size_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/min_max_sizes.cc (renamed from chromium/third_party/blink/renderer/core/layout/min_max_size.cc)4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/min_max_sizes.h (renamed from chromium/third_party/blink/renderer/core/layout/min_max_size.h)20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.cc205
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.h44
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/custom_intrinsic_sizes.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/custom_intrinsic_sizes.h53
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.cc35
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_scope.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.cc77
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.h31
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/document_layout_definition.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/document_layout_definition.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/fragment_result_options.idl1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/intrinsic_sizes.idl15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/intrinsic_sizes_result_options.idl10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_child.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_fragment.idl2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.cc79
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_test.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc295
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h36
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.cc89
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h207
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_baseline_test.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc48
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc60
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc202
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h108
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc57
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc113
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc315
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h32
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h22
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc1024
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h301
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc122
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc93
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h26
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc219
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc193
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h55
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc123
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h58
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc234
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc192
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc368
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h42
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc83
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h38
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc26
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_end_effect.h20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc206
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc125
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_progress.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/README.md9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc399
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h40
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.cc61
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h (renamed from chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h)28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/list_marker.cc256
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/list_marker.h71
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc60
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/layout_ng_mathml_block.cc46
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/layout_ng_mathml_block.h29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.cc323
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.h31
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc97
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.h54
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.cc180
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.h42
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.h31
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc70
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h36
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils_test.cc443
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_child_iterator_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc427
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h48
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc133
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc358
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.h42
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_node_test.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.cc73
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h37
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc182
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h67
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc119
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h23
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc358
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc37
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h339
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h75
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc64
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc434
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h56
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc1517
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_flex_child_iterator.cc38
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_flex_child_iterator.h53
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc858
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h30
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.cc212
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h141
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator_test.cc808
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_test.cc197
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc44
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc69
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h42
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h48
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc331
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc55
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc257
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h153
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc40
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc135
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc264
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h79
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment_test.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc135
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h105
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/scroll_anchor.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/scroll_anchor_test.cc110
-rw-r--r--chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc178
-rw-r--r--chromium/third_party/blink/renderer/core/layout/shapes/shape.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/layout/shapes/shape.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/BUILD.gn4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.cc (renamed from chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter_primitive.cc)20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.h (renamed from chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter_primitive.h)34
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h26
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc62
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h37
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc91
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h66
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc79
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.h16
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_linear_gradient.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_linear_gradient.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc85
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc82
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.h9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_flow_box.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.h9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc22
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_marker_data.cc122
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_marker_data.h17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc319
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources.h64
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc66
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.cc95
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h43
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc42
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_text_query.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc32
-rw-r--r--chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/layout/text_autosizer.cc64
-rw-r--r--chromium/third_party/blink/renderer/core/layout/text_autosizer.h14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/text_autosizer_test.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc17
434 files changed, 17225 insertions, 10894 deletions
diff --git a/chromium/third_party/blink/renderer/core/layout/BUILD.gn b/chromium/third_party/blink/renderer/core/layout/BUILD.gn
index c7a4d88018b..cb2f84ebd46 100644
--- a/chromium/third_party/blink/renderer/core/layout/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/layout/BUILD.gn
@@ -139,16 +139,14 @@ blink_core_sources("layout") {
"layout_image_resource_style_image.h",
"layout_inline.cc",
"layout_inline.h",
- "layout_list_box.cc",
- "layout_list_box.h",
+ "layout_inside_list_marker.cc",
+ "layout_inside_list_marker.h",
"layout_list_item.cc",
"layout_list_item.h",
"layout_list_marker.cc",
"layout_list_marker.h",
"layout_media.cc",
"layout_media.h",
- "layout_menu_list.cc",
- "layout_menu_list.h",
"layout_multi_column_flow_thread.cc",
"layout_multi_column_flow_thread.h",
"layout_multi_column_set.cc",
@@ -162,6 +160,8 @@ blink_core_sources("layout") {
"layout_object_factory.cc",
"layout_object_factory.h",
"layout_object_inlines.h",
+ "layout_outside_list_marker.cc",
+ "layout_outside_list_marker.h",
"layout_progress.cc",
"layout_progress.h",
"layout_quote.cc",
@@ -176,8 +176,6 @@ blink_core_sources("layout") {
"layout_ruby_run.h",
"layout_ruby_text.cc",
"layout_ruby_text.h",
- "layout_search_field.cc",
- "layout_search_field.h",
"layout_shift_region.cc",
"layout_shift_region.h",
"layout_shift_tracker.cc",
@@ -267,14 +265,16 @@ blink_core_sources("layout") {
"list_marker_text.cc",
"list_marker_text.h",
"map_coordinates_flags.h",
- "min_max_size.cc",
- "min_max_size.h",
+ "min_max_sizes.cc",
+ "min_max_sizes.h",
"multi_column_fragmentainer_group.cc",
"multi_column_fragmentainer_group.h",
"ng/custom/css_layout_definition.cc",
"ng/custom/css_layout_definition.h",
"ng/custom/css_layout_worklet.cc",
"ng/custom/css_layout_worklet.h",
+ "ng/custom/custom_intrinsic_sizes.cc",
+ "ng/custom/custom_intrinsic_sizes.h",
"ng/custom/custom_layout_child.cc",
"ng/custom/custom_layout_child.h",
"ng/custom/custom_layout_constraints.cc",
@@ -323,8 +323,6 @@ blink_core_sources("layout") {
"ng/inline/layout_ng_text_fragment.h",
"ng/inline/ng_abstract_inline_text_box.cc",
"ng/inline/ng_abstract_inline_text_box.h",
- "ng/inline/ng_baseline.cc",
- "ng/inline/ng_baseline.h",
"ng/inline/ng_bidi_paragraph.cc",
"ng/inline/ng_bidi_paragraph.h",
"ng/inline/ng_caret_position.cc",
@@ -411,12 +409,24 @@ blink_core_sources("layout") {
"ng/list/layout_ng_inside_list_marker.h",
"ng/list/layout_ng_list_item.cc",
"ng/list/layout_ng_list_item.h",
- "ng/list/layout_ng_list_marker.cc",
- "ng/list/layout_ng_list_marker.h",
"ng/list/layout_ng_list_marker_image.cc",
"ng/list/layout_ng_list_marker_image.h",
+ "ng/list/layout_ng_outside_list_marker.cc",
+ "ng/list/layout_ng_outside_list_marker.h",
+ "ng/list/list_marker.cc",
+ "ng/list/list_marker.h",
"ng/list/ng_unpositioned_list_marker.cc",
"ng/list/ng_unpositioned_list_marker.h",
+ "ng/mathml/layout_ng_mathml_block.cc",
+ "ng/mathml/layout_ng_mathml_block.h",
+ "ng/mathml/ng_math_fraction_layout_algorithm.cc",
+ "ng/mathml/ng_math_fraction_layout_algorithm.h",
+ "ng/mathml/ng_math_layout_utils.cc",
+ "ng/mathml/ng_math_layout_utils.h",
+ "ng/mathml/ng_math_row_layout_algorithm.cc",
+ "ng/mathml/ng_math_row_layout_algorithm.h",
+ "ng/mathml/ng_math_space_layout_algorithm.cc",
+ "ng/mathml/ng_math_space_layout_algorithm.h",
"ng/ng_absolute_utils.cc",
"ng/ng_absolute_utils.h",
"ng/ng_block_break_token.cc",
@@ -447,12 +457,16 @@ blink_core_sources("layout") {
"ng/ng_early_break.h",
"ng/ng_fieldset_layout_algorithm.cc",
"ng/ng_fieldset_layout_algorithm.h",
+ "ng/ng_flex_child_iterator.cc",
+ "ng/ng_flex_child_iterator.h",
"ng/ng_flex_layout_algorithm.cc",
"ng/ng_flex_layout_algorithm.h",
"ng/ng_floats_utils.cc",
"ng/ng_floats_utils.h",
"ng/ng_fragment.h",
"ng/ng_fragment_builder.h",
+ "ng/ng_fragment_child_iterator.cc",
+ "ng/ng_fragment_child_iterator.h",
"ng/ng_fragmentation_utils.cc",
"ng/ng_fragmentation_utils.h",
"ng/ng_ink_overflow.cc",
diff --git a/chromium/third_party/blink/renderer/core/layout/DEPS b/chromium/third_party/blink/renderer/core/layout/DEPS
index 3b34fd02b70..98473842d29 100644
--- a/chromium/third_party/blink/renderer/core/layout/DEPS
+++ b/chromium/third_party/blink/renderer/core/layout/DEPS
@@ -1,5 +1,5 @@
specific_include_rules = {
- "layout_theme\.cc": [
+ "layout_theme\.cc|layout_theme_mac\.mm": [
"+ui/native_theme/native_theme.h",
],
}
diff --git a/chromium/third_party/blink/renderer/core/layout/api/line_layout_list_marker.h b/chromium/third_party/blink/renderer/core/layout/api/line_layout_list_marker.h
index f78350e836f..f5cc4ed4fcd 100644
--- a/chromium/third_party/blink/renderer/core/layout/api/line_layout_list_marker.h
+++ b/chromium/third_party/blink/renderer/core/layout/api/line_layout_list_marker.h
@@ -24,16 +24,7 @@ class LineLayoutListMarker : public LineLayoutBox {
LineLayoutListMarker() = default;
- bool IsInside() const { return ToListMarker()->IsInside(); }
-
- private:
- LayoutListMarker* ToListMarker() {
- return ToLayoutListMarker(GetLayoutObject());
- }
-
- const LayoutListMarker* ToListMarker() const {
- return ToLayoutListMarker(GetLayoutObject());
- }
+ bool IsInside() const { return GetLayoutObject()->IsInsideListMarker(); }
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/custom_scrollbar.cc b/chromium/third_party/blink/renderer/core/layout/custom_scrollbar.cc
index 456ffcf24d8..5136d0d40a3 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom_scrollbar.cc
+++ b/chromium/third_party/blink/renderer/core/layout/custom_scrollbar.cc
@@ -36,14 +36,6 @@
namespace blink {
-Scrollbar* CustomScrollbar::CreateCustomScrollbar(
- ScrollableArea* scrollable_area,
- ScrollbarOrientation orientation,
- Element* style_source) {
- return MakeGarbageCollected<CustomScrollbar>(scrollable_area, orientation,
- style_source);
-}
-
CustomScrollbar::CustomScrollbar(ScrollableArea* scrollable_area,
ScrollbarOrientation orientation,
Element* style_source)
@@ -104,7 +96,7 @@ int CustomScrollbar::HypotheticalScrollbarThickness(
enclosing_box.ClientWidth().ToInt(), part_style.get());
}
-void CustomScrollbar::Trace(blink::Visitor* visitor) {
+void CustomScrollbar::Trace(Visitor* visitor) {
Scrollbar::Trace(visitor);
}
@@ -150,14 +142,18 @@ void CustomScrollbar::SetPressedPart(ScrollbarPart part,
UpdateScrollbarPart(kTrackBGPart);
}
-scoped_refptr<ComputedStyle> CustomScrollbar::GetScrollbarPseudoElementStyle(
- ScrollbarPart part_type,
- PseudoId pseudo_id) {
+scoped_refptr<const ComputedStyle>
+CustomScrollbar::GetScrollbarPseudoElementStyle(ScrollbarPart part_type,
+ PseudoId pseudo_id) {
if (!StyleSource()->GetLayoutObject())
return nullptr;
- return StyleSource()->StyleForPseudoElement(
- PseudoElementStyleRequest(pseudo_id, this, part_type),
- StyleSource()->GetLayoutObject()->Style());
+ const ComputedStyle* source_style = StyleSource()->GetLayoutObject()->Style();
+ scoped_refptr<const ComputedStyle> part_style =
+ StyleSource()->StyleForPseudoElement(
+ PseudoElementStyleRequest(pseudo_id, this, part_type), source_style);
+ if (!part_style)
+ return nullptr;
+ return source_style->AddCachedPseudoElementStyle(std::move(part_style));
}
void CustomScrollbar::UpdateScrollbarParts(bool destroy) {
@@ -236,41 +232,28 @@ void CustomScrollbar::UpdateScrollbarPart(ScrollbarPart part_type,
if (part_type == kNoPart)
return;
- scoped_refptr<ComputedStyle> part_style =
+ scoped_refptr<const ComputedStyle> part_style =
!destroy ? GetScrollbarPseudoElementStyle(
part_type, PseudoForScrollbarPart(part_type))
- : scoped_refptr<ComputedStyle>(nullptr);
+ : scoped_refptr<const ComputedStyle>(nullptr);
bool need_layout_object =
!destroy && part_style && part_style->Display() != EDisplay::kNone;
- if (need_layout_object && part_style->Display() != EDisplay::kBlock) {
- // See if we are a button that should not be visible according to OS
- // settings.
- WebScrollbarButtonsPlacement buttons_placement =
- GetTheme().ButtonsPlacement();
+ if (need_layout_object &&
+ // display:block overrides OS settings.
+ part_style->Display() != EDisplay::kBlock) {
+ // If not display:block, visibility of buttons depends on OS settings.
switch (part_type) {
case kBackButtonStartPart:
- need_layout_object =
- (buttons_placement == kWebScrollbarButtonsPlacementSingle ||
- buttons_placement == kWebScrollbarButtonsPlacementDoubleStart ||
- buttons_placement == kWebScrollbarButtonsPlacementDoubleBoth);
- break;
- case kForwardButtonStartPart:
- need_layout_object =
- (buttons_placement == kWebScrollbarButtonsPlacementDoubleStart ||
- buttons_placement == kWebScrollbarButtonsPlacementDoubleBoth);
+ case kForwardButtonEndPart:
+ // Create buttons only if the OS theme has scrollbar buttons.
+ need_layout_object = GetTheme().NativeThemeHasButtons();
break;
case kBackButtonEndPart:
- need_layout_object =
- (buttons_placement == kWebScrollbarButtonsPlacementDoubleEnd ||
- buttons_placement == kWebScrollbarButtonsPlacementDoubleBoth);
- break;
- case kForwardButtonEndPart:
- need_layout_object =
- (buttons_placement == kWebScrollbarButtonsPlacementSingle ||
- buttons_placement == kWebScrollbarButtonsPlacementDoubleEnd ||
- buttons_placement == kWebScrollbarButtonsPlacementDoubleBoth);
+ case kForwardButtonStartPart:
+ // These buttons are not supported by any OS.
+ need_layout_object = false;
break;
default:
break;
diff --git a/chromium/third_party/blink/renderer/core/layout/custom_scrollbar.h b/chromium/third_party/blink/renderer/core/layout/custom_scrollbar.h
index 6f097019e0f..734cb2d7931 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom_scrollbar.h
+++ b/chromium/third_party/blink/renderer/core/layout/custom_scrollbar.h
@@ -45,10 +45,6 @@ class LayoutObject;
// LayoutCustomScrollbarPart.
class CustomScrollbar final : public Scrollbar {
public:
- static Scrollbar* CreateCustomScrollbar(ScrollableArea*,
- ScrollbarOrientation,
- Element*);
-
CustomScrollbar(ScrollableArea*, ScrollbarOrientation, Element*);
~CustomScrollbar() override;
@@ -77,7 +73,7 @@ class CustomScrollbar final : public Scrollbar {
void SetVisualRect(const IntRect&) final;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
friend class Scrollbar;
@@ -94,8 +90,9 @@ class CustomScrollbar final : public Scrollbar {
void UpdateScrollbarParts(bool destroy = false);
- scoped_refptr<ComputedStyle> GetScrollbarPseudoElementStyle(ScrollbarPart,
- PseudoId);
+ scoped_refptr<const ComputedStyle> GetScrollbarPseudoElementStyle(
+ ScrollbarPart,
+ PseudoId);
void UpdateScrollbarPart(ScrollbarPart, bool destroy = false);
HashMap<unsigned, LayoutCustomScrollbarPart*> parts_;
diff --git a/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
index e5556b46d71..ebc3d542dff 100644
--- a/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.cc
@@ -32,7 +32,8 @@
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
-#include "third_party/blink/renderer/core/layout/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
namespace blink {
namespace {
@@ -72,77 +73,97 @@ ContentDistributionType BoxPackToContentDistribution(EBoxPack box_pack) {
} // namespace
-FlexItem::FlexItem(LayoutBox* box,
+FlexItem::FlexItem(const FlexLayoutAlgorithm* algorithm,
+ LayoutBox* box,
+ const ComputedStyle& style,
LayoutUnit flex_base_content_size,
- MinMaxSize min_max_sizes,
- base::Optional<MinMaxSize> min_max_cross_axis_sizes,
+ MinMaxSizes min_max_main_sizes,
+ base::Optional<MinMaxSizes> min_max_cross_sizes,
LayoutUnit main_axis_border_padding,
- LayoutUnit main_axis_margin)
- : algorithm(nullptr),
+ LayoutUnit cross_axis_border_padding,
+ NGPhysicalBoxStrut physical_margins)
+ : algorithm(algorithm),
line_number(0),
box(box),
+ style(style),
flex_base_content_size(flex_base_content_size),
- min_max_sizes(min_max_sizes),
- min_max_cross_sizes(min_max_cross_axis_sizes),
+ min_max_main_sizes(min_max_main_sizes),
+ min_max_cross_sizes(min_max_cross_sizes),
hypothetical_main_content_size(
- min_max_sizes.ClampSizeToMinAndMax(flex_base_content_size)),
+ min_max_main_sizes.ClampSizeToMinAndMax(flex_base_content_size)),
main_axis_border_padding(main_axis_border_padding),
- main_axis_margin(main_axis_margin),
+ cross_axis_border_padding(cross_axis_border_padding),
+ physical_margins(physical_margins),
frozen(false),
needs_relayout_for_stretch(false),
ng_input_node(/* LayoutBox* */ nullptr) {
- DCHECK(!box->IsOutOfFlowPositioned());
- DCHECK_GE(min_max_sizes.max_size, LayoutUnit())
+ DCHECK_GE(min_max_main_sizes.max_size, LayoutUnit())
<< "Use LayoutUnit::Max() for no max size";
}
bool FlexItem::MainAxisIsInlineAxis() const {
- return algorithm->IsHorizontalFlow() == box->IsHorizontalWritingMode();
+ return algorithm->IsHorizontalFlow() == style.IsHorizontalWritingMode();
}
LayoutUnit FlexItem::FlowAwareMarginStart() const {
if (algorithm->IsHorizontalFlow()) {
- return algorithm->IsLeftToRightFlow() ? box->MarginLeft()
- : box->MarginRight();
+ return algorithm->IsLeftToRightFlow() ? physical_margins.left
+ : physical_margins.right;
}
- return algorithm->IsLeftToRightFlow() ? box->MarginTop()
- : box->MarginBottom();
+ return algorithm->IsLeftToRightFlow() ? physical_margins.top
+ : physical_margins.bottom;
}
LayoutUnit FlexItem::FlowAwareMarginEnd() const {
if (algorithm->IsHorizontalFlow()) {
- return algorithm->IsLeftToRightFlow() ? box->MarginRight()
- : box->MarginLeft();
+ return algorithm->IsLeftToRightFlow() ? physical_margins.right
+ : physical_margins.left;
}
- return algorithm->IsLeftToRightFlow() ? box->MarginBottom()
- : box->MarginTop();
+ return algorithm->IsLeftToRightFlow() ? physical_margins.bottom
+ : physical_margins.top;
}
LayoutUnit FlexItem::FlowAwareMarginBefore() const {
switch (algorithm->GetTransformedWritingMode()) {
case TransformedWritingMode::kTopToBottomWritingMode:
- return box->MarginTop();
+ return physical_margins.top;
case TransformedWritingMode::kBottomToTopWritingMode:
- return box->MarginBottom();
+ return physical_margins.bottom;
case TransformedWritingMode::kLeftToRightWritingMode:
- return box->MarginLeft();
+ return physical_margins.left;
case TransformedWritingMode::kRightToLeftWritingMode:
- return box->MarginRight();
+ return physical_margins.right;
}
NOTREACHED();
- return box->MarginTop();
+ return LayoutUnit();
+}
+
+LayoutUnit FlexItem::MainAxisMarginExtent() const {
+ return algorithm->IsHorizontalFlow() ? physical_margins.HorizontalSum()
+ : physical_margins.VerticalSum();
}
LayoutUnit FlexItem::CrossAxisMarginExtent() const {
- return algorithm->IsHorizontalFlow() ? box->MarginHeight()
- : box->MarginWidth();
+ return algorithm->IsHorizontalFlow() ? physical_margins.VerticalSum()
+ : physical_margins.HorizontalSum();
}
LayoutUnit FlexItem::MarginBoxAscent() const {
- LayoutUnit ascent(box->FirstLineBoxBaseline());
- if (ascent == -1)
- ascent = cross_axis_size;
- return ascent + FlowAwareMarginBefore();
+ if (box) {
+ LayoutUnit ascent(box->FirstLineBoxBaseline());
+ if (ascent == -1)
+ ascent = cross_axis_size;
+ return ascent + FlowAwareMarginBefore();
+ }
+
+ DCHECK(layout_result);
+ base::Optional<LayoutUnit> baseline =
+ NGBoxFragment(
+ algorithm->StyleRef().GetWritingMode(),
+ algorithm->StyleRef().Direction(),
+ To<NGPhysicalBoxFragment>(layout_result->PhysicalFragment()))
+ .Baseline();
+ return baseline.value_or(cross_axis_size) + FlowAwareMarginBefore();
}
LayoutUnit FlexItem::AvailableAlignmentSpace() const {
@@ -152,64 +173,59 @@ LayoutUnit FlexItem::AvailableAlignmentSpace() const {
bool FlexItem::HasAutoMarginsInCrossAxis() const {
if (algorithm->IsHorizontalFlow()) {
- return box->StyleRef().MarginTop().IsAuto() ||
- box->StyleRef().MarginBottom().IsAuto();
+ return style.MarginTop().IsAuto() || style.MarginBottom().IsAuto();
}
- return box->StyleRef().MarginLeft().IsAuto() ||
- box->StyleRef().MarginRight().IsAuto();
+ return style.MarginLeft().IsAuto() || style.MarginRight().IsAuto();
}
ItemPosition FlexItem::Alignment() const {
- return FlexLayoutAlgorithm::AlignmentForChild(*algorithm->Style(),
- box->StyleRef());
+ return FlexLayoutAlgorithm::AlignmentForChild(*algorithm->Style(), style);
}
void FlexItem::UpdateAutoMarginsInMainAxis(LayoutUnit auto_margin_offset) {
DCHECK_GE(auto_margin_offset, LayoutUnit());
if (algorithm->IsHorizontalFlow()) {
- if (box->StyleRef().MarginLeft().IsAuto())
- box->SetMarginLeft(auto_margin_offset);
- if (box->StyleRef().MarginRight().IsAuto())
- box->SetMarginRight(auto_margin_offset);
+ if (style.MarginLeft().IsAuto())
+ physical_margins.left = auto_margin_offset;
+ if (style.MarginRight().IsAuto())
+ physical_margins.right = auto_margin_offset;
} else {
- if (box->StyleRef().MarginTop().IsAuto())
- box->SetMarginTop(auto_margin_offset);
- if (box->StyleRef().MarginBottom().IsAuto())
- box->SetMarginBottom(auto_margin_offset);
+ if (style.MarginTop().IsAuto())
+ physical_margins.top = auto_margin_offset;
+ if (style.MarginBottom().IsAuto())
+ physical_margins.bottom = auto_margin_offset;
}
}
bool FlexItem::UpdateAutoMarginsInCrossAxis(
LayoutUnit available_alignment_space) {
- DCHECK(!box->IsOutOfFlowPositioned());
DCHECK_GE(available_alignment_space, LayoutUnit());
bool is_horizontal = algorithm->IsHorizontalFlow();
- const Length& top_or_left = is_horizontal ? box->StyleRef().MarginTop()
- : box->StyleRef().MarginLeft();
- const Length& bottom_or_right = is_horizontal ? box->StyleRef().MarginBottom()
- : box->StyleRef().MarginRight();
+ const Length& top_or_left =
+ is_horizontal ? style.MarginTop() : style.MarginLeft();
+ const Length& bottom_or_right =
+ is_horizontal ? style.MarginBottom() : style.MarginRight();
if (top_or_left.IsAuto() && bottom_or_right.IsAuto()) {
desired_location.Move(LayoutUnit(), available_alignment_space / 2);
if (is_horizontal) {
- box->SetMarginTop(available_alignment_space / 2);
- box->SetMarginBottom(available_alignment_space / 2);
+ physical_margins.top = available_alignment_space / 2;
+ physical_margins.bottom = available_alignment_space / 2;
} else {
- box->SetMarginLeft(available_alignment_space / 2);
- box->SetMarginRight(available_alignment_space / 2);
+ physical_margins.left = available_alignment_space / 2;
+ physical_margins.right = available_alignment_space / 2;
}
return true;
}
bool should_adjust_top_or_left = true;
- if (algorithm->IsColumnFlow() && !box->StyleRef().IsLeftToRightDirection()) {
+ if (algorithm->IsColumnFlow() && !style.IsLeftToRightDirection()) {
// For column flows, only make this adjustment if topOrLeft corresponds to
// the "before" margin, so that flipForRightToLeftColumn will do the right
// thing.
should_adjust_top_or_left = false;
}
- if (!algorithm->IsColumnFlow() &&
- box->StyleRef().IsFlippedBlocksWritingMode()) {
+ if (!algorithm->IsColumnFlow() && style.IsFlippedBlocksWritingMode()) {
// If we are a flipped writing mode, we need to adjust the opposite side.
// This is only needed for row flows because this only affects the
// block-direction axis.
@@ -221,9 +237,9 @@ bool FlexItem::UpdateAutoMarginsInCrossAxis(
desired_location.Move(LayoutUnit(), available_alignment_space);
if (is_horizontal)
- box->SetMarginTop(available_alignment_space);
+ physical_margins.top = available_alignment_space;
else
- box->SetMarginLeft(available_alignment_space);
+ physical_margins.left = available_alignment_space;
return true;
}
if (bottom_or_right.IsAuto()) {
@@ -231,9 +247,9 @@ bool FlexItem::UpdateAutoMarginsInCrossAxis(
desired_location.Move(LayoutUnit(), available_alignment_space);
if (is_horizontal)
- box->SetMarginBottom(available_alignment_space);
+ physical_margins.bottom = available_alignment_space;
else
- box->SetMarginRight(available_alignment_space);
+ physical_margins.right = available_alignment_space;
return true;
}
return false;
@@ -241,25 +257,24 @@ bool FlexItem::UpdateAutoMarginsInCrossAxis(
void FlexItem::ComputeStretchedSize() {
DCHECK_EQ(Alignment(), ItemPosition::kStretch);
- if (MainAxisIsInlineAxis() && box->StyleRef().LogicalHeight().IsAuto()) {
- LayoutUnit stretched_logical_height =
- std::max(box->BorderAndPaddingLogicalHeight(),
- Line()->cross_axis_extent - CrossAxisMarginExtent());
- cross_axis_size = box->ConstrainLogicalHeightByMinMax(
- stretched_logical_height, box->IntrinsicContentLogicalHeight());
- } else if (!MainAxisIsInlineAxis() &&
- box->StyleRef().LogicalWidth().IsAuto()) {
- LayoutUnit child_width =
- (Line()->cross_axis_extent - CrossAxisMarginExtent())
- .ClampNegativeToZero();
- if (LayoutFlexibleBox* flexbox = ToLayoutFlexibleBoxOrNull(box->Parent())) {
+ LayoutUnit stretched_size =
+ std::max(cross_axis_border_padding,
+ Line()->cross_axis_extent - CrossAxisMarginExtent());
+ if (box) {
+ if (MainAxisIsInlineAxis() && style.LogicalHeight().IsAuto()) {
+ cross_axis_size = box->ConstrainLogicalHeightByMinMax(
+ stretched_size, box->IntrinsicContentLogicalHeight());
+ } else if (!MainAxisIsInlineAxis() && style.LogicalWidth().IsAuto()) {
+ const LayoutFlexibleBox* flexbox = ToLayoutFlexibleBox(box->Parent());
cross_axis_size = box->ConstrainLogicalWidthByMinMax(
- child_width, flexbox->CrossAxisContentExtent(), flexbox);
- } else {
- DCHECK(box->Parent()->IsLayoutNGFlexibleBox());
- cross_axis_size = min_max_cross_sizes->ClampSizeToMinAndMax(child_width);
+ stretched_size, flexbox->CrossAxisContentExtent(), flexbox);
}
+ return;
}
+
+ if ((MainAxisIsInlineAxis() && style.LogicalHeight().IsAuto()) ||
+ (!MainAxisIsInlineAxis() && style.LogicalWidth().IsAuto()))
+ cross_axis_size = min_max_cross_sizes->ClampSizeToMinAndMax(stretched_size);
}
// static
@@ -314,12 +329,11 @@ void FlexLine::FreezeViolations(ViolationsVector& violations) {
const ComputedStyle& flex_box_style = algorithm->StyleRef();
for (size_t i = 0; i < violations.size(); ++i) {
DCHECK(!violations[i]->frozen) << i;
- LayoutBox* child = violations[i]->box;
+ const ComputedStyle& child_style = violations[i]->style;
LayoutUnit child_size = violations[i]->flexed_content_size;
remaining_free_space -= child_size - violations[i]->flex_base_content_size;
- total_flex_grow -= child->StyleRef().ResolvedFlexGrow(flex_box_style);
- const float flex_shrink =
- child->StyleRef().ResolvedFlexShrink(flex_box_style);
+ total_flex_grow -= child_style.ResolvedFlexGrow(flex_box_style);
+ const float flex_shrink = child_style.ResolvedFlexShrink(flex_box_style);
total_flex_shrink -= flex_shrink;
total_weighted_flex_shrink -=
flex_shrink * violations[i]->flex_base_content_size;
@@ -344,13 +358,11 @@ void FlexLine::FreezeInflexibleItems() {
const ComputedStyle& flex_box_style = algorithm->StyleRef();
for (size_t i = 0; i < line_items.size(); ++i) {
FlexItem& flex_item = line_items[i];
- LayoutBox* child = flex_item.box;
- DCHECK(!flex_item.box->IsOutOfFlowPositioned());
DCHECK(!flex_item.frozen) << i;
float flex_factor =
(flex_sign == kPositiveFlexibility)
- ? child->StyleRef().ResolvedFlexGrow(flex_box_style)
- : child->StyleRef().ResolvedFlexShrink(flex_box_style);
+ ? flex_item.style.ResolvedFlexGrow(flex_box_style)
+ : flex_item.style.ResolvedFlexShrink(flex_box_style);
if (flex_factor == 0 ||
(flex_sign == kPositiveFlexibility &&
flex_item.flex_base_content_size >
@@ -384,7 +396,6 @@ bool FlexLine::ResolveFlexibleLengths() {
const ComputedStyle& flex_box_style = algorithm->StyleRef();
for (size_t i = 0; i < line_items.size(); ++i) {
FlexItem& flex_item = line_items[i];
- LayoutBox* child = flex_item.box;
// This check also covers out-of-flow children.
if (flex_item.frozen)
@@ -395,14 +406,14 @@ bool FlexLine::ResolveFlexibleLengths() {
if (remaining_free_space > 0 && total_flex_grow > 0 &&
flex_sign == kPositiveFlexibility && std::isfinite(total_flex_grow)) {
extra_space = remaining_free_space *
- child->StyleRef().ResolvedFlexGrow(flex_box_style) /
+ flex_item.style.ResolvedFlexGrow(flex_box_style) /
total_flex_grow;
} else if (remaining_free_space < 0 && total_weighted_flex_shrink > 0 &&
flex_sign == kNegativeFlexibility &&
std::isfinite(total_weighted_flex_shrink) &&
- child->StyleRef().ResolvedFlexShrink(flex_box_style)) {
+ flex_item.style.ResolvedFlexShrink(flex_box_style)) {
extra_space = remaining_free_space *
- child->StyleRef().ResolvedFlexShrink(flex_box_style) *
+ flex_item.style.ResolvedFlexShrink(flex_box_style) *
flex_item.flex_base_content_size /
total_weighted_flex_shrink;
}
@@ -438,17 +449,16 @@ LayoutUnit FlexLine::ApplyMainAxisAutoMarginAdjustment() {
int number_of_auto_margins = 0;
bool is_horizontal = algorithm->IsHorizontalFlow();
for (size_t i = 0; i < line_items.size(); ++i) {
- LayoutBox* child = line_items[i].box;
- DCHECK(!child->IsOutOfFlowPositioned());
+ const ComputedStyle& style = line_items[i].style;
if (is_horizontal) {
- if (child->StyleRef().MarginLeft().IsAuto())
+ if (style.MarginLeft().IsAuto())
++number_of_auto_margins;
- if (child->StyleRef().MarginRight().IsAuto())
+ if (style.MarginRight().IsAuto())
++number_of_auto_margins;
} else {
- if (child->StyleRef().MarginTop().IsAuto())
+ if (style.MarginTop().IsAuto())
++number_of_auto_margins;
- if (child->StyleRef().MarginBottom().IsAuto())
+ if (style.MarginBottom().IsAuto())
++number_of_auto_margins;
}
}
@@ -468,11 +478,8 @@ void FlexLine::ComputeLineItemsPosition(LayoutUnit main_axis_start_offset,
// Recalculate the remaining free space. The adjustment for flex factors
// between 0..1 means we can't just use remainingFreeSpace here.
LayoutUnit total_item_size;
- for (size_t i = 0; i < line_items.size(); ++i) {
- FlexItem& flex_item = line_items[i];
- DCHECK(!flex_item.box->IsOutOfFlowPositioned());
- total_item_size += flex_item.FlexedMarginBoxSize();
- }
+ for (size_t i = 0; i < line_items.size(); ++i)
+ total_item_size += line_items[i].FlexedMarginBoxSize();
remaining_free_space = container_main_inner_size - total_item_size;
const StyleContentAlignmentData justify_content =
@@ -516,8 +523,6 @@ void FlexLine::ComputeLineItemsPosition(LayoutUnit main_axis_start_offset,
for (size_t i = 0; i < line_items.size(); ++i) {
FlexItem& flex_item = line_items[i];
- DCHECK(!flex_item.box->IsOutOfFlowPositioned());
-
flex_item.UpdateAutoMarginsInMainAxis(auto_margin_offset);
LayoutUnit child_cross_axis_margin_box_extent;
@@ -590,7 +595,6 @@ FlexLine* FlexLayoutAlgorithm::ComputeNextFlexLine(
for (; next_item_index_ < all_items_.size(); ++next_item_index_) {
FlexItem& flex_item = all_items_[next_item_index_];
- DCHECK(!flex_item.box->IsOutOfFlowPositioned());
if (IsMultiline() &&
sum_hypothetical_main_size +
flex_item.HypotheticalMainAxisMarginBoxSize() >
@@ -600,9 +604,8 @@ FlexLine* FlexLayoutAlgorithm::ComputeNextFlexLine(
}
line_has_in_flow_item = true;
sum_flex_base_size += flex_item.FlexBaseMarginBoxSize();
- total_flex_grow += flex_item.box->StyleRef().ResolvedFlexGrow(StyleRef());
- const float flex_shrink =
- flex_item.box->StyleRef().ResolvedFlexShrink(StyleRef());
+ total_flex_grow += flex_item.style.ResolvedFlexGrow(StyleRef());
+ const float flex_shrink = flex_item.style.ResolvedFlexShrink(StyleRef());
total_flex_shrink += flex_shrink;
total_weighted_flex_shrink +=
flex_shrink * flex_item.flex_base_content_size;
@@ -663,6 +666,8 @@ bool FlexLayoutAlgorithm::ShouldApplyMinSizeAutoForChild(
// css-flexbox section 4.5
const Length& min = IsHorizontalFlow() ? child.StyleRef().MinWidth()
: child.StyleRef().MinHeight();
+ // TODO(dgrogan): min.IsIntrinsic should also get past this check when in the
+ // item's block direction.
if (!min.IsAuto())
return false;
@@ -670,6 +675,8 @@ bool FlexLayoutAlgorithm::ShouldApplyMinSizeAutoForChild(
if (StyleRef().IsDeprecatedWebkitBox())
return false;
+ // TODO(dgrogan): MainAxisOverflowForChild == kClip also qualifies, not just
+ // kVisible.
return !child.ShouldApplySizeContainment() &&
MainAxisOverflowForChild(child) == EOverflow::kVisible;
}
@@ -737,12 +744,9 @@ void FlexLayoutAlgorithm::AlignChildren() {
LayoutUnit max_ascent = line_context.max_ascent;
for (FlexItem& flex_item : line_context.line_items) {
- DCHECK(!flex_item.box->IsOutOfFlowPositioned());
-
if (flex_item.UpdateAutoMarginsInCrossAxis(
- std::max(LayoutUnit(), flex_item.AvailableAlignmentSpace()))) {
+ flex_item.AvailableAlignmentSpace().ClampNegativeToZero()))
continue;
- }
ItemPosition position = flex_item.Alignment();
if (position == ItemPosition::kStretch) {
@@ -980,14 +984,17 @@ void FlexLayoutAlgorithm::LayoutColumnReverse(
child_number < line_context.line_items.size(); ++child_number) {
FlexItem& flex_item = line_context.line_items[child_number];
LayoutUnit item_main_size = flex_item.FlexedBorderBoxSize();
+
+ NGBoxStrut margins = flex_item.physical_margins.ConvertToLogical(
+ Style()->GetWritingMode(), Style()->Direction());
+
// We passed 0 as the initial main_axis offset to ComputeLineItemsPosition
// for ColumnReverse containers so here we have to add the
// border_scrollbar_padding of the container.
flex_item.desired_location.SetX(
main_axis_content_size + border_scrollbar_padding_before -
- flex_item.desired_location.X() - item_main_size -
- flex_item.box->MarginAfter(Style()) +
- flex_item.box->MarginBefore(Style()));
+ flex_item.desired_location.X() - item_main_size - margins.block_end +
+ margins.block_start);
}
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.h b/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
index 8fc05cdab10..19ccd4575f2 100644
--- a/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/flexible_box_algorithm.h
@@ -33,7 +33,7 @@
#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/order_iterator.h"
@@ -49,7 +49,7 @@ class FlexItem;
class FlexLine;
class FlexLayoutAlgorithm;
class LayoutBox;
-struct MinMaxSize;
+struct MinMaxSizes;
enum FlexSign {
kPositiveFlexibility,
@@ -113,24 +113,28 @@ class FlexItem {
public:
// Parameters:
// - |flex_base_content_size| includes scrollbar size but not border/padding.
- // - |min_max_sizes| is the resolved min and max size properties in the
+ // - |min_max_main_sizes| is the resolved min and max size properties in the
// main axis direction (not intrinsic widths). It does not include
- // border/scrollbar/padding.
- FlexItem(LayoutBox*,
+ // border/padding.
+ FlexItem(const FlexLayoutAlgorithm*,
+ LayoutBox*,
+ const ComputedStyle& style,
LayoutUnit flex_base_content_size,
- MinMaxSize min_max_main_axis_sizes,
+ MinMaxSizes min_max_main_sizes,
// Ignored for legacy, required for NG:
- base::Optional<MinMaxSize> min_max_cross_axis_sizes,
+ base::Optional<MinMaxSizes> min_max_cross_sizes,
LayoutUnit main_axis_border_padding,
- LayoutUnit main_axis_margin);
+ LayoutUnit cross_axis_border_padding,
+ NGPhysicalBoxStrut physical_margins);
LayoutUnit HypotheticalMainAxisMarginBoxSize() const {
return hypothetical_main_content_size + main_axis_border_padding +
- main_axis_margin;
+ MainAxisMarginExtent();
}
LayoutUnit FlexBaseMarginBoxSize() const {
- return flex_base_content_size + main_axis_border_padding + main_axis_margin;
+ return flex_base_content_size + main_axis_border_padding +
+ MainAxisMarginExtent();
}
LayoutUnit FlexedBorderBoxSize() const {
@@ -138,11 +142,12 @@ class FlexItem {
}
LayoutUnit FlexedMarginBoxSize() const {
- return flexed_content_size + main_axis_border_padding + main_axis_margin;
+ return flexed_content_size + main_axis_border_padding +
+ MainAxisMarginExtent();
}
LayoutUnit ClampSizeToMinAndMax(LayoutUnit size) const {
- return min_max_sizes.ClampSizeToMinAndMax(size);
+ return min_max_main_sizes.ClampSizeToMinAndMax(size);
}
ItemPosition Alignment() const;
@@ -152,6 +157,8 @@ class FlexItem {
LayoutUnit FlowAwareMarginStart() const;
LayoutUnit FlowAwareMarginEnd() const;
LayoutUnit FlowAwareMarginBefore() const;
+
+ LayoutUnit MainAxisMarginExtent() const;
LayoutUnit CrossAxisMarginExtent() const;
LayoutUnit MarginBoxAscent() const;
@@ -178,15 +185,18 @@ class FlexItem {
bool is_wrap_reverse,
bool is_deprecated_webkit_box);
- FlexLayoutAlgorithm* algorithm;
+ const FlexLayoutAlgorithm* algorithm;
wtf_size_t line_number;
LayoutBox* box;
+ const ComputedStyle& style;
const LayoutUnit flex_base_content_size;
- const MinMaxSize min_max_sizes;
- const base::Optional<MinMaxSize> min_max_cross_sizes;
+ const MinMaxSizes min_max_main_sizes;
+ const base::Optional<MinMaxSizes> min_max_cross_sizes;
const LayoutUnit hypothetical_main_content_size;
const LayoutUnit main_axis_border_padding;
- const LayoutUnit main_axis_margin;
+ const LayoutUnit cross_axis_border_padding;
+ NGPhysicalBoxStrut physical_margins;
+
LayoutUnit flexed_content_size;
// When set by the caller, this should be the size pre-stretching.
@@ -327,7 +337,7 @@ class FlexLine {
// https://drafts.csswg.org/css-flexbox/
//
// Expected usage is as follows:
-// FlexLayoutAlgorithm algorithm(Style(), MainAxisLength(), flex_items);
+// FlexLayoutAlgorithm algorithm(Style(), MainAxisLength());
// for (each child) {
// algorithm.emplace_back(...caller must compute these values...)
// }
@@ -353,14 +363,13 @@ class FlexLayoutAlgorithm {
template <typename... Args>
FlexItem& emplace_back(Args&&... args) {
- FlexItem& item = all_items_.emplace_back(std::forward<Args>(args)...);
- item.algorithm = this;
- return item;
+ return all_items_.emplace_back(this, std::forward<Args>(args)...);
}
const ComputedStyle* Style() const { return style_; }
const ComputedStyle& StyleRef() const { return *style_; }
+ const Vector<FlexLine>& FlexLines() const { return flex_lines_; }
Vector<FlexLine>& FlexLines() { return flex_lines_; }
// Computes the next flex line, stores it in FlexLines(), and returns a
diff --git a/chromium/third_party/blink/renderer/core/layout/floating_objects.cc b/chromium/third_party/blink/renderer/core/layout/floating_objects.cc
index 1fe5923973b..d3bc48f940f 100644
--- a/chromium/third_party/blink/renderer/core/layout/floating_objects.cc
+++ b/chromium/third_party/blink/renderer/core/layout/floating_objects.cc
@@ -47,7 +47,7 @@ struct SameSizeAsFloatingObject {
static_assert(sizeof(FloatingObject) == sizeof(SameSizeAsFloatingObject),
"FloatingObject should stay small");
-FloatingObject::FloatingObject(LayoutBox* layout_object, Type type)
+FloatingObject::FloatingObject(PassKey key, LayoutBox* layout_object, Type type)
: layout_object_(layout_object),
originating_line_(nullptr),
type_(type),
@@ -63,7 +63,8 @@ FloatingObject::FloatingObject(LayoutBox* layout_object, Type type)
{
}
-FloatingObject::FloatingObject(LayoutBox* layout_object,
+FloatingObject::FloatingObject(PassKey key,
+ LayoutBox* layout_object,
Type type,
const LayoutRect& frame_rect,
bool should_paint,
@@ -89,7 +90,7 @@ FloatingObject::FloatingObject(LayoutBox* layout_object,
std::unique_ptr<FloatingObject> FloatingObject::Create(LayoutBox* layout_object,
Type type) {
std::unique_ptr<FloatingObject> new_obj =
- base::WrapUnique(new FloatingObject(layout_object, type));
+ base::WrapUnique(new FloatingObject(PassKey(), layout_object, type));
// If a layer exists, the float will paint itself. Otherwise someone else
// will.
@@ -114,14 +115,14 @@ std::unique_ptr<FloatingObject> FloatingObject::CopyToNewContainer(
bool should_paint,
bool is_descendant) const {
return base::WrapUnique(new FloatingObject(
- GetLayoutObject(), GetType(),
+ PassKey(), GetLayoutObject(), GetType(),
LayoutRect(FrameRect().Location() - offset, FrameRect().Size()),
should_paint, is_descendant, IsLowestNonOverhangingFloatInChild()));
}
std::unique_ptr<FloatingObject> FloatingObject::UnsafeClone() const {
std::unique_ptr<FloatingObject> clone_object = base::WrapUnique(
- new FloatingObject(GetLayoutObject(), GetType(), frame_rect_,
+ new FloatingObject(PassKey(), GetLayoutObject(), GetType(), frame_rect_,
should_paint_, is_descendant_, false));
clone_object->is_placed_ = is_placed_;
#if DCHECK_IS_ON()
diff --git a/chromium/third_party/blink/renderer/core/layout/floating_objects.h b/chromium/third_party/blink/renderer/core/layout/floating_objects.h
index f11a30e3aad..11edc377a8d 100644
--- a/chromium/third_party/blink/renderer/core/layout/floating_objects.h
+++ b/chromium/third_party/blink/renderer/core/layout/floating_objects.h
@@ -27,6 +27,7 @@
#include <memory>
#include "base/macros.h"
+#include "base/util/type_safety/pass_key.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "third_party/blink/renderer/platform/wtf/list_hash_set.h"
@@ -147,15 +148,17 @@ class FloatingObject {
RootInlineBox* OriginatingLine() const { return originating_line_; }
void SetOriginatingLine(RootInlineBox* line) { originating_line_ = line; }
- private:
- FloatingObject(LayoutBox*, Type);
- FloatingObject(LayoutBox*,
+ using PassKey = util::PassKey<FloatingObject>;
+ FloatingObject(PassKey, LayoutBox*, Type);
+ FloatingObject(PassKey,
+ LayoutBox*,
Type,
const LayoutRect&,
bool should_paint,
bool is_descendant,
bool is_lowest_non_overhanging_float_in_child);
+ private:
LayoutBox* layout_object_;
RootInlineBox* originating_line_;
LayoutRect frame_rect_;
diff --git a/chromium/third_party/blink/renderer/core/layout/generated_children.h b/chromium/third_party/blink/renderer/core/layout/generated_children.h
index 52db3958b73..6ed0c9020de 100644
--- a/chromium/third_party/blink/renderer/core/layout/generated_children.h
+++ b/chromium/third_party/blink/renderer/core/layout/generated_children.h
@@ -18,7 +18,7 @@ static bool CanHaveGeneratedChildren(const LayoutObject& layout_object) {
// FIXME: LayoutMedia::layout makes assumptions about what children are
// allowed so we can't support generated content.
if (layout_object.IsMedia() || layout_object.IsTextControl() ||
- layout_object.IsMenuList())
+ IsMenuList(&layout_object))
return false;
// Input elements can't have generated children, but button elements can.
diff --git a/chromium/third_party/blink/renderer/core/layout/geometry/physical_offset.h b/chromium/third_party/blink/renderer/core/layout/geometry/physical_offset.h
index f435b7ec3bd..20ddb662d16 100644
--- a/chromium/third_party/blink/renderer/core/layout/geometry/physical_offset.h
+++ b/chromium/third_party/blink/renderer/core/layout/geometry/physical_offset.h
@@ -96,6 +96,8 @@ struct CORE_EXPORT PhysicalOffset {
: left(point.X()), top(point.Y()) {}
explicit PhysicalOffset(const IntSize& size)
: left(size.Width()), top(size.Height()) {}
+ explicit PhysicalOffset(const gfx::Point& point)
+ : left(point.x()), top(point.y()) {}
static PhysicalOffset FromFloatPointFloor(const FloatPoint& point) {
return {LayoutUnit::FromFloatFloor(point.X()),
diff --git a/chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.h b/chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.h
index 35436292847..8c8a236c58c 100644
--- a/chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.h
+++ b/chromium/third_party/blink/renderer/core/layout/geometry/physical_rect.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GEOMETRY_PHYSICAL_RECT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_GEOMETRY_PHYSICAL_RECT_H_
+#include "base/compiler_specific.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
@@ -97,8 +98,8 @@ struct CORE_EXPORT PhysicalRect {
return Contains(point.left, point.top);
}
- bool Intersects(const PhysicalRect&) const;
- bool IntersectsInclusively(const PhysicalRect&) const;
+ WARN_UNUSED_RESULT bool Intersects(const PhysicalRect&) const;
+ WARN_UNUSED_RESULT bool IntersectsInclusively(const PhysicalRect&) const;
// Whether all edges of the rect are at full-pixel boundaries.
// i.e.: EnclosingIntRect(this)) == this
@@ -107,10 +108,6 @@ struct CORE_EXPORT PhysicalRect {
!size.width.HasFraction() && !size.height.HasFraction();
}
- PhysicalRect operator+(const PhysicalOffset&) const {
- return {this->offset + offset, size};
- }
-
void Unite(const PhysicalRect&);
void UniteIfNonZero(const PhysicalRect&);
void UniteEvenIfEmpty(const PhysicalRect&);
diff --git a/chromium/third_party/blink/renderer/core/layout/grid.cc b/chromium/third_party/blink/renderer/core/layout/grid.cc
index f13eca09ca2..d86bcfc238c 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid.cc
+++ b/chromium/third_party/blink/renderer/core/layout/grid.cc
@@ -8,6 +8,7 @@
#include <memory>
#include <utility>
+#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/core/layout/layout_grid.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/layout/grid_test.cc b/chromium/third_party/blink/renderer/core/layout/grid_test.cc
index 65bdebf1006..e9779901a9d 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/grid_test.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/layout/grid.h"
#include "third_party/blink/renderer/core/layout/layout_grid.h"
+#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
index d803cb4052f..9ac29ea0ea3 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc
@@ -148,29 +148,47 @@ class DefiniteSizeStrategy final : public GridTrackSizingAlgorithmStrategy {
GridTrackSizingAlgorithmStrategy::~GridTrackSizingAlgorithmStrategy() = default;
-bool GridTrackSizingAlgorithmStrategy::
- ShouldClearOverrideContainingBlockContentSizeForChild(
- const LayoutGrid& grid,
- const LayoutBox& child,
- GridTrackSizingDirection direction) {
+bool GridTrackSizingAlgorithmStrategy::HasRelativeMarginOrPaddingForChild(
+ const LayoutGrid& grid,
+ const LayoutBox& child,
+ GridTrackSizingDirection direction) {
GridTrackSizingDirection child_inline_direction =
GridLayoutUtils::FlowAwareDirectionForChild(grid, child, kForColumns);
if (direction == child_inline_direction) {
- return child.HasRelativeLogicalWidth() ||
- child.StyleRef().LogicalWidth().IsIntrinsicOrAuto() ||
- child.StyleRef().MarginStart().IsPercentOrCalc() ||
+ return child.StyleRef().MarginStart().IsPercentOrCalc() ||
child.StyleRef().MarginEnd().IsPercentOrCalc() ||
child.StyleRef().PaddingStart().IsPercentOrCalc() ||
child.StyleRef().PaddingEnd().IsPercentOrCalc();
}
- return child.HasRelativeLogicalHeight() ||
- child.StyleRef().LogicalHeight().IsIntrinsicOrAuto() ||
- child.StyleRef().MarginBefore().IsPercentOrCalc() ||
+ return child.StyleRef().MarginBefore().IsPercentOrCalc() ||
child.StyleRef().MarginAfter().IsPercentOrCalc() ||
child.StyleRef().PaddingBefore().IsPercentOrCalc() ||
child.StyleRef().PaddingAfter().IsPercentOrCalc();
}
+bool GridTrackSizingAlgorithmStrategy::HasRelativeOrIntrinsicSizeForChild(
+ const LayoutGrid& grid,
+ const LayoutBox& child,
+ GridTrackSizingDirection direction) {
+ GridTrackSizingDirection child_inline_direction =
+ GridLayoutUtils::FlowAwareDirectionForChild(grid, child, kForColumns);
+ if (direction == child_inline_direction) {
+ return child.HasRelativeLogicalWidth() ||
+ child.StyleRef().LogicalWidth().IsIntrinsicOrAuto();
+ }
+ return child.HasRelativeLogicalHeight() ||
+ child.StyleRef().LogicalHeight().IsIntrinsicOrAuto();
+}
+
+bool GridTrackSizingAlgorithmStrategy::
+ ShouldClearOverrideContainingBlockContentSizeForChild(
+ const LayoutGrid& grid,
+ const LayoutBox& child,
+ GridTrackSizingDirection direction) {
+ return HasRelativeOrIntrinsicSizeForChild(grid, child, direction) ||
+ HasRelativeMarginOrPaddingForChild(grid, child, direction);
+}
+
void GridTrackSizingAlgorithmStrategy::
SetOverrideContainingBlockContentSizeForChild(
LayoutBox& child,
@@ -224,7 +242,8 @@ LayoutUnit GridTrackSizingAlgorithm::EstimatedGridAreaBreadthForChild(
kForColumns);
if (grid_area_is_indefinite) {
return direction == child_inline_direction
- ? std::max(child.MaxPreferredLogicalWidth(), grid_area_size)
+ ? std::max(child.PreferredLogicalWidths().max_size,
+ grid_area_size)
: LayoutUnit(-1);
}
return grid_area_size;
@@ -338,7 +357,7 @@ LayoutUnit GridTrackSizingAlgorithmStrategy::MinContentForChild(
// FIXME: It's unclear if we should return the intrinsic width or the
// preferred width.
// See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
- return child.MinPreferredLogicalWidth() +
+ return child.PreferredLogicalWidths().min_size +
GridLayoutUtils::MarginLogicalWidthForChild(*GetLayoutGrid(),
child) +
algorithm_.BaselineOffsetForChild(child,
@@ -362,7 +381,7 @@ LayoutUnit GridTrackSizingAlgorithmStrategy::MaxContentForChild(
// FIXME: It's unclear if we should return the intrinsic width or the
// preferred width.
// See http://lists.w3.org/Archives/Public/www-style/2013Jan/0245.html
- return child.MaxPreferredLogicalWidth() +
+ return child.PreferredLogicalWidths().max_size +
GridLayoutUtils::MarginLogicalWidthForChild(*GetLayoutGrid(),
child) +
algorithm_.BaselineOffsetForChild(child,
@@ -570,8 +589,11 @@ LayoutUnit DefiniteSizeStrategy::MinLogicalSizeForChild(
kForColumns);
LayoutUnit indefinite_size =
Direction() == child_inline_direction ? LayoutUnit() : LayoutUnit(-1);
- if (ShouldClearOverrideContainingBlockContentSizeForChild(
- *GetLayoutGrid(), child, Direction())) {
+ if (HasRelativeMarginOrPaddingForChild(*GetLayoutGrid(), child,
+ Direction()) ||
+ (Direction() != child_inline_direction &&
+ HasRelativeOrIntrinsicSizeForChild(*GetLayoutGrid(), child,
+ Direction()))) {
SetOverrideContainingBlockContentSizeForChild(child, Direction(),
indefinite_size);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h b/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
index c2f67decf4f..5472026fedd 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h
@@ -326,6 +326,12 @@ class GridTrackSizingAlgorithmStrategy {
}
// Helper functions
+ static bool HasRelativeMarginOrPaddingForChild(const LayoutGrid&,
+ const LayoutBox& child,
+ GridTrackSizingDirection);
+ static bool HasRelativeOrIntrinsicSizeForChild(const LayoutGrid&,
+ const LayoutBox& child,
+ GridTrackSizingDirection);
static bool ShouldClearOverrideContainingBlockContentSizeForChild(
const LayoutGrid&,
const LayoutBox& child,
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_cache.cc b/chromium/third_party/blink/renderer/core/layout/hit_test_cache.cc
index 2b536141ab6..5a46d3b68cb 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_cache.cc
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_cache.cc
@@ -40,7 +40,7 @@ bool HitTestCache::LookupCachedResult(const HitTestLocation& location,
return result;
}
-void HitTestCacheEntry::Trace(blink::Visitor* visitor) {
+void HitTestCacheEntry::Trace(Visitor* visitor) {
visitor->Trace(result);
}
@@ -85,7 +85,7 @@ void HitTestCache::Clear() {
items_.clear();
}
-void HitTestCache::Trace(blink::Visitor* visitor) {
+void HitTestCache::Trace(Visitor* visitor) {
visitor->Trace(items_);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_cache.h b/chromium/third_party/blink/renderer/core/layout/hit_test_cache.h
index 43f3e253c9d..985e58c1840 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_cache.h
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_cache.h
@@ -37,7 +37,7 @@ namespace blink {
struct HitTestCacheEntry {
DISALLOW_NEW();
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
HitTestLocation location;
HitTestResult result;
@@ -61,7 +61,7 @@ class CORE_EXPORT HitTestCache final : public GarbageCollected<HitTestCache> {
const HitTestResult&,
uint64_t dom_tree_version);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
// The below UMA values reference a validity region. This code has not
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_canvas_result.cc b/chromium/third_party/blink/renderer/core/layout/hit_test_canvas_result.cc
index 8c1f87c84d1..79e9b485d94 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_canvas_result.cc
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_canvas_result.cc
@@ -17,7 +17,7 @@ Element* HitTestCanvasResult::GetControl() const {
return control_.Get();
}
-void HitTestCanvasResult::Trace(blink::Visitor* visitor) {
+void HitTestCanvasResult::Trace(Visitor* visitor) {
visitor->Trace(control_);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_canvas_result.h b/chromium/third_party/blink/renderer/core/layout/hit_test_canvas_result.h
index 341faf0840b..4dcc8d19cdb 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_canvas_result.h
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_canvas_result.h
@@ -17,7 +17,7 @@ class CORE_EXPORT HitTestCanvasResult final
String GetId() const;
Element* GetControl() const;
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
String id_;
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_location.cc b/chromium/third_party/blink/renderer/core/layout/hit_test_location.cc
index e68cb3bd7dd..bae6bafa322 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_location.cc
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_location.cc
@@ -88,8 +88,6 @@ HitTestLocation::HitTestLocation(const HitTestLocation& other,
HitTestLocation::HitTestLocation(const HitTestLocation& other) = default;
-HitTestLocation::~HitTestLocation() = default;
-
HitTestLocation& HitTestLocation::operator=(const HitTestLocation& other) =
default;
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_location.h b/chromium/third_party/blink/renderer/core/layout/hit_test_location.h
index 08b89056581..016b930ff21 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_location.h
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_location.h
@@ -62,7 +62,6 @@ class CORE_EXPORT HitTestLocation {
HitTestLocation(const HitTestLocation&, const PhysicalOffset& offset);
HitTestLocation(const HitTestLocation&);
- ~HitTestLocation();
HitTestLocation& operator=(const HitTestLocation&);
const PhysicalOffset& Point() const { return point_; }
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_result.cc b/chromium/third_party/blink/renderer/core/layout/hit_test_result.cc
index 2138f41923d..68ac6dfdaa8 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_result.cc
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_result.cc
@@ -29,6 +29,7 @@
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
#include "third_party/blink/renderer/core/editing/visible_units.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/forms/html_text_area_element.h"
#include "third_party/blink/renderer/core/html/html_area_element.h"
@@ -38,7 +39,10 @@
#include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/input_type_names.h"
+#include "third_party/blink/renderer/core/layout/layout_block.h"
#include "third_party/blink/renderer/core/layout/layout_image.h"
+#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
#include "third_party/blink/renderer/core/scroll/scrollbar.h"
#include "third_party/blink/renderer/core/svg/svg_element.h"
#include "third_party/blink/renderer/platform/geometry/region.h"
@@ -124,7 +128,7 @@ void HitTestResult::PopulateFromCachedResult(const HitTestResult& other) {
: nullptr;
}
-void HitTestResult::Trace(blink::Visitor* visitor) {
+void HitTestResult::Trace(Visitor* visitor) {
visitor->Trace(inner_node_);
visitor->Trace(inert_node_);
visitor->Trace(inner_element_);
@@ -174,6 +178,31 @@ void HitTestResult::SetToShadowHostIfInRestrictedShadowRoot() {
SetInnerNode(shadow_host);
}
+CompositorElementId HitTestResult::GetScrollableContainer() const {
+ DCHECK(InnerNode());
+ LayoutBox* cur_box = InnerNode()->GetLayoutObject()->EnclosingBox();
+
+ // Scrolling propagates along the containing block chain and ends at the
+ // RootScroller node. The RootScroller node will have a custom applyScroll
+ // callback that performs scrolling as well as associated "root" actions like
+ // browser control movement and overscroll glow.
+ while (cur_box) {
+ if (cur_box->IsGlobalRootScroller() ||
+ cur_box->NeedsScrollNode(CompositingReason::kNone)) {
+ return CompositorElementIdFromUniqueObjectId(
+ cur_box->UniqueId(), CompositorElementIdNamespace::kScroll);
+ }
+
+ cur_box = cur_box->ContainingBlock();
+ }
+
+ return InnerNode()
+ ->GetDocument()
+ .GetPage()
+ ->GetVisualViewport()
+ .GetScrollElementId();
+}
+
HTMLAreaElement* HitTestResult::ImageAreaForImage() const {
DCHECK(inner_node_);
auto* image_element = DynamicTo<HTMLImageElement>(inner_node_.Get());
@@ -374,9 +403,7 @@ HTMLMediaElement* HitTestResult::MediaElement() const {
inner_node_->GetLayoutObject()->IsMedia()))
return nullptr;
- if (IsHTMLMediaElement(*inner_node_))
- return ToHTMLMediaElement(inner_node_);
- return nullptr;
+ return DynamicTo<HTMLMediaElement>(*inner_node_);
}
KURL HitTestResult::AbsoluteLinkURL() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_result.h b/chromium/third_party/blink/renderer/core/layout/hit_test_result.h
index c6ea07e53a6..d40ba852d00 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_result.h
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_result.h
@@ -27,6 +27,7 @@
#include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
#include "third_party/blink/renderer/core/layout/hit_test_location.h"
#include "third_party/blink/renderer/core/layout/hit_test_request.h"
+#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
#include "third_party/blink/renderer/platform/geometry/float_rect.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -66,7 +67,7 @@ class CORE_EXPORT HitTestResult {
HitTestResult(const HitTestResult&);
~HitTestResult();
HitTestResult& operator=(const HitTestResult&);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
bool EqualForCacheability(const HitTestResult&) const;
void CacheValues(const HitTestResult& other);
@@ -86,6 +87,7 @@ class CORE_EXPORT HitTestResult {
Node* InnerPossiblyPseudoNode() const {
return inner_possibly_pseudo_node_.Get();
}
+ CompositorElementId GetScrollableContainer() const;
Element* InnerElement() const { return inner_element_.Get(); }
// If innerNode is an image map or image map area, return the associated image
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block.cc b/chromium/third_party/blink/renderer/core/layout/layout_block.cc
index 228e4a3494e..c17f2501e74 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block.cc
@@ -32,7 +32,6 @@
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/editing/drag_caret.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
@@ -103,7 +102,6 @@ LayoutBlock::LayoutBlock(ContainerNode* node)
: LayoutBox(node),
has_margin_before_quirk_(false),
has_margin_after_quirk_(false),
- being_destroyed_(false),
has_markup_truncation_(false),
width_available_to_children_changed_(false),
height_available_to_children_changed_(false),
@@ -461,6 +459,7 @@ void LayoutBlock::ComputeVisualOverflow(bool) {
AddVisualOverflowFromTheme();
if (VisualOverflowRect() != previous_visual_overflow_rect) {
+ InvalidateIntersectionObserverCachedRects();
SetShouldCheckForPaintInvalidation();
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
}
@@ -548,7 +547,7 @@ void LayoutBlock::AddLayoutOverflowFromPositionedObjects() {
// Fixed positioned elements whose containing block is the LayoutView
// don't contribute to layout overflow, since they don't scroll with the
// content.
- if (!IsLayoutView() ||
+ if (!IsA<LayoutView>(this) ||
positioned_object->StyleRef().GetPosition() != EPosition::kFixed) {
AddLayoutOverflowFromChild(*positioned_object,
ToLayoutSize(positioned_object->Location()));
@@ -593,7 +592,8 @@ void LayoutBlock::UpdateBlockChildDirtyBitsBeforeLayout(bool relayout_children,
child.HasRelativeLogicalHeight() ||
(child.IsAnonymous() && HasRelativeLogicalHeight()) ||
child.StretchesToViewport();
- if (relayout_children || (has_relative_logical_height && !IsLayoutView()) ||
+ if (relayout_children ||
+ (has_relative_logical_height && !IsA<LayoutView>(this)) ||
(height_available_to_children_changed_ &&
ChangeInAvailableLogicalHeightAffectsChild(this, child)) ||
(child.IsListMarker() && IsListItem() &&
@@ -719,11 +719,11 @@ void LayoutBlock::MarkFixedPositionObjectForLayoutIfNeeded(
return;
LayoutObject* o = child->Parent();
- while (!o->IsLayoutView() &&
- o->StyleRef().GetPosition() != EPosition::kAbsolute)
+ bool is_layout_view = IsA<LayoutView>(o);
+ while (!is_layout_view && o->StyleRef().GetPosition() != EPosition::kAbsolute)
o = o->Parent();
// The LayoutView is absolute-positioned, but does not move.
- if (o->IsLayoutView())
+ if (is_layout_view)
return;
// We must compute child's width and height, but not update them now.
@@ -1176,7 +1176,7 @@ bool LayoutBlock::IsPointInOverflowControl(
bool LayoutBlock::HitTestOverflowControl(
HitTestResult& result,
const HitTestLocation& hit_test_location,
- const PhysicalOffset& adjusted_location) {
+ const PhysicalOffset& adjusted_location) const {
if (VisibleToHitTestRequest(result.GetHitTestRequest()) &&
IsPointInOverflowControl(result, hit_test_location.Point(),
adjusted_location)) {
@@ -1262,7 +1262,7 @@ static inline bool IsEditingBoundary(const LayoutObject* ancestor,
DCHECK(child);
DCHECK(child.NonPseudoNode());
return !ancestor || !ancestor->Parent() ||
- (ancestor->HasLayer() && ancestor->Parent()->IsLayoutView()) ||
+ (ancestor->HasLayer() && IsA<LayoutView>(ancestor->Parent())) ||
HasEditableStyle(*ancestor->NonPseudoNode()) ==
HasEditableStyle(*child.NonPseudoNode());
}
@@ -1399,10 +1399,9 @@ void LayoutBlock::ScrollbarsChanged(bool horizontal_scrollbar_changed,
height_available_to_children_changed_ |= horizontal_scrollbar_changed;
}
-void LayoutBlock::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
- int scrollbar_width = ScrollbarLogicalWidth();
+MinMaxSizes LayoutBlock::ComputeIntrinsicLogicalWidths() const {
+ MinMaxSizes sizes;
+ sizes += BorderAndPaddingLogicalWidth() + ScrollbarLogicalWidth();
// See if we can early out sooner if the logical width is overridden or we're
// size contained. Note that for multicol containers we need the column gaps.
@@ -1410,50 +1409,56 @@ void LayoutBlock::ComputeIntrinsicLogicalWidths(
const auto* block_flow = DynamicTo<LayoutBlockFlow>(this);
if (!block_flow || !block_flow->MultiColumnFlowThread()) {
if (HasOverrideIntrinsicContentLogicalWidth()) {
- max_logical_width = min_logical_width =
- OverrideIntrinsicContentLogicalWidth() + LayoutUnit(scrollbar_width);
- return;
+ sizes += OverrideIntrinsicContentLogicalWidth();
+ return sizes;
}
- if (ShouldApplySizeContainment()) {
- max_logical_width = min_logical_width = LayoutUnit(scrollbar_width);
- return;
+ LayoutUnit default_inline_size = DefaultIntrinsicContentInlineSize();
+ if (default_inline_size != kIndefiniteSize) {
+ sizes.max_size += default_inline_size;
+ if (!StyleRef().LogicalWidth().IsPercentOrCalc())
+ sizes.min_size = sizes.max_size;
+ return sizes;
}
+ if (ShouldApplySizeContainment())
+ return sizes;
}
+ MinMaxSizes child_sizes;
if (ChildrenInline()) {
// FIXME: Remove this const_cast.
To<LayoutBlockFlow>(const_cast<LayoutBlock*>(this))
- ->ComputeInlinePreferredLogicalWidths(min_logical_width,
- max_logical_width);
+ ->ComputeInlinePreferredLogicalWidths(child_sizes.min_size,
+ child_sizes.max_size);
} else {
- ComputeBlockPreferredLogicalWidths(min_logical_width, max_logical_width);
+ ComputeBlockPreferredLogicalWidths(child_sizes.min_size,
+ child_sizes.max_size);
}
- max_logical_width = std::max(min_logical_width, max_logical_width);
+ child_sizes.max_size = std::max(child_sizes.min_size, child_sizes.max_size);
auto* html_marquee_element = DynamicTo<HTMLMarqueeElement>(GetNode());
if (html_marquee_element && html_marquee_element->IsHorizontal())
- min_logical_width = LayoutUnit();
+ child_sizes.min_size = LayoutUnit();
+ if (UNLIKELY(IsListBox(this) && StyleRef().LogicalWidth().IsPercentOrCalc()))
+ child_sizes.min_size = LayoutUnit();
if (IsTableCell()) {
Length table_cell_width =
ToInterface<LayoutNGTableCellInterface>(this)->StyleOrColLogicalWidth();
- if (table_cell_width.IsFixed() && table_cell_width.Value() > 0)
- max_logical_width = std::max(min_logical_width,
- AdjustContentBoxLogicalWidthForBoxSizing(
- LayoutUnit(table_cell_width.Value())));
+ if (table_cell_width.IsFixed() && table_cell_width.Value() > 0) {
+ child_sizes.max_size = std::max(
+ child_sizes.min_size, AdjustContentBoxLogicalWidthForBoxSizing(
+ LayoutUnit(table_cell_width.Value())));
+ }
}
- max_logical_width += scrollbar_width;
- min_logical_width += scrollbar_width;
+ sizes += child_sizes;
+ return sizes;
}
DISABLE_CFI_PERF
-void LayoutBlock::ComputePreferredLogicalWidths() {
- DCHECK(PreferredLogicalWidthsDirty());
-
- min_preferred_logical_width_ = LayoutUnit();
- max_preferred_logical_width_ = LayoutUnit();
+MinMaxSizes LayoutBlock::PreferredLogicalWidths() const {
+ MinMaxSizes sizes;
// FIXME: The isFixed() calls here should probably be checking for isSpecified
// since you should be able to use percentage, calc or viewport relative
@@ -1462,52 +1467,32 @@ void LayoutBlock::ComputePreferredLogicalWidths() {
if (!IsTableCell() && style_to_use.LogicalWidth().IsFixed() &&
style_to_use.LogicalWidth().Value() >= 0 &&
!(IsFlexItemCommon() && Parent()->StyleRef().IsDeprecatedWebkitBox() &&
- !style_to_use.LogicalWidth().IntValue()))
- min_preferred_logical_width_ = max_preferred_logical_width_ =
- AdjustContentBoxLogicalWidthForBoxSizing(
- LayoutUnit(style_to_use.LogicalWidth().Value()));
- else
- ComputeIntrinsicLogicalWidths(min_preferred_logical_width_,
- max_preferred_logical_width_);
+ !style_to_use.LogicalWidth().IntValue())) {
+ sizes = AdjustBorderBoxLogicalWidthForBoxSizing(
+ LayoutUnit(style_to_use.LogicalWidth().Value()));
+ } else {
+ sizes = IntrinsicLogicalWidths();
+ }
if (style_to_use.LogicalMaxWidth().IsFixed()) {
- max_preferred_logical_width_ =
- std::min(max_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- LayoutUnit(style_to_use.LogicalMaxWidth().Value())));
- min_preferred_logical_width_ =
- std::min(min_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- LayoutUnit(style_to_use.LogicalMaxWidth().Value())));
+ sizes.Constrain(AdjustBorderBoxLogicalWidthForBoxSizing(
+ LayoutUnit(style_to_use.LogicalMaxWidth().Value())));
}
if (style_to_use.LogicalMinWidth().IsFixed() &&
style_to_use.LogicalMinWidth().Value() > 0) {
- max_preferred_logical_width_ =
- std::max(max_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- LayoutUnit(style_to_use.LogicalMinWidth().Value())));
- min_preferred_logical_width_ =
- std::max(min_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- LayoutUnit(style_to_use.LogicalMinWidth().Value())));
+ sizes.Encompass(AdjustBorderBoxLogicalWidthForBoxSizing(
+ LayoutUnit(style_to_use.LogicalMinWidth().Value())));
}
- LayoutUnit border_and_padding = BorderAndPaddingLogicalWidth();
- DCHECK_GE(border_and_padding, LayoutUnit());
- min_preferred_logical_width_ += border_and_padding;
- max_preferred_logical_width_ += border_and_padding;
-
// Table layout uses integers, ceil the preferred widths to ensure that they
// can contain the contents.
if (IsTableCell()) {
- min_preferred_logical_width_ =
- LayoutUnit(min_preferred_logical_width_.Ceil());
- max_preferred_logical_width_ =
- LayoutUnit(max_preferred_logical_width_.Ceil());
+ sizes.min_size = LayoutUnit(sizes.min_size.Ceil());
+ sizes.max_size = LayoutUnit(sizes.max_size.Ceil());
}
- ClearPreferredLogicalWidthsDirty();
+ return sizes;
}
void LayoutBlock::ComputeBlockPreferredLogicalWidths(
@@ -1532,7 +1517,10 @@ void LayoutBlock::ComputeBlockPreferredLogicalWidths(
// We don't really know whether the containing block of this child did
// change or is going to change size. However, this is our only
// opportunity to make sure that it gets its min/max widths calculated.
- child->SetPreferredLogicalWidthsDirty();
+ // This is also an important hook for flow threads; if the container of a
+ // flow thread needs its preferred logical widths recalculated, so does
+ // the flow thread, potentially.
+ child->SetIntrinsicLogicalWidthsDirty();
}
scoped_refptr<const ComputedStyle> child_style = child->Style();
@@ -1648,8 +1636,10 @@ void LayoutBlock::ComputeChildPreferredLogicalWidths(
ToLayoutBox(child).ComputeLogicalHeightWithoutLayout();
return;
}
- min_preferred_logical_width = child.MinPreferredLogicalWidth();
- max_preferred_logical_width = child.MaxPreferredLogicalWidth();
+
+ MinMaxSizes child_preferred_logical_widths = child.PreferredLogicalWidths();
+ min_preferred_logical_width = child_preferred_logical_widths.min_size;
+ max_preferred_logical_width = child_preferred_logical_widths.max_size;
// For non-replaced blocks if the inline size is min|max-content or a definite
// size the min|max-content contribution is that size plus border, padding and
@@ -1664,18 +1654,29 @@ void LayoutBlock::ComputeChildPreferredLogicalWidths(
}
bool LayoutBlock::HasLineIfEmpty() const {
- if (!GetNode())
- return false;
-
- if (IsRootEditableElement(*GetNode()))
- return true;
-
- if (auto* shadow_root = DynamicTo<ShadowRoot>(GetNode())) {
- if (IsA<HTMLInputElement>(shadow_root->host()))
+ if (GetNode()) {
+ if (IsRootEditableElement(*GetNode()))
return true;
}
+ return FirstLineStyleRef().HasLineIfEmpty();
+}
- return false;
+LayoutUnit LayoutBlock::EmptyLineBaseline(
+ LineDirectionMode line_direction) const {
+ if (!HasLineIfEmpty())
+ return LayoutUnit(-1);
+ const SimpleFontData* font_data = FirstLineStyle()->GetFont().PrimaryFont();
+ if (!font_data)
+ return LayoutUnit(-1);
+ const auto& font_metrics = font_data->GetFontMetrics();
+ const LayoutUnit line_height =
+ LineHeight(true, line_direction, kPositionOfInteriorLineBoxes);
+ const LayoutUnit border_padding = line_direction == kHorizontalLine
+ ? BorderTop() + PaddingTop()
+ : BorderRight() + PaddingRight();
+ return LayoutUnit((font_metrics.Ascent() +
+ (line_height - font_metrics.Height()) / 2 + border_padding)
+ .ToInt());
}
LayoutUnit LayoutBlock::LineHeight(bool first_line,
@@ -1816,7 +1817,7 @@ bool LayoutBlock::UseLogicalBottomMarginEdgeForInlineBlockBaseline() const {
// where the block's contents shouldn't be considered when laying out its
// ancestors or siblings.
return (!StyleRef().IsOverflowVisible() &&
- !ShouldIgnoreOverflowPropertyForInlineBlockBaseline()) ||
+ !StyleRef().ShouldIgnoreOverflowPropertyForInlineBlockBaseline()) ||
ShouldApplyLayoutContainment();
}
@@ -1845,18 +1846,8 @@ LayoutUnit LayoutBlock::InlineBlockBaseline(
}
}
}
- const SimpleFontData* font_data = FirstLineStyle()->GetFont().PrimaryFont();
- if (font_data && !have_normal_flow_child && HasLineIfEmpty()) {
- const FontMetrics& font_metrics = font_data->GetFontMetrics();
- return LayoutUnit(
- (font_metrics.Ascent() +
- (LineHeight(true, line_direction, kPositionOfInteriorLineBoxes) -
- font_metrics.Height()) /
- 2 +
- (line_direction == kHorizontalLine ? BorderTop() + PaddingTop()
- : BorderRight() + PaddingRight()))
- .ToInt());
- }
+ if (!have_normal_flow_child)
+ return EmptyLineBaseline(line_direction);
return LayoutUnit(-1);
}
@@ -2320,7 +2311,7 @@ LayoutUnit LayoutBlock::AvailableLogicalHeightForPercentageComputation() const {
available_height = computed_values.extent_ -
BorderAndPaddingLogicalHeight() -
ScrollbarLogicalHeight();
- } else if (IsLayoutView()) {
+ } else if (IsA<LayoutView>(this)) {
available_height = View()->ViewLogicalHeightForPercentages();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block.h b/chromium/third_party/blink/renderer/core/layout/layout_block.h
index 64c3ba8c89a..68f16211d48 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block.h
@@ -142,6 +142,10 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
const char* GetName() const override;
+ virtual const NGPhysicalBoxFragment* CurrentFragment() const {
+ return nullptr;
+ }
+
protected:
// Insert a child correctly into the tree when |beforeDescendant| isn't a
// direct child of |this|. This happens e.g. when there's an anonymous block
@@ -395,6 +399,7 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
virtual void PaintChildren(const PaintInfo&,
const PhysicalOffset& paint_offset) const;
void UpdateAfterLayout() override;
+ MinMaxSizes PreferredLogicalWidths() const override;
protected:
virtual void AdjustInlineDirectionLineBounds(
@@ -402,10 +407,7 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
LayoutUnit& /* logicalLeft */,
LayoutUnit& /* logicalWidth */) const {}
- void ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const override;
- void ComputePreferredLogicalWidths() override;
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const override;
void ComputeChildPreferredLogicalWidths(
LayoutObject& child,
LayoutUnit& min_preferred_logical_width,
@@ -414,17 +416,10 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
LayoutUnit FirstLineBoxBaseline() const override;
LayoutUnit InlineBlockBaseline(LineDirectionMode) const override;
- // This function disables the 'overflow' check in inlineBlockBaseline.
- // For 'inline-block', CSS says that the baseline is the bottom margin edge
- // if 'overflow' is not visible. But some descendant classes want to ignore
- // this condition.
- virtual bool ShouldIgnoreOverflowPropertyForInlineBlockBaseline() const {
- return false;
- }
-
- bool HitTestOverflowControl(HitTestResult&,
- const HitTestLocation&,
- const PhysicalOffset& adjusted_location) override;
+ bool HitTestOverflowControl(
+ HitTestResult&,
+ const HitTestLocation&,
+ const PhysicalOffset& adjusted_location) const override;
bool HitTestChildren(HitTestResult&,
const HitTestLocation&,
const PhysicalOffset& accumulated_offset,
@@ -482,6 +477,8 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
hit_test_action == kHitTestChildBlockBackground;
}
+ LayoutUnit EmptyLineBaseline(LineDirectionMode line_direction) const;
+
private:
LayoutObjectChildList* VirtualChildren() final { return Children(); }
const LayoutObjectChildList* VirtualChildren() const final {
@@ -558,7 +555,6 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
// in LayoutBlockRareData since they are
// set too frequently.
unsigned has_margin_after_quirk_ : 1;
- unsigned being_destroyed_ : 1;
unsigned has_markup_truncation_ : 1;
unsigned width_available_to_children_changed_ : 1;
unsigned height_available_to_children_changed_ : 1;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc b/chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc
index 596ea315e8a..b0d5df85710 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc
@@ -77,7 +77,8 @@ bool LayoutBlockFlow::can_propagate_float_into_sibling_ = false;
struct SameSizeAsLayoutBlockFlow : public LayoutBlock {
LineBoxList line_boxes;
- void* pointers[2];
+ void* pointers[1];
+ Persistent<void*> persistent[1];
};
static_assert(sizeof(LayoutBlockFlow) == sizeof(SameSizeAsLayoutBlockFlow),
@@ -131,7 +132,6 @@ class MarginInfo {
bool has_margin_after_quirk_ : 1;
bool determined_margin_before_quirk_ : 1;
- bool discard_margin_ : 1;
bool last_child_is_self_collapsing_block_with_clearance_ : 1;
// These flags track the previous maximal positive and negative margins.
@@ -155,26 +155,21 @@ class MarginInfo {
determined_margin_before_quirk_ = b;
}
void SetPositiveMargin(LayoutUnit p) {
- DCHECK(!discard_margin_);
positive_margin_ = p;
}
void SetNegativeMargin(LayoutUnit n) {
- DCHECK(!discard_margin_);
negative_margin_ = n;
}
void SetPositiveMarginIfLarger(LayoutUnit p) {
- DCHECK(!discard_margin_);
if (p > positive_margin_)
positive_margin_ = p;
}
void SetNegativeMarginIfLarger(LayoutUnit n) {
- DCHECK(!discard_margin_);
if (n > negative_margin_)
negative_margin_ = n;
}
void SetMargin(LayoutUnit p, LayoutUnit n) {
- DCHECK(!discard_margin_);
positive_margin_ = p;
negative_margin_ = n;
}
@@ -184,7 +179,6 @@ class MarginInfo {
void SetCanCollapseMarginAfterWithLastChild(bool collapse) {
can_collapse_margin_after_with_last_child_ = collapse;
}
- void SetDiscardMargin(bool value) { discard_margin_ = value; }
bool AtBeforeSideOfBlock() const { return at_before_side_of_block_; }
bool CanCollapseWithMarginBefore() const {
@@ -211,7 +205,6 @@ class MarginInfo {
bool HasMarginAfterQuirk() const { return has_margin_after_quirk_; }
LayoutUnit PositiveMargin() const { return positive_margin_; }
LayoutUnit NegativeMargin() const { return negative_margin_; }
- bool DiscardMargin() const { return discard_margin_; }
LayoutUnit Margin() const { return positive_margin_ - negative_margin_; }
void SetLastChildIsSelfCollapsingBlockWithClearance(bool value) {
last_child_is_self_collapsing_block_with_clearance_ = value;
@@ -261,9 +254,16 @@ class BlockChildrenLayoutInfo {
bool IsAtFirstInFlowChild() const { return is_at_first_in_flow_child_; }
void ClearIsAtFirstInFlowChild() { is_at_first_in_flow_child_ = false; }
+ // The page name of the previous sibling. Consecutive siblings with the same
+ // name are allowed on the same page, but if they differ, we need a page
+ // break.
+ const AtomicString& ChildPageName() const { return child_page_name_; }
+ void SetChildPageName(const AtomicString& name) { child_page_name_ = name; }
+
private:
MultiColumnLayoutState multi_column_layout_state_;
MarginInfo margin_info_;
+ AtomicString child_page_name_;
LayoutUnit previous_float_logical_bottom_;
EBreakBetween previous_break_after_value_;
bool is_at_first_in_flow_child_;
@@ -387,9 +387,7 @@ bool LayoutBlockFlow::CheckIfIsSelfCollapsingBlock() const {
(element && element->ShadowPseudoId() == "-webkit-input-placeholder"));
if (LogicalHeight() > LayoutUnit() ||
- StyleRef().LogicalMinHeight().IsPositive() ||
- StyleRef().MarginBeforeCollapse() == EMarginCollapse::kSeparate ||
- StyleRef().MarginAfterCollapse() == EMarginCollapse::kSeparate)
+ StyleRef().LogicalMinHeight().IsPositive())
return false;
const Length& logical_height_length = StyleRef().LogicalHeight();
@@ -398,7 +396,7 @@ bool LayoutBlockFlow::CheckIfIsSelfCollapsingBlock() const {
!GetDocument().InQuirksMode()) {
has_auto_height = true;
if (LayoutBlock* cb = ContainingBlock()) {
- if (!cb->IsLayoutView() &&
+ if (!IsA<LayoutView>(cb) &&
(cb->StyleRef().LogicalHeight().IsFixed() || cb->IsTableCell()))
has_auto_height = false;
}
@@ -467,7 +465,7 @@ void LayoutBlockFlow::UpdateBlockLayout(bool relayout_children) {
TextAutosizer::LayoutScope text_autosizer_layout_scope(this, &layout_scope);
bool pagination_state_changed = pagination_state_changed_;
- bool preferred_logical_widths_were_dirty = PreferredLogicalWidthsDirty();
+ bool intrinsic_logical_widths_were_dirty = IntrinsicLogicalWidthsDirty();
// Multiple passes might be required for column based layout.
// The number of passes could be as high as the number of columns.
@@ -484,7 +482,7 @@ void LayoutBlockFlow::UpdateBlockLayout(bool relayout_children) {
LayoutChildren(relayout_children, layout_scope);
- if (!preferred_logical_widths_were_dirty && PreferredLogicalWidthsDirty()) {
+ if (!intrinsic_logical_widths_were_dirty && IntrinsicLogicalWidthsDirty()) {
// The only thing that should dirty preferred widths at this point is the
// addition of overflow:auto scrollbars in a descendant. To avoid a
// potential infinite loop, run layout again with auto scrollbars frozen
@@ -854,6 +852,24 @@ void LayoutBlockFlow::InsertForcedBreakBeforeChildIfNeeded(
// those preceding the break.
EBreakBetween class_a_break_point_value =
child.ClassABreakPointValue(layout_info.PreviousBreakAfterValue());
+
+ bool is_named_page_break;
+ if (layout_info.ChildPageName()) {
+ // Adjacent siblings with the same page name may be put on the same
+ // page. Otherwise, we need a break.
+ is_named_page_break =
+ layout_info.ChildPageName() != child.StyleRef().Page();
+ } else {
+ // If the previous sibling (if any) didn't specify a page name, see if one
+ // is specified on an ancestor. If the child specifies a page name, and it
+ // doesn't match what's specified further up (if anything), we need a break.
+ is_named_page_break =
+ child.StyleRef().Page() &&
+ child.StyleRef().Page() != View()->GetLayoutState()->PageName();
+ }
+ if (is_named_page_break)
+ class_a_break_point_value = EBreakBetween::kPage;
+
if (IsForcedFragmentainerBreakValue(class_a_break_point_value)) {
layout_info.GetMarginInfo().ClearMargin();
LayoutUnit old_logical_top = LogicalHeight();
@@ -862,6 +878,10 @@ void LayoutBlockFlow::InsertForcedBreakBeforeChildIfNeeded(
SetLogicalHeight(new_logical_top);
LayoutUnit pagination_strut = new_logical_top - old_logical_top;
child.SetPaginationStrut(pagination_strut);
+ if (is_named_page_break) {
+ // This was a forced break because of named pages.
+ layout_info.SetChildPageName(child.StyleRef().Page());
+ }
}
}
@@ -898,8 +918,6 @@ void LayoutBlockFlow::LayoutBlockChild(LayoutBox& child,
// Cache if we are at the top of the block right now.
bool at_before_side_of_block = margin_info.AtBeforeSideOfBlock();
bool child_is_self_collapsing = child.IsSelfCollapsingBlock();
- bool child_discard_margin_before = MustDiscardMarginBeforeForChild(child);
- bool child_discard_margin_after = MustDiscardMarginAfterForChild(child);
bool paginated = View()->GetLayoutState()->IsPaginated();
// If there should be a forced break before the child, we need to insert it
@@ -917,15 +935,12 @@ void LayoutBlockFlow::LayoutBlockChild(LayoutBox& child,
// Now determine the correct ypos based off examination of collapsing margin
// values.
LayoutUnit logical_top_before_clear =
- CollapseMargins(child, layout_info, child_is_self_collapsing,
- child_discard_margin_before, child_discard_margin_after);
+ CollapseMargins(child, layout_info, child_is_self_collapsing);
// Now check for clear.
- bool child_discard_margin =
- child_discard_margin_before || child_discard_margin_after;
LayoutUnit new_logical_top = ClearFloatsIfNeeded(
child, margin_info, old_pos_margin_before, old_neg_margin_before,
- logical_top_before_clear, child_is_self_collapsing, child_discard_margin);
+ logical_top_before_clear, child_is_self_collapsing);
// If there's a forced break in front of this child, its final position has
// already been determined. Otherwise, see if there are other reasons for
@@ -982,10 +997,7 @@ void LayoutBlockFlow::LayoutBlockChild(LayoutBox& child,
// Update our height now that the child has been placed in the correct
// position.
SetLogicalHeight(LogicalHeight() + LogicalHeightForChild(child));
- if (MustSeparateMarginAfterForChild(child)) {
- SetLogicalHeight(LogicalHeight() + MarginAfterForChild(child));
- margin_info.ClearMargin();
- }
+
// If the child has overhanging floats that intrude into following siblings
// (or possibly out of this block), then the parent gets notified of the
// floats now.
@@ -1376,8 +1388,9 @@ void LayoutBlockFlow::RebuildFloatsFromIntruding() {
// Inline blocks are covered by the isAtomicInlineLevel() check in the
// avoidFloats method.
- if (CreatesNewFormattingContext() || IsDocumentElement() || IsLayoutView() ||
- IsFloatingOrOutOfFlowPositioned() || IsTableCell()) {
+ if (CreatesNewFormattingContext() || IsDocumentElement() ||
+ IsA<LayoutView>(this) || IsFloatingOrOutOfFlowPositioned() ||
+ IsTableCell()) {
if (floating_objects_) {
floating_objects_->Clear();
}
@@ -1620,17 +1633,15 @@ MarginInfo::MarginInfo(LayoutBlockFlow* block_flow,
has_margin_before_quirk_(false),
has_margin_after_quirk_(false),
determined_margin_before_quirk_(false),
- discard_margin_(false),
last_child_is_self_collapsing_block_with_clearance_(false) {
const ComputedStyle& block_style = block_flow->StyleRef();
- DCHECK(block_flow->IsLayoutView() || block_flow->Parent());
+ DCHECK(IsA<LayoutView>(block_flow) || block_flow->Parent());
can_collapse_with_children_ = !block_flow->CreatesNewFormattingContext() &&
!block_flow->IsLayoutFlowThread() &&
- !block_flow->IsLayoutView();
+ !IsA<LayoutView>(block_flow);
can_collapse_margin_before_with_children_ =
- can_collapse_with_children_ && !before_border_padding &&
- block_style.MarginBeforeCollapse() != EMarginCollapse::kSeparate;
+ can_collapse_with_children_ && !before_border_padding;
// If any height other than auto is specified in CSS, then we don't collapse
// our bottom margins with our children's margins. To do otherwise would be to
@@ -1640,20 +1651,14 @@ MarginInfo::MarginInfo(LayoutBlockFlow* block_flow,
can_collapse_margin_after_with_children_ =
can_collapse_with_children_ && !after_border_padding &&
(block_style.LogicalHeight().IsAuto() &&
- !block_style.LogicalHeight().Value()) &&
- block_style.MarginAfterCollapse() != EMarginCollapse::kSeparate;
+ !block_style.LogicalHeight().Value());
quirk_container_ = block_flow->IsTableCell() || block_flow->IsBody();
- discard_margin_ = can_collapse_margin_before_with_children_ &&
- block_flow->MustDiscardMarginBefore();
-
- positive_margin_ = (can_collapse_margin_before_with_children_ &&
- !block_flow->MustDiscardMarginBefore())
+ positive_margin_ = can_collapse_margin_before_with_children_
? block_flow->MaxPositiveMarginBefore()
: LayoutUnit();
- negative_margin_ = (can_collapse_margin_before_with_children_ &&
- !block_flow->MustDiscardMarginBefore())
+ negative_margin_ = can_collapse_margin_before_with_children_
? block_flow->MaxNegativeMarginBefore()
: LayoutUnit();
}
@@ -1766,17 +1771,9 @@ static LayoutBlockFlow* PreviousBlockFlowInFormattingContext(
LayoutUnit LayoutBlockFlow::CollapseMargins(
LayoutBox& child,
BlockChildrenLayoutInfo& layout_info,
- bool child_is_self_collapsing,
- bool child_discard_margin_before,
- bool child_discard_margin_after) {
+ bool child_is_self_collapsing) {
MarginInfo& margin_info = layout_info.GetMarginInfo();
- // The child discards the before margin when the the after margin has discard
- // in the case of a self collapsing block.
- child_discard_margin_before =
- child_discard_margin_before ||
- (child_discard_margin_after && child_is_self_collapsing);
-
// Get the four margin values for the child and cache them.
const LayoutBlockFlow::MarginValues child_margins =
MarginValuesForChild(child);
@@ -1797,46 +1794,32 @@ LayoutUnit LayoutBlockFlow::CollapseMargins(
bool top_quirk = HasMarginBeforeQuirk(&child);
if (margin_info.CanCollapseWithMarginBefore()) {
- if (!child_discard_margin_before && !margin_info.DiscardMargin()) {
- // This child is collapsing with the top of the
- // block. If it has larger margin values, then we need to update
- // our own maximal values.
- if (!GetDocument().InQuirksMode() || !margin_info.QuirkContainer() ||
- !top_quirk)
- SetMaxMarginBeforeValues(std::max(pos_top, MaxPositiveMarginBefore()),
- std::max(neg_top, MaxNegativeMarginBefore()));
-
- // The minute any of the margins involved isn't a quirk, don't
- // collapse it away, even if the margin is smaller (www.webreference.com
- // has an example of this, a <dt> with 0.8em author-specified inside
- // a <dl> inside a <td>.
- if (!margin_info.DeterminedMarginBeforeQuirk() && !top_quirk &&
- (pos_top - neg_top)) {
- SetHasMarginBeforeQuirk(false);
- margin_info.SetDeterminedMarginBeforeQuirk(true);
- }
+ // This child is collapsing with the top of the block. If it has larger
+ // margin values, then we need to update our own maximal values.
+ if (!GetDocument().InQuirksMode() || !margin_info.QuirkContainer() ||
+ !top_quirk) {
+ SetMaxMarginBeforeValues(std::max(pos_top, MaxPositiveMarginBefore()),
+ std::max(neg_top, MaxNegativeMarginBefore()));
+ }
- if (!margin_info.DeterminedMarginBeforeQuirk() && top_quirk &&
- !MarginBefore()) {
- // We have no top margin and our top child has a quirky margin.
- // We will pick up this quirky margin and pass it through.
- // This deals with the <td><div><p> case.
- // Don't do this for a block that split two inlines though. You do
- // still apply margins in this case.
- SetHasMarginBeforeQuirk(true);
- }
- } else {
- // The before margin of the container will also discard all the margins it
- // is collapsing with.
- SetMustDiscardMarginBefore();
+ // The minute any of the margins involved isn't a quirk, don't collapse it
+ // away, even if the margin is smaller (www.webreference.com has an example
+ // of this, a <dt> with 0.8em author-specified inside a <dl> inside a <td>).
+ if (!margin_info.DeterminedMarginBeforeQuirk() && !top_quirk &&
+ (pos_top - neg_top)) {
+ SetHasMarginBeforeQuirk(false);
+ margin_info.SetDeterminedMarginBeforeQuirk(true);
}
- }
- // Once we find a child with discardMarginBefore all the margins collapsing
- // with us must also discard.
- if (child_discard_margin_before) {
- margin_info.SetDiscardMargin(true);
- margin_info.ClearMargin();
+ if (!margin_info.DeterminedMarginBeforeQuirk() && top_quirk &&
+ !MarginBefore()) {
+ // We have no top margin and our top child has a quirky margin.
+ // We will pick up this quirky margin and pass it through.
+ // This deals with the <td><div><p> case.
+ // Don't do this for a block that split two inlines though. You do still
+ // apply margins in this case.
+ SetHasMarginBeforeQuirk(true);
+ }
}
if (margin_info.QuirkContainer() && margin_info.AtBeforeSideOfBlock() &&
@@ -1866,71 +1849,46 @@ LayoutUnit LayoutBlockFlow::CollapseMargins(
MarginValuesForChild(*previous_block_flow).PositiveMarginBefore());
if (child_is_self_collapsing) {
- // For a self collapsing block both the before and after margins get
- // discarded. The block doesn't contribute anything to the height of the
- // block. Also, the child's top position equals the logical height of the
- // container.
- if (!child_discard_margin_before && !margin_info.DiscardMargin()) {
- // This child has no height. We need to compute our
- // position before we collapse the child's margins together,
- // so that we can get an accurate position for the zero-height block.
- LayoutUnit collapsed_before_pos = std::max(
- margin_info.PositiveMargin(), child_margins.PositiveMarginBefore());
- LayoutUnit collapsed_before_neg = std::max(
- margin_info.NegativeMargin(), child_margins.NegativeMarginBefore());
- margin_info.SetMargin(collapsed_before_pos, collapsed_before_neg);
-
- // Now collapse the child's margins together, which means examining our
- // bottom margin values as well.
- margin_info.SetPositiveMarginIfLarger(
- child_margins.PositiveMarginAfter());
- margin_info.SetNegativeMarginIfLarger(
- child_margins.NegativeMarginAfter());
-
- if (!margin_info.CanCollapseWithMarginBefore()) {
- // We need to make sure that the position of the self-collapsing block
- // is correct, since it could have overflowing content
- // that needs to be positioned correctly (e.g., a block that
- // had a specified height of 0 but that actually had subcontent).
- logical_top =
- LogicalHeight() + collapsed_before_pos - collapsed_before_neg;
- }
+ // The block doesn't contribute anything to the height of the block. Also,
+ // the child's top position equals the logical height of the container.
+
+ // This child has no height. We need to compute our position before we
+ // collapse the child's margins together, so that we can get an accurate
+ // position for the zero-height block.
+ LayoutUnit collapsed_before_pos = std::max(
+ margin_info.PositiveMargin(), child_margins.PositiveMarginBefore());
+ LayoutUnit collapsed_before_neg = std::max(
+ margin_info.NegativeMargin(), child_margins.NegativeMarginBefore());
+ margin_info.SetMargin(collapsed_before_pos, collapsed_before_neg);
+
+ // Now collapse the child's margins together, which means examining our
+ // bottom margin values as well.
+ margin_info.SetPositiveMarginIfLarger(child_margins.PositiveMarginAfter());
+ margin_info.SetNegativeMarginIfLarger(child_margins.NegativeMarginAfter());
+
+ if (!margin_info.CanCollapseWithMarginBefore()) {
+ // We need to make sure that the position of the self-collapsing block is
+ // correct, since it could have overflowing content that needs to be
+ // positioned correctly (e.g., a block that had a specified height of 0
+ // but that actually had subcontent).
+ logical_top =
+ LogicalHeight() + collapsed_before_pos - collapsed_before_neg;
}
} else {
- if (MustSeparateMarginBeforeForChild(child)) {
- DCHECK(!margin_info.DiscardMargin() ||
- (margin_info.DiscardMargin() && !margin_info.Margin()));
- // If we are at the before side of the block and we collapse, ignore the
- // computed margin and just add the child margin to the container height.
- // This will correctly position the child inside the container.
- LayoutUnit separate_margin = !margin_info.CanCollapseWithMarginBefore()
- ? margin_info.Margin()
- : LayoutUnit();
- SetLogicalHeight(LogicalHeight() + separate_margin +
- MarginBeforeForChild(child));
- logical_top = LogicalHeight();
- } else if (!margin_info.DiscardMargin() &&
- (!margin_info.AtBeforeSideOfBlock() ||
- (!margin_info.CanCollapseMarginBeforeWithChildren() &&
- (!GetDocument().InQuirksMode() ||
- !margin_info.QuirkContainer() ||
- !margin_info.HasMarginBeforeQuirk())))) {
- // We're collapsing with a previous sibling's margins and not
- // with the top of the block.
+ if (!margin_info.AtBeforeSideOfBlock() ||
+ (!margin_info.CanCollapseMarginBeforeWithChildren() &&
+ (!GetDocument().InQuirksMode() || !margin_info.QuirkContainer() ||
+ !margin_info.HasMarginBeforeQuirk()))) {
+ // We're collapsing with a previous sibling's margins and not with the
+ // top of the block.
SetLogicalHeight(LogicalHeight() +
std::max(margin_info.PositiveMargin(), pos_top) -
std::max(margin_info.NegativeMargin(), neg_top));
logical_top = LogicalHeight();
}
- margin_info.SetDiscardMargin(child_discard_margin_after);
-
- if (!margin_info.DiscardMargin()) {
- margin_info.SetPositiveMargin(child_margins.PositiveMarginAfter());
- margin_info.SetNegativeMargin(child_margins.NegativeMarginAfter());
- } else {
- margin_info.ClearMargin();
- }
+ margin_info.SetPositiveMargin(child_margins.PositiveMarginAfter());
+ margin_info.SetNegativeMargin(child_margins.NegativeMarginAfter());
if (margin_info.Margin())
margin_info.SetHasMarginAfterQuirk(HasMarginAfterQuirk(&child));
@@ -2016,8 +1974,7 @@ LayoutUnit LayoutBlockFlow::ClearFloatsIfNeeded(LayoutBox& child,
LayoutUnit old_top_pos_margin,
LayoutUnit old_top_neg_margin,
LayoutUnit y_pos,
- bool child_is_self_collapsing,
- bool child_discard_margin) {
+ bool child_is_self_collapsing) {
LayoutUnit height_increase = GetClearDelta(&child, y_pos);
margin_info.SetLastChildIsSelfCollapsingBlockWithClearance(false);
@@ -2026,24 +1983,17 @@ LayoutUnit LayoutBlockFlow::ClearFloatsIfNeeded(LayoutBox& child,
if (child_is_self_collapsing) {
margin_info.SetLastChildIsSelfCollapsingBlockWithClearance(true);
- margin_info.SetDiscardMargin(child_discard_margin);
// For self-collapsing blocks that clear, they can still collapse their
// margins with following siblings. Reset the current margins to represent
// the self-collapsing block's margins only.
- // If DISCARD is specified for -webkit-margin-collapse, reset the margin
- // values.
LayoutBlockFlow::MarginValues child_margins = MarginValuesForChild(child);
- if (!child_discard_margin) {
- margin_info.SetPositiveMargin(
- std::max(child_margins.PositiveMarginBefore(),
- child_margins.PositiveMarginAfter()));
- margin_info.SetNegativeMargin(
- std::max(child_margins.NegativeMarginBefore(),
- child_margins.NegativeMarginAfter()));
- } else {
- margin_info.ClearMargin();
- }
+ margin_info.SetPositiveMargin(
+ std::max(child_margins.PositiveMarginBefore(),
+ child_margins.PositiveMarginAfter()));
+ margin_info.SetNegativeMargin(
+ std::max(child_margins.NegativeMarginBefore(),
+ child_margins.NegativeMarginAfter()));
// CSS2.1 states:
// "If the top and bottom margins of an element with clearance are
@@ -2080,11 +2030,6 @@ LayoutUnit LayoutBlockFlow::ClearFloatsIfNeeded(LayoutBox& child,
// occurred. The empty blocks collapse into the cleared block.
SetMaxMarginBeforeValues(old_top_pos_margin, old_top_neg_margin);
margin_info.SetAtBeforeSideOfBlock(false);
-
- // In case the child discarded the before margin of the block we need to
- // reset the mustDiscardMarginBefore flag to the initial value.
- SetMustDiscardMarginBefore(StyleRef().MarginBeforeCollapse() ==
- EMarginCollapse::kDiscard);
}
return y_pos + height_increase;
@@ -2093,14 +2038,6 @@ LayoutUnit LayoutBlockFlow::ClearFloatsIfNeeded(LayoutBox& child,
void LayoutBlockFlow::SetCollapsedBottomMargin(const MarginInfo& margin_info) {
if (margin_info.CanCollapseWithMarginAfter() &&
!margin_info.CanCollapseWithMarginBefore()) {
- // Update the after side margin of the container to discard if the after
- // margin of the last child also discards and we collapse with it.
- // Don't update the max margin values because we won't need them anyway.
- if (margin_info.DiscardMargin()) {
- SetMustDiscardMarginAfter();
- return;
- }
-
// Update our max pos/neg bottom margins, since we collapsed our bottom
// margins with our children.
SetMaxMarginAfterValues(
@@ -2123,28 +2060,14 @@ DISABLE_CFI_PERF
void LayoutBlockFlow::MarginBeforeEstimateForChild(
LayoutBox& child,
LayoutUnit& positive_margin_before,
- LayoutUnit& negative_margin_before,
- bool& discard_margin_before) const {
+ LayoutUnit& negative_margin_before) const {
// Give up if in quirks mode and we're a body/table cell and the top margin of
// the child box is quirky.
- // Give up if the child specified -webkit-margin-collapse: separate that
- // prevents collapsing.
// FIXME: Use writing mode independent accessor for marginBeforeCollapse.
- if ((GetDocument().InQuirksMode() && HasMarginBeforeQuirk(&child) &&
- (IsTableCell() || IsBody())) ||
- child.StyleRef().MarginBeforeCollapse() == EMarginCollapse::kSeparate)
+ if (GetDocument().InQuirksMode() && HasMarginBeforeQuirk(&child) &&
+ (IsTableCell() || IsBody()))
return;
- // The margins are discarded by a child that specified
- // -webkit-margin-collapse: discard.
- // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
- if (child.StyleRef().MarginBeforeCollapse() == EMarginCollapse::kDiscard) {
- positive_margin_before = LayoutUnit();
- negative_margin_before = LayoutUnit();
- discard_margin_before = true;
- return;
- }
-
LayoutUnit before_child_margin = MarginBeforeForChild(child);
positive_margin_before =
std::max(positive_margin_before, before_child_margin);
@@ -2200,8 +2123,7 @@ void LayoutBlockFlow::MarginBeforeEstimateForChild(
// Collapse the margin of the grandchild box with our own to produce an
// estimate.
child_block_flow->MarginBeforeEstimateForChild(
- *grandchild_box, positive_margin_before, negative_margin_before,
- discard_margin_before);
+ *grandchild_box, positive_margin_before, negative_margin_before);
}
LayoutUnit LayoutBlockFlow::EstimateLogicalTopPosition(
@@ -2215,13 +2137,11 @@ LayoutUnit LayoutBlockFlow::EstimateLogicalTopPosition(
LayoutUnit logical_top_estimate = LogicalHeight();
LayoutUnit positive_margin_before;
LayoutUnit negative_margin_before;
- bool discard_margin_before = false;
if (!margin_info.CanCollapseWithMarginBefore()) {
if (child.SelfNeedsLayout()) {
// Try to do a basic estimation of how the collapse is going to go.
MarginBeforeEstimateForChild(child, positive_margin_before,
- negative_margin_before,
- discard_margin_before);
+ negative_margin_before);
} else {
// Use the cached collapsed margin values from a previous layout. Most of
// the time they will be right.
@@ -2230,14 +2150,12 @@ LayoutUnit LayoutBlockFlow::EstimateLogicalTopPosition(
margin_values.PositiveMarginBefore());
negative_margin_before = std::max(negative_margin_before,
margin_values.NegativeMarginBefore());
- discard_margin_before = MustDiscardMarginBeforeForChild(child);
}
// Collapse the result with our current margins.
- if (!discard_margin_before)
- logical_top_estimate +=
- std::max(margin_info.PositiveMargin(), positive_margin_before) -
- std::max(margin_info.NegativeMargin(), negative_margin_before);
+ logical_top_estimate +=
+ std::max(margin_info.PositiveMargin(), positive_margin_before) -
+ std::max(margin_info.NegativeMargin(), negative_margin_before);
}
LayoutState* layout_state = View()->GetLayoutState();
@@ -2265,9 +2183,7 @@ LayoutUnit LayoutBlockFlow::EstimateLogicalTopPosition(
// Disregard previous margins, since they will collapse with the
// fragmentainer boundary, due to the forced break. Only apply margins
// that have been specified on the child or its descendants.
- if (!discard_margin_before)
- logical_top_estimate +=
- positive_margin_before - negative_margin_before;
+ logical_top_estimate += positive_margin_before - negative_margin_before;
// Clearance may already have taken us past the beginning of the next
// fragmentainer.
@@ -2325,11 +2241,10 @@ void LayoutBlockFlow::HandleAfterSideOfBlock(LayoutBox* last_child,
// If we can't collapse with children then go ahead and add in the bottom
// margin.
- if (!margin_info.DiscardMargin() &&
- (!margin_info.CanCollapseWithMarginAfter() &&
- !margin_info.CanCollapseWithMarginBefore() &&
- (!GetDocument().InQuirksMode() || !margin_info.QuirkContainer() ||
- !margin_info.HasMarginAfterQuirk())))
+ if (!margin_info.CanCollapseWithMarginAfter() &&
+ !margin_info.CanCollapseWithMarginBefore() &&
+ (!GetDocument().InQuirksMode() || !margin_info.QuirkContainer() ||
+ !margin_info.HasMarginAfterQuirk()))
SetLogicalHeight(LogicalHeight() + margin_info.Margin());
// Now add in our bottom border/padding.
@@ -2352,97 +2267,12 @@ void LayoutBlockFlow::HandleAfterSideOfBlock(LayoutBox* last_child,
JoinFragmentainerBreakValues(BreakAfter(), last_child->BreakAfter()));
}
-void LayoutBlockFlow::SetMustDiscardMarginBefore(bool value) {
- if (StyleRef().MarginBeforeCollapse() == EMarginCollapse::kDiscard) {
- DCHECK(value);
- return;
- }
-
- if (!rare_data_ && !value)
- return;
-
- if (!rare_data_)
- rare_data_ = std::make_unique<LayoutBlockFlowRareData>(this);
-
- rare_data_->discard_margin_before_ = value;
-}
-
-void LayoutBlockFlow::SetMustDiscardMarginAfter(bool value) {
- if (StyleRef().MarginAfterCollapse() == EMarginCollapse::kDiscard) {
- DCHECK(value);
- return;
- }
-
- if (!rare_data_ && !value)
- return;
-
- if (!rare_data_)
- rare_data_ = std::make_unique<LayoutBlockFlowRareData>(this);
-
- rare_data_->discard_margin_after_ = value;
-}
-
-bool LayoutBlockFlow::MustDiscardMarginBefore() const {
- return StyleRef().MarginBeforeCollapse() == EMarginCollapse::kDiscard ||
- (rare_data_ && rare_data_->discard_margin_before_);
-}
-
-bool LayoutBlockFlow::MustDiscardMarginAfter() const {
- return StyleRef().MarginAfterCollapse() == EMarginCollapse::kDiscard ||
- (rare_data_ && rare_data_->discard_margin_after_);
-}
-
-bool LayoutBlockFlow::MustDiscardMarginBeforeForChild(
- const LayoutBox& child) const {
- DCHECK(!child.SelfNeedsLayout() ||
- child.LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kSelf));
- if (!child.IsWritingModeRoot()) {
- auto* child_layout_block = DynamicTo<LayoutBlockFlow>(&child);
- return child_layout_block ? child_layout_block->MustDiscardMarginBefore()
- : (child.StyleRef().MarginBeforeCollapse() ==
- EMarginCollapse::kDiscard);
- }
- if (child.IsHorizontalWritingMode() == IsHorizontalWritingMode()) {
- auto* child_layout_block = DynamicTo<LayoutBlockFlow>(&child);
- return child_layout_block ? child_layout_block->MustDiscardMarginAfter()
- : (child.StyleRef().MarginAfterCollapse() ==
- EMarginCollapse::kDiscard);
- }
-
- // FIXME: We return false here because the implementation is not geometrically
- // complete. We have values only for before/after, not start/end.
- // In case the boxes are perpendicular we assume the property is not
- // specified.
- return false;
-}
-
-bool LayoutBlockFlow::MustDiscardMarginAfterForChild(
- const LayoutBox& child) const {
- DCHECK(!child.SelfNeedsLayout() ||
- child.LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kSelf));
- if (!child.IsWritingModeRoot()) {
- auto* child_layout_block = DynamicTo<LayoutBlockFlow>(&child);
- return child_layout_block ? child_layout_block->MustDiscardMarginAfter()
- : (child.StyleRef().MarginAfterCollapse() ==
- EMarginCollapse::kDiscard);
- }
- if (child.IsHorizontalWritingMode() == IsHorizontalWritingMode()) {
- auto* child_layout_block = DynamicTo<LayoutBlockFlow>(&child);
- return child_layout_block ? child_layout_block->MustDiscardMarginBefore()
- : (child.StyleRef().MarginBeforeCollapse() ==
- EMarginCollapse::kDiscard);
- }
-
- // FIXME: See |mustDiscardMarginBeforeForChild| above.
- return false;
-}
-
void LayoutBlockFlow::SetMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg) {
if (!rare_data_) {
if (pos == LayoutBlockFlowRareData::PositiveMarginBeforeDefault(this) &&
neg == LayoutBlockFlowRareData::NegativeMarginBeforeDefault(this))
return;
- rare_data_ = std::make_unique<LayoutBlockFlowRareData>(this);
+ rare_data_ = MakeGarbageCollected<LayoutBlockFlowRareData>(this);
}
rare_data_->margins_.SetPositiveMarginBefore(pos);
rare_data_->margins_.SetNegativeMarginBefore(neg);
@@ -2453,40 +2283,12 @@ void LayoutBlockFlow::SetMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg) {
if (pos == LayoutBlockFlowRareData::PositiveMarginAfterDefault(this) &&
neg == LayoutBlockFlowRareData::NegativeMarginAfterDefault(this))
return;
- rare_data_ = std::make_unique<LayoutBlockFlowRareData>(this);
+ rare_data_ = MakeGarbageCollected<LayoutBlockFlowRareData>(this);
}
rare_data_->margins_.SetPositiveMarginAfter(pos);
rare_data_->margins_.SetNegativeMarginAfter(neg);
}
-bool LayoutBlockFlow::MustSeparateMarginBeforeForChild(
- const LayoutBox& child) const {
- DCHECK(!child.SelfNeedsLayout() ||
- child.LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kSelf));
- const ComputedStyle& child_style = child.StyleRef();
- if (!child.IsWritingModeRoot())
- return child_style.MarginBeforeCollapse() == EMarginCollapse::kSeparate;
- if (child.IsHorizontalWritingMode() == IsHorizontalWritingMode())
- return child_style.MarginAfterCollapse() == EMarginCollapse::kSeparate;
-
- // FIXME: See |mustDiscardMarginBeforeForChild| above.
- return false;
-}
-
-bool LayoutBlockFlow::MustSeparateMarginAfterForChild(
- const LayoutBox& child) const {
- DCHECK(!child.SelfNeedsLayout() ||
- child.LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kSelf));
- const ComputedStyle& child_style = child.StyleRef();
- if (!child.IsWritingModeRoot())
- return child_style.MarginAfterCollapse() == EMarginCollapse::kSeparate;
- if (child.IsHorizontalWritingMode() == IsHorizontalWritingMode())
- return child_style.MarginBeforeCollapse() == EMarginCollapse::kSeparate;
-
- // FIXME: See |mustDiscardMarginBeforeForChild| above.
- return false;
-}
-
LayoutUnit LayoutBlockFlow::ApplyForcedBreak(LayoutUnit logical_offset,
EBreakBetween break_value) {
if (!IsForcedFragmentainerBreakValue(break_value))
@@ -2559,6 +2361,27 @@ void LayoutBlockFlow::AddVisualOverflowFromFloats() {
}
}
+void LayoutBlockFlow::AddVisualOverflowFromFloats(
+ const NGPhysicalContainerFragment& fragment) {
+ DCHECK(fragment.HasFloatingDescendantsForPaint());
+ for (const NGLink& child : fragment.Children()) {
+ if (child->HasSelfPaintingLayer())
+ continue;
+
+ if (child->IsFloating()) {
+ AddVisualOverflowFromChild(ToLayoutBox(*child->GetLayoutObject()));
+ continue;
+ }
+
+ if (const NGPhysicalContainerFragment* child_container =
+ DynamicTo<NGPhysicalContainerFragment>(child.get())) {
+ if (child_container->HasFloatingDescendantsForPaint() &&
+ !child_container->IsFormattingContextRoot())
+ AddVisualOverflowFromFloats(*child_container);
+ }
+ }
+}
+
void LayoutBlockFlow::AddLayoutOverflowFromFloats() {
if (!floating_objects_)
return;
@@ -2597,6 +2420,7 @@ void LayoutBlockFlow::ComputeVisualOverflow(
HasSelfPaintingLayer()))
AddVisualOverflowFromFloats();
if (VisualOverflowRect() != previous_visual_overflow_rect) {
+ InvalidateIntersectionObserverCachedRects();
SetShouldCheckForPaintInvalidation();
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
}
@@ -2712,15 +2536,13 @@ LayoutUnit LayoutBlockFlow::FirstLineBoxBaseline() const {
NGBoxFragment box_fragment(
StyleRef().GetWritingMode(), StyleRef().Direction(),
To<NGPhysicalBoxFragment>(paint_fragment->PhysicalFragment()));
- NGLineHeightMetrics metrics =
- box_fragment.BaselineMetricsWithoutSynthesize(
- {NGBaselineAlgorithmType::kFirstLine,
- StyleRef().GetFontBaseline()});
- if (!metrics.IsEmpty())
- return metrics.ascent;
+ base::Optional<LayoutUnit> baseline = box_fragment.Baseline();
+ if (baseline)
+ return *baseline;
}
}
- return LayoutUnit(-1);
+ return EmptyLineBaseline(IsHorizontalWritingMode() ? kHorizontalLine
+ : kVerticalLine);
}
LayoutUnit LayoutBlockFlow::InlineBlockBaseline(
@@ -2750,23 +2572,7 @@ LayoutUnit LayoutBlockFlow::InlineBlockBaseline(
return LastLineBox()->LogicalTop() +
font_data->GetFontMetrics().Ascent(LastRootBox()->BaselineType());
}
- if (!HasLineIfEmpty())
- return LayoutUnit(-1);
-
- const SimpleFontData* font_data = FirstLineStyle()->GetFont().PrimaryFont();
- DCHECK(font_data);
- if (!font_data)
- return LayoutUnit(-1);
-
- const FontMetrics& font_metrics = font_data->GetFontMetrics();
- return LayoutUnit(
- (font_metrics.Ascent() +
- (LineHeight(true, line_direction, kPositionOfInteriorLineBoxes) -
- font_metrics.Height()) /
- 2 +
- (line_direction == kHorizontalLine ? BorderTop() + PaddingTop()
- : BorderRight() + PaddingRight()))
- .ToInt());
+ return EmptyLineBaseline(line_direction);
}
void LayoutBlockFlow::RemoveFloatingObjectsFromDescendants() {
@@ -2939,9 +2745,6 @@ void LayoutBlockFlow::CreateFloatingObjects() {
}
void LayoutBlockFlow::WillBeDestroyed() {
- // Mark as being destroyed to avoid trouble with merges in removeChild().
- being_destroyed_ = true;
-
// Make sure to destroy anonymous children first while they are still
// connected to the rest of the tree, so that they will properly dirty line
// boxes that they are removed from. Effects that do :before/:after only on
@@ -3030,7 +2833,7 @@ void LayoutBlockFlow::StyleDidChange(StyleDifference diff,
const FloatingObjectSet& floating_object_set = floating_objects_->Set();
FloatingObjectSetIterator end = floating_object_set.end();
- for (LayoutObject* curr = Parent(); curr && !curr->IsLayoutView();
+ for (LayoutObject* curr = Parent(); !IsA<LayoutView>(curr);
curr = curr->Parent()) {
auto* curr_block = DynamicTo<LayoutBlockFlow>(curr);
if (curr_block) {
@@ -3149,9 +2952,9 @@ void LayoutBlockFlow::AddChild(LayoutObject* new_child,
return;
}
- // LayoutNGListMarker is out-of-flow for the tree building purpose, and that
- // is not inline level, but IsInline().
- if (new_child->IsInline() && !new_child->IsLayoutNGListMarker()) {
+ // LayoutNGOutsideListMarker is out-of-flow for the tree building purpose,
+ // and that is not inline level, but IsInline().
+ if (new_child->IsInline() && !new_child->IsLayoutNGOutsideListMarker()) {
// No suitable existing anonymous box - create a new one.
auto* new_block = To<LayoutBlockFlow>(CreateAnonymousBlock());
LayoutBox::AddChild(new_block, before_child);
@@ -3364,7 +3167,7 @@ void LayoutBlockFlow::CollapseAnonymousBlockChild(LayoutBlockFlow* child) {
// design, so we don't remove them.
if (child->IsRubyRun() || child->IsRubyBase())
return;
- SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kChildAnonymousBlockChanged);
child->MoveAllChildrenTo(this, child->NextSibling(), child->HasLayer());
@@ -3390,7 +3193,7 @@ bool LayoutBlockFlow::MergeSiblingContiguousAnonymousBlock(
!IsMergeableAnonymousBlock(sibling_that_may_be_deleted))
return false;
- SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kAnonymousBlockChange);
// If the inlineness of children of the two block don't match, we'd need
@@ -3510,9 +3313,9 @@ static void GetInlineRun(LayoutObject* start,
// Start by skipping as many non-inlines as we can.
LayoutObject* curr = start;
- // LayoutNGListMarker is out-of-flow for the tree building purpose. Skip here
- // because it's the first child.
- if (curr && curr->IsLayoutNGListMarker())
+ // LayoutNGOutsideListMarker is out-of-flow for the tree building purpose.
+ // Skip here because it's the first child.
+ if (curr && curr->IsLayoutNGOutsideListMarker())
curr = curr->NextSibling();
bool saw_inline;
@@ -3577,7 +3380,7 @@ void LayoutBlockFlow::MakeChildrenNonInline(LayoutObject* insertion_point) {
#if DCHECK_IS_ON()
for (LayoutObject* c = FirstChild(); c; c = c->NextSibling())
- DCHECK(!c->IsInline() || c->IsLayoutNGListMarker());
+ DCHECK(!c->IsInline() || c->IsLayoutNGOutsideListMarker());
#endif
SetShouldDoFullPaintInvalidation();
@@ -4422,7 +4225,7 @@ void LayoutBlockFlow::SetPaginationStrutPropagatedFromChild(LayoutUnit strut) {
if (!rare_data_) {
if (!strut)
return;
- rare_data_ = std::make_unique<LayoutBlockFlowRareData>(this);
+ rare_data_ = MakeGarbageCollected<LayoutBlockFlowRareData>(this);
}
rare_data_->pagination_strut_propagated_from_child_ = strut;
}
@@ -4431,7 +4234,7 @@ void LayoutBlockFlow::SetFirstForcedBreakOffset(LayoutUnit block_offset) {
if (!rare_data_) {
if (!block_offset)
return;
- rare_data_ = std::make_unique<LayoutBlockFlowRareData>(this);
+ rare_data_ = MakeGarbageCollected<LayoutBlockFlowRareData>(this);
}
rare_data_->first_forced_break_offset_ = block_offset;
}
@@ -4450,7 +4253,7 @@ bool LayoutBlockFlow::CreatesNewFormattingContext() const {
if (IsInline() || IsFloatingOrOutOfFlowPositioned() || HasOverflowClip() ||
IsFlexItemIncludingDeprecatedAndNG() || IsCustomItem() ||
IsDocumentElement() || IsGridItem() || IsWritingModeRoot() ||
- StyleRef().Display() == EDisplay::kFlowRoot ||
+ IsMathItem() || StyleRef().Display() == EDisplay::kFlowRoot ||
ShouldApplyPaintContainment() || ShouldApplyLayoutContainment() ||
StyleRef().SpecifiesColumns() ||
StyleRef().GetColumnSpan() == EColumnSpan::kAll) {
@@ -4518,7 +4321,7 @@ void LayoutBlockFlow::CreateOrDestroyMultiColumnFlowThreadIfNeeded(
// Form controls are replaced content, and are therefore not supposed to
// support multicol.
- if (IsFileUploadControl() || IsTextControl() || IsListBox())
+ if (IsFileUploadControl() || IsTextControl() || IsListBox(this))
return;
// We don't allow custom layout and multicol on the same object. This is
@@ -4546,7 +4349,7 @@ LayoutBlockFlow::LayoutBlockFlowRareData& LayoutBlockFlow::EnsureRareData() {
if (rare_data_)
return *rare_data_;
- rare_data_ = std::make_unique<LayoutBlockFlowRareData>(this);
+ rare_data_ = MakeGarbageCollected<LayoutBlockFlowRareData>(this);
return *rare_data_;
}
@@ -4631,10 +4434,9 @@ void LayoutBlockFlow::RecalcInlineChildrenVisualOverflow() {
if (const NGFragmentItems* items = fragment->Items()) {
NGInlineCursor cursor(*items);
NGFragmentItem::RecalcInkOverflowForCursor(&cursor);
- }
-
- if (fragment->HasFloatingDescendantsForPaint())
+ } else if (fragment->HasFloatingDescendantsForPaint()) {
RecalcFloatingDescendantsVisualOverflow(*fragment);
+ }
return;
}
}
@@ -4946,9 +4748,7 @@ LayoutBlockFlow::LayoutBlockFlowRareData::LayoutBlockFlowRareData(
break_before_(static_cast<unsigned>(EBreakBetween::kAuto)),
break_after_(static_cast<unsigned>(EBreakBetween::kAuto)),
line_break_to_avoid_widow_(-1),
- did_break_at_line_to_avoid_widow_(false),
- discard_margin_before_(false),
- discard_margin_after_(false) {}
+ did_break_at_line_to_avoid_widow_(false) {}
LayoutBlockFlow::LayoutBlockFlowRareData::~LayoutBlockFlowRareData() = default;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block_flow.h b/chromium/third_party/blink/renderer/core/layout/layout_block_flow.h
index bbe43e33163..e7f1a334a53 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block_flow.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block_flow.h
@@ -105,7 +105,6 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
static LayoutBlockFlow* CreateAnonymous(Document*,
scoped_refptr<ComputedStyle>,
LegacyLayout);
- bool BeingDestroyed() const { return being_destroyed_; }
bool IsLayoutBlockFlow() const final { return true; }
@@ -454,6 +453,7 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
// These functions are only public so we can call it from NGBlockNode while
// we're still working on LayoutNG.
void AddVisualOverflowFromFloats();
+ void AddVisualOverflowFromFloats(const NGPhysicalContainerFragment& fragment);
void AddLayoutOverflowFromFloats();
virtual NGInlineNodeData* TakeNGInlineNodeData() { return nullptr; }
@@ -464,9 +464,6 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
virtual void WillCollectInlines() {}
virtual void SetPaintFragment(const NGBlockBreakToken*,
scoped_refptr<const NGPhysicalFragment>);
- virtual const NGPhysicalBoxFragment* CurrentFragment() const {
- return nullptr;
- }
const NGFragmentItems* FragmentItems() const;
#if DCHECK_IS_ON()
@@ -530,7 +527,6 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
const PhysicalOffset& additional_offset,
NGOutlineType) const override;
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override;
void InvalidateDisplayItemClients(PaintInvalidationReason) const override;
Node* NodeForHitTest() const final;
@@ -736,9 +732,8 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
MarginValues MarginValuesForChild(LayoutBox& child) const;
// Allocated only when some of these fields have non-default values
- struct LayoutBlockFlowRareData {
- USING_FAST_MALLOC(LayoutBlockFlowRareData);
-
+ struct LayoutBlockFlowRareData final
+ : public GarbageCollected<LayoutBlockFlowRareData> {
public:
explicit LayoutBlockFlowRareData(const LayoutBlockFlow* block);
~LayoutBlockFlowRareData();
@@ -758,6 +753,8 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
return (-block->MarginAfter()).ClampNegativeToZero();
}
+ void Trace(Visitor*) {}
+
MarginValues margins_;
LayoutUnit pagination_strut_propagated_from_child_;
@@ -775,8 +772,6 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
unsigned break_after_ : 4;
int line_break_to_avoid_widow_;
bool did_break_at_line_to_avoid_widow_ : 1;
- bool discard_margin_before_ : 1;
- bool discard_margin_after_ : 1;
DISALLOW_COPY_AND_ASSIGN(LayoutBlockFlowRareData);
};
@@ -823,18 +818,6 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
void SetMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg);
void SetMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg);
- void SetMustDiscardMarginBefore(bool = true);
- void SetMustDiscardMarginAfter(bool = true);
-
- bool MustDiscardMarginBefore() const;
- bool MustDiscardMarginAfter() const;
-
- bool MustDiscardMarginBeforeForChild(const LayoutBox&) const;
- bool MustDiscardMarginAfterForChild(const LayoutBox&) const;
-
- bool MustSeparateMarginBeforeForChild(const LayoutBox&) const;
- bool MustSeparateMarginAfterForChild(const LayoutBox&) const;
-
void InitMaxMarginValues() {
if (rare_data_) {
rare_data_->margins_ = MarginValues(
@@ -842,9 +825,6 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
LayoutBlockFlowRareData::NegativeMarginBeforeDefault(this),
LayoutBlockFlowRareData::PositiveMarginAfterDefault(this),
LayoutBlockFlowRareData::NegativeMarginAfterDefault(this));
-
- rare_data_->discard_margin_before_ = false;
- rare_data_->discard_margin_after_ = false;
}
}
@@ -866,24 +846,18 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
LayoutUnit CollapseMargins(LayoutBox& child,
BlockChildrenLayoutInfo&,
- bool child_is_self_collapsing,
- bool child_discard_margin_before,
- bool child_discard_margin_after);
+ bool child_is_self_collapsing);
LayoutUnit ClearFloatsIfNeeded(LayoutBox& child,
MarginInfo&,
LayoutUnit old_top_pos_margin,
LayoutUnit old_top_neg_margin,
LayoutUnit y_pos,
- bool child_is_self_collapsing,
- bool child_discard_margin);
+ bool child_is_self_collapsing);
LayoutUnit EstimateLogicalTopPosition(
LayoutBox& child,
const BlockChildrenLayoutInfo&,
LayoutUnit& estimate_without_pagination);
- void MarginBeforeEstimateForChild(LayoutBox&,
- LayoutUnit&,
- LayoutUnit&,
- bool&) const;
+ void MarginBeforeEstimateForChild(LayoutBox&, LayoutUnit&, LayoutUnit&) const;
void HandleAfterSideOfBlock(LayoutBox* last_child,
LayoutUnit top,
LayoutUnit bottom,
@@ -937,7 +911,7 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
bool CheckIfIsSelfCollapsingBlock() const;
protected:
- std::unique_ptr<LayoutBlockFlowRareData> rare_data_;
+ Persistent<LayoutBlockFlowRareData> rare_data_;
std::unique_ptr<FloatingObjects> floating_objects_;
friend class MarginInfo;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc b/chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
index ca02eebdb92..96f21e1d24c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/core/layout/line/word_measurement.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h"
#include "third_party/blink/renderer/core/layout/vertical_position_cache.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
@@ -956,7 +957,7 @@ RootInlineBox* LayoutBlockFlow::CreateLineBoxesFromBidiRuns(
// text selection in RTL boxes would not work as expected.
if (is_svg_root_inline_box) {
DCHECK(IsSVGText());
- ToSVGRootInlineBox(line_box)->ComputePerCharacterLayoutInformation();
+ To<SVGRootInlineBox>(line_box)->ComputePerCharacterLayoutInformation();
}
// Compute our overflow now.
@@ -1179,7 +1180,13 @@ void LayoutBlockFlow::LayoutRunsAndFloatsInRange(
resolver, bidi_runs, end_of_line, override,
layout_state.GetLineInfo().PreviousLineBrokeCleanly(),
is_new_uba_paragraph);
- DCHECK(resolver.GetPosition() == end_of_line);
+ // |resolver| to be at |end_of_line| is critical, because
+ // |SetLineBreakInfo| below copies |end_of_line.current_| to
+ // |RootInlineBox::line_break_obj_|. When the object is destroyed,
+ // |RootInlineBox::ChildRemoved()| clears |line_break_obj_| to avoid
+ // use-after-free, but we cannot find the correct |RootInlineBox| if
+ // |end_of_line| is actually not in this |RootInlineBox|.
+ CHECK(resolver.GetPosition() == end_of_line);
BidiRun* trailing_space_run = resolver.TrailingSpaceRun();
@@ -1690,7 +1697,7 @@ void LayoutBlockFlow::ComputeInlinePreferredLogicalWidths(
// did change or is going to change size. However, this is our only
// opportunity to make sure that it gets its min/max widths
// calculated.
- child->SetPreferredLogicalWidthsDirty();
+ child->SetIntrinsicLogicalWidthsDirty();
}
// Case (1) and (2). Inline replaced and inline flow elements.
@@ -1699,13 +1706,14 @@ void LayoutBlockFlow::ComputeInlinePreferredLogicalWidths(
child_min, child_max);
inline_min += child_min;
inline_max += child_max;
- child->ClearPreferredLogicalWidthsDirty();
+ child->ClearIntrinsicLogicalWidthsDirty();
} else {
AdjustMarginForInlineReplaced(child, child_min, child_max);
}
}
- if (!child->IsLayoutInline() && !child->IsText()) {
+ if (!child->IsLayoutInline() && !child->IsText() &&
+ !child->IsOutsideListMarker()) {
// Case (2). Inline replaced elements and floats.
// Go ahead and terminate the current line as far as
// minwidth is concerned.
@@ -1893,7 +1901,7 @@ void LayoutBlockFlow::ComputeInlinePreferredLogicalWidths(
}
// Ignore spaces after a list marker.
- if (child->IsListMarkerIncludingNG())
+ if (child->IsListMarkerIncludingNGOutside())
strip_front_spaces = true;
} else {
min_logical_width = std::max(min_logical_width, inline_min);
@@ -2394,17 +2402,21 @@ void LayoutBlockFlow::AddVisualOverflowFromInlineChildren() {
AddContentsVisualOverflow(child_rect);
}
}
- } else if (const NGFragmentItems* items = FragmentItems()) {
- for (NGInlineCursor cursor(*items); cursor; cursor.MoveToNextSibling()) {
- const NGFragmentItem* child = cursor.CurrentItem();
- DCHECK(child);
- if (child->HasSelfPaintingLayer())
- continue;
- PhysicalRect child_rect = child->InkOverflow();
- if (!child_rect.IsEmpty()) {
- child_rect.offset += child->Offset();
- AddContentsVisualOverflow(child_rect);
+ } else if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
+ if (const NGFragmentItems* items = fragment->Items()) {
+ for (NGInlineCursor cursor(*items); cursor; cursor.MoveToNextSibling()) {
+ const NGFragmentItem* child = cursor.CurrentItem();
+ DCHECK(child);
+ if (child->HasSelfPaintingLayer())
+ continue;
+ PhysicalRect child_rect = child->InkOverflow();
+ if (!child_rect.IsEmpty()) {
+ child_rect.offset += child->OffsetInContainerBlock();
+ AddContentsVisualOverflow(child_rect);
+ }
}
+ } else if (fragment->HasFloatingDescendantsForPaint()) {
+ AddVisualOverflowFromFloats(*fragment);
}
} else {
for (RootInlineBox* curr = FirstRootBox(); curr;
@@ -2744,18 +2756,36 @@ LayoutUnit LayoutBlockFlow::StartAlignedOffsetForLine(
void LayoutBlockFlow::SetShouldDoFullPaintInvalidationForFirstLine() {
DCHECK(ChildrenInline());
- if (RootInlineBox* first_root_box = FirstRootBox())
- first_root_box->SetShouldDoFullPaintInvalidationForFirstLine();
- else if (const NGPaintFragment* paint_fragment = PaintFragment())
+
+ if (const NGPaintFragment* paint_fragment = PaintFragment()) {
paint_fragment->SetShouldDoFullPaintInvalidationForFirstLine();
-}
+ return;
+ }
-bool LayoutBlockFlow::PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
- // LayoutBlockFlow is in charge of paint invalidation of the first line.
- if (FirstLineBox())
- return false;
+ if (const NGFragmentItems* fragment_items = FragmentItems()) {
+ NGInlineCursor first_line(*fragment_items);
+ if (first_line) {
+ DCHECK(!FirstRootBox());
+ first_line.MoveToFirstLine();
+ if (first_line && first_line.Current().UsesFirstLineStyle()) {
+ // Mark all descendants of the first line if first-line style.
+ for (NGInlineCursor descendants = first_line.CursorForDescendants();
+ descendants; descendants.MoveToNext()) {
+ LayoutObject* layout_object =
+ descendants.Current()->GetMutableLayoutObject();
+ DCHECK(layout_object);
+ layout_object->StyleRef().ClearCachedPseudoElementStyles();
+ layout_object->SetShouldDoFullPaintInvalidation();
+ }
+ StyleRef().ClearCachedPseudoElementStyles();
+ SetShouldDoFullPaintInvalidation();
+ }
+ }
+ return;
+ }
- return LayoutBlock::PaintedOutputOfObjectHasNoEffectRegardlessOfSize();
+ if (RootInlineBox* first_root_box = FirstRootBox())
+ first_root_box->SetShouldDoFullPaintInvalidationForFirstLine();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_block_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_block_test.cc
index 98e24416cfd..a08a3b30dc6 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block_test.cc
@@ -54,7 +54,8 @@ TEST_F(LayoutBlockTest, WidthAvailableToChildrenChanged) {
150 - list_box->VerticalScrollbarWidth());
DummyExceptionStateForTesting exception_state;
- list_element->style()->setCSSText(&GetDocument(), "width:150px;height:100px;",
+ list_element->style()->setCSSText(GetDocument().GetExecutionContext(),
+ "width:150px;height:100px;",
exception_state);
ASSERT_FALSE(exception_state.HadException());
UpdateAllLifecyclePhasesForTest();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box.cc b/chromium/third_party/blink/renderer/core/layout/layout_box.cc
index e9e3cfdf053..d10c1623fc7 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box.cc
@@ -30,9 +30,11 @@
#include <algorithm>
#include "cc/input/scroll_snap_data.h"
+#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h"
#include "third_party/blink/public/platform/web_rect.h"
-#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
+#include "third_party/blink/public/strings/grit/blink_strings.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -40,10 +42,15 @@
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
+#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
+#include "third_party/blink/renderer/core/html/forms/html_opt_group_element.h"
+#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
+#include "third_party/blink/renderer/core/html/html_div_element.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html/html_frame_element_base.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
+#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_box.h"
#include "third_party/blink/renderer/core/layout/box_layout_extra_input.h"
@@ -52,6 +59,7 @@
#include "third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
#include "third_party/blink/renderer/core/layout/layout_fieldset.h"
+#include "third_party/blink/renderer/core/layout/layout_file_upload_control.h"
#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
#include "third_party/blink/renderer/core/layout/layout_grid.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
@@ -91,6 +99,7 @@
#include "third_party/blink/renderer/platform/geometry/float_rounded_rect.h"
#include "third_party/blink/renderer/platform/geometry/length_functions.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/text/platform_locale.h"
namespace blink {
@@ -107,13 +116,117 @@ struct SameSizeAsLayoutBox : public LayoutBoxModelObject {
LayoutSize previous_size;
LayoutUnit intrinsic_content_logical_height;
LayoutRectOutsets margin_box_outsets;
- LayoutUnit preferred_logical_width[2];
- void* pointers[5];
+ MinMaxSizes intrinsic_logical_widths;
+ LayoutUnit intrinsic_logical_widths_percentage_resolution_block_size;
+ void* pointers[4];
+ Persistent<void*> rare_data;
+ Vector<scoped_refptr<const NGLayoutResult>, 1> layout_results;
};
static_assert(sizeof(LayoutBox) == sizeof(SameSizeAsLayoutBox),
"LayoutBox should stay small");
+namespace {
+
+LayoutUnit FileUploadControlIntrinsicInlineSize(const HTMLInputElement& input,
+ const LayoutBox& box) {
+ // Figure out how big the filename space needs to be for a given number of
+ // characters (using "0" as the nominal character).
+ constexpr int kDefaultWidthNumChars = 34;
+ constexpr UChar kCharacter = '0';
+ const String character_as_string = String(&kCharacter, 1);
+ const Font& font = box.StyleRef().GetFont();
+ const float min_default_label_width =
+ kDefaultWidthNumChars *
+ font.Width(ConstructTextRun(font, character_as_string, box.StyleRef(),
+ TextRun::kAllowTrailingExpansion));
+
+ const String label =
+ input.GetLocale().QueryString(IDS_FORM_FILE_NO_FILE_LABEL);
+ float default_label_width = font.Width(ConstructTextRun(
+ font, label, box.StyleRef(), TextRun::kAllowTrailingExpansion));
+ if (HTMLInputElement* button = input.UploadButton()) {
+ if (LayoutObject* button_layout_object = button->GetLayoutObject()) {
+ default_label_width +=
+ button_layout_object->PreferredLogicalWidths().max_size +
+ LayoutFileUploadControl::kAfterButtonSpacing;
+ }
+ }
+ return LayoutUnit(
+ ceilf(std::max(min_default_label_width, default_label_width)));
+}
+
+LayoutUnit ListBoxDefaultItemHeight(const LayoutBox& box) {
+ constexpr int kDefaultPaddingBottom = 1;
+
+ const SimpleFontData* font_data = box.StyleRef().GetFont().PrimaryFont();
+ if (!font_data)
+ return LayoutUnit();
+ return LayoutUnit(font_data->GetFontMetrics().Height() +
+ kDefaultPaddingBottom);
+}
+
+// TODO(crbug.com/1040826): This function is written in LayoutObject API
+// so that this works in both of the legacy layout and LayoutNG. We
+// should have LayoutNG-specific code.
+LayoutUnit ListBoxItemHeight(const HTMLSelectElement& select,
+ const LayoutBox& box) {
+ const auto& items = select.GetListItems();
+ if (items.IsEmpty() || box.ShouldApplySizeContainment())
+ return ListBoxDefaultItemHeight(box);
+
+ LayoutUnit max_height;
+ for (Element* element : items) {
+ if (auto* optgroup = DynamicTo<HTMLOptGroupElement>(element))
+ element = &optgroup->OptGroupLabelElement();
+ LayoutUnit item_height;
+ if (auto* layout_box = element->GetLayoutBox())
+ item_height = layout_box->Size().Height();
+ else
+ item_height = ListBoxDefaultItemHeight(box);
+ max_height = std::max(max_height, item_height);
+ }
+ return max_height;
+}
+
+LayoutUnit MenuListIntrinsicInlineSize(const HTMLSelectElement& select,
+ const LayoutBox& box) {
+ const ComputedStyle& style = box.StyleRef();
+ float max_option_width = 0;
+ if (!box.ShouldApplySizeContainment()) {
+ for (auto* const option : select.GetOptionList()) {
+ String text = option->TextIndentedToRespectGroupLabel();
+ const ComputedStyle* item_style =
+ option->GetComputedStyle() ? option->GetComputedStyle() : &style;
+ item_style->ApplyTextTransform(&text);
+ // We apply SELECT's style, not OPTION's style because max_option_width is
+ // used to determine intrinsic width of the menulist box.
+ TextRun text_run = ConstructTextRun(style.GetFont(), text, style);
+ max_option_width =
+ std::max(max_option_width, style.GetFont().Width(text_run));
+ }
+ }
+
+ LayoutTheme& theme = LayoutTheme::GetTheme();
+ int paddings = theme.PopupInternalPaddingStart(style) +
+ theme.PopupInternalPaddingEnd(box.GetFrame(), style);
+ return std::max(static_cast<int>(ceilf(max_option_width)),
+ LayoutTheme::GetTheme().MinimumMenuListSize(style)) +
+ LayoutUnit(paddings);
+}
+
+LayoutUnit MenuListIntrinsicBlockSize(const HTMLSelectElement& select,
+ const LayoutBox& box) {
+ if (!box.StyleRef().HasEffectiveAppearance())
+ return kIndefiniteSize;
+ const SimpleFontData* font_data = box.StyleRef().GetFont().PrimaryFont();
+ DCHECK(font_data);
+ return (font_data ? font_data->GetFontMetrics().Height() : 0) +
+ select.InnerElement().GetLayoutBox()->BorderAndPaddingLogicalHeight();
+}
+
+} // anonymous namespace
+
BoxLayoutExtraInput::BoxLayoutExtraInput(LayoutBox& box) : box(box) {
box.SetBoxLayoutExtraInput(this);
}
@@ -135,11 +248,15 @@ LayoutBoxRareData::LayoutBoxRareData()
snap_container_(nullptr),
snap_areas_(nullptr) {}
+void LayoutBoxRareData::Trace(Visitor* visitor) {
+ visitor->Trace(layout_child_);
+}
+
LayoutBox::LayoutBox(ContainerNode* node)
: LayoutBoxModelObject(node),
intrinsic_content_logical_height_(-1),
- min_preferred_logical_width_(-1),
- max_preferred_logical_width_(-1),
+ intrinsic_logical_widths_percentage_resolution_block_size_(
+ LayoutUnit::Min()),
inline_box_wrapper_(nullptr) {
SetIsBox();
if (blink::IsA<HTMLLegendElement>(node))
@@ -181,6 +298,8 @@ void LayoutBox::WillBeDestroyed() {
if (!DocumentBeingDestroyed()) {
if (NGPaintFragment* first_inline_fragment = FirstInlineFragment())
first_inline_fragment->LayoutObjectWillBeDestroyed();
+ for (auto result : layout_results_)
+ result->PhysicalFragment().LayoutObjectWillBeDestroyed();
}
SetSnapContainer(nullptr);
@@ -242,8 +361,7 @@ void LayoutBox::StyleWillChange(StyleDifference diff,
// The background of the root element or the body element could propagate up
// to the canvas. Just dirty the entire canvas when our style changes
// substantially.
- if ((diff.NeedsFullPaintInvalidation() || diff.NeedsLayout()) &&
- GetNode() &&
+ if ((diff.NeedsPaintInvalidation() || diff.NeedsLayout()) && GetNode() &&
(IsDocumentElement() || IsA<HTMLBodyElement>(*GetNode()))) {
View()->SetShouldDoFullPaintInvalidation();
}
@@ -258,7 +376,7 @@ void LayoutBox::StyleWillChange(StyleDifference diff,
// We're about to go out of flow. Before that takes place, we need to
// mark the current containing block chain for preferred widths
// recalculation.
- SetNeedsLayoutAndPrefWidthsRecalc(
+ SetNeedsLayoutAndIntrinsicWidthsRecalc(
layout_invalidation_reason::kStyleChange);
} else {
MarkContainerChainForLayout();
@@ -468,7 +586,6 @@ void LayoutBox::UpdateScrollSnapMappingAfterStyleChange(
const ComputedStyle& old_style) {
DCHECK(Style());
SnapCoordinator& snap_coordinator = GetDocument().GetSnapCoordinator();
-
// scroll-snap-type and scroll-padding invalidate the snap container.
if (old_style.GetScrollSnapType() != StyleRef().GetScrollSnapType() ||
old_style.ScrollPaddingBottom() != StyleRef().ScrollPaddingBottom() ||
@@ -487,6 +604,10 @@ void LayoutBox::UpdateScrollSnapMappingAfterStyleChange(
old_style.ScrollMarginTop() != StyleRef().ScrollMarginTop() ||
old_style.ScrollMarginRight() != StyleRef().ScrollMarginRight())
snap_coordinator.SnapAreaDidChange(*this, StyleRef().GetScrollSnapAlign());
+
+ // Transform invalidates the snap area.
+ if (old_style.Transform() != StyleRef().Transform())
+ snap_coordinator.SnapAreaDidChange(*this, StyleRef().GetScrollSnapAlign());
}
void LayoutBox::AddScrollSnapMapping() {
@@ -647,9 +768,9 @@ int LayoutBox::PixelSnappedScrollHeight() const {
PhysicalRect LayoutBox::ScrollRectToVisibleRecursive(
const PhysicalRect& absolute_rect,
- const WebScrollIntoViewParams& params) {
- DCHECK(params.GetScrollType() == kProgrammaticScroll ||
- params.GetScrollType() == kUserScroll);
+ mojom::blink::ScrollIntoViewParamsPtr params) {
+ DCHECK(params->type == mojom::blink::ScrollType::kProgrammatic ||
+ params->type == mojom::blink::ScrollType::kUser);
if (!GetFrameView())
return absolute_rect;
@@ -659,12 +780,9 @@ PhysicalRect LayoutBox::ScrollRectToVisibleRecursive(
// if the stop_at_main_frame_layout_viewport option is set. We do this so
// that we can allow a smooth "scroll and zoom" animation to do the final
// scroll in cases like scrolling a focused editable box into view.
- if (params.stop_at_main_frame_layout_viewport && IsGlobalRootScroller())
+ if (params->stop_at_main_frame_layout_viewport && IsGlobalRootScroller())
return absolute_rect;
- // Presumably the same issue as in setScrollTop. See crbug.com/343132.
- DisableCompositingQueryAsserts disabler;
-
PhysicalRect absolute_rect_to_scroll = absolute_rect;
if (absolute_rect_to_scroll.Width() <= 0)
absolute_rect_to_scroll.SetWidth(LayoutUnit(1));
@@ -677,11 +795,11 @@ PhysicalRect LayoutBox::ScrollRectToVisibleRecursive(
parent_box = ContainingBlock();
PhysicalRect absolute_rect_for_parent;
- if (!IsLayoutView() && HasOverflowClip()) {
+ if (!IsA<LayoutView>(this) && HasOverflowClip()) {
absolute_rect_for_parent =
GetScrollableArea()->ScrollIntoView(absolute_rect_to_scroll, params);
} else if (!parent_box && CanBeProgramaticallyScrolled()) {
- ScrollableArea* area_to_scroll = params.make_visible_in_visual_viewport
+ ScrollableArea* area_to_scroll = params->make_visible_in_visual_viewport
? GetFrameView()->GetScrollableArea()
: GetFrameView()->LayoutViewport();
absolute_rect_for_parent =
@@ -706,7 +824,7 @@ PhysicalRect LayoutBox::ScrollRectToVisibleRecursive(
// have any effect, so we avoid using the RootFrameViewport and explicitly
// scroll the visual viewport if we can. If not, we're done.
if (StyleRef().GetPosition() == EPosition::kFixed && Container() == View() &&
- params.make_visible_in_visual_viewport) {
+ params->make_visible_in_visual_viewport) {
if (GetFrame()->IsMainFrame()) {
// TODO(donnd): We should continue the recursion if we're in a subframe.
return GetFrame()->GetPage()->GetVisualViewport().ScrollIntoView(
@@ -718,11 +836,11 @@ PhysicalRect LayoutBox::ScrollRectToVisibleRecursive(
if (parent_box) {
return parent_box->ScrollRectToVisibleRecursive(absolute_rect_for_parent,
- params);
+ std::move(params));
} else if (GetFrame()->IsLocalRoot() && !GetFrame()->IsMainFrame()) {
if (AllowedToPropagateRecursiveScrollToParentFrame(params)) {
GetFrameView()->ScrollRectToVisibleInRemoteParent(
- absolute_rect_for_parent, params);
+ absolute_rect_for_parent, std::move(params));
}
}
@@ -767,67 +885,74 @@ void LayoutBox::UpdateAfterLayout() {
// e.g. an OOF-positioned object is laid out by an NG containing block, then
// Legacy, then NG again, NG won't use a stale layout result.
if (IsOutOfFlowPositioned() && !IsLayoutNGObject())
- cached_layout_result_.reset();
+ ClearLayoutResults();
}
bool LayoutBox::HasOverrideIntrinsicContentWidth() const {
- const auto& style = StyleRef();
- const IntrinsicLength& intrinsic_length = style.IntrinsicWidth();
- if (intrinsic_length.IsLegacy())
+ if (!ShouldApplySizeContainment())
return false;
- if (intrinsic_length.IsAuto()) {
- // If we have an overflow that is not 'visible' in this direction, then we
- // override the intrinsic length to be 0. Otherwise, it's the same as
- // legacy, meaning we don't override it.
- // https://drafts.csswg.org/css-sizing-4/#valdef-intrinsic-block-size-auto
- return style.OverflowX() != EOverflow::kVisible;
- }
- return true;
+ const Length& intrinsic_length = StyleRef().ContainIntrinsicSize().Width();
+ return !intrinsic_length.IsAuto();
}
bool LayoutBox::HasOverrideIntrinsicContentHeight() const {
- const auto& style = StyleRef();
- const IntrinsicLength& intrinsic_length = style.IntrinsicHeight();
- if (intrinsic_length.IsLegacy())
+ if (!ShouldApplySizeContainment())
return false;
- if (intrinsic_length.IsAuto()) {
- // If we have an overflow that is not 'visible' in this direction, then we
- // override the intrinsic length to be 0. Otherwise, it's the same as
- // legacy, meaning we don't override it.
- // https://drafts.csswg.org/css-sizing-4/#valdef-intrinsic-block-size-auto
- return style.OverflowY() != EOverflow::kVisible;
- }
- return true;
+ const Length& intrinsic_length = StyleRef().ContainIntrinsicSize().Height();
+ return !intrinsic_length.IsAuto();
}
LayoutUnit LayoutBox::OverrideIntrinsicContentWidth() const {
DCHECK(HasOverrideIntrinsicContentWidth());
const auto& style = StyleRef();
- const IntrinsicLength& intrinsic_length = style.IntrinsicWidth();
- DCHECK(!intrinsic_length.IsLegacy());
- if (intrinsic_length.IsAuto()) {
- DCHECK(style.OverflowX() != EOverflow::kVisible);
- return LayoutUnit();
- }
- DCHECK(intrinsic_length.GetLength().IsFixed());
- DCHECK_GE(intrinsic_length.GetLength().Value(), 0.f);
- return LayoutUnit(intrinsic_length.GetLength().Value());
+ const Length& intrinsic_length = style.ContainIntrinsicSize().Width();
+ DCHECK(!intrinsic_length.IsAuto());
+ DCHECK(intrinsic_length.IsFixed());
+ DCHECK_GE(intrinsic_length.Value(), 0.f);
+ return LayoutUnit(intrinsic_length.Value());
}
LayoutUnit LayoutBox::OverrideIntrinsicContentHeight() const {
DCHECK(HasOverrideIntrinsicContentHeight());
const auto& style = StyleRef();
- const IntrinsicLength& intrinsic_length = style.IntrinsicHeight();
- DCHECK(!intrinsic_length.IsLegacy());
- if (intrinsic_length.IsAuto()) {
- DCHECK(style.OverflowY() != EOverflow::kVisible);
- return LayoutUnit();
+ const Length& intrinsic_length = style.ContainIntrinsicSize().Height();
+ DCHECK(!intrinsic_length.IsAuto());
+ DCHECK(intrinsic_length.IsFixed());
+ DCHECK_GE(intrinsic_length.Value(), 0.f);
+ return LayoutUnit(intrinsic_length.Value());
+}
+
+LayoutUnit LayoutBox::DefaultIntrinsicContentInlineSize() const {
+ // If the intrinsic-inline-size is specified, then we shouldn't ever need to
+ // get here.
+ DCHECK(!HasOverrideIntrinsicContentLogicalWidth());
+
+ auto* select = DynamicTo<HTMLSelectElement>(GetNode());
+ if (UNLIKELY(select && select->UsesMenuList())) {
+ return MenuListIntrinsicInlineSize(*select, *this);
+ }
+ auto* input = DynamicTo<HTMLInputElement>(GetNode());
+ if (UNLIKELY(input && input->type() == input_type_names::kFile))
+ return FileUploadControlIntrinsicInlineSize(*input, *this);
+ return kIndefiniteSize;
+}
+
+LayoutUnit LayoutBox::DefaultIntrinsicContentBlockSize() const {
+ // If the intrinsic-block-size is specified, then we shouldn't ever need to
+ // get here.
+ DCHECK(!HasOverrideIntrinsicContentLogicalHeight());
+
+ if (const auto* select = DynamicTo<HTMLSelectElement>(GetNode())) {
+ if (select->UsesMenuList()) {
+ return MenuListIntrinsicBlockSize(*select, *this);
+ } else {
+ return ListBoxItemHeight(*select, *this) * select->ListBoxSize() -
+ ScrollbarLogicalHeight();
+ }
}
- DCHECK(intrinsic_length.GetLength().IsFixed());
- DCHECK_GE(intrinsic_length.GetLength().Value(), 0.f);
- return LayoutUnit(intrinsic_length.GetLength().Value());
+ return kIndefiniteSize;
}
LayoutUnit LayoutBox::LogicalHeightWithVisibleOverflow() const {
@@ -844,7 +969,7 @@ LayoutUnit LayoutBox::ConstrainLogicalWidthByMinMax(
LayoutUnit available_width,
const LayoutBlock* cb) const {
const ComputedStyle& style_to_use = StyleRef();
- if (!style_to_use.LogicalMaxWidth().IsMaxSizeNone())
+ if (!style_to_use.LogicalMaxWidth().IsNone())
logical_width = std::min(
logical_width,
ComputeLogicalWidthUsing(kMaxSize, style_to_use.LogicalMaxWidth(),
@@ -860,8 +985,7 @@ LayoutUnit LayoutBox::ConstrainLogicalHeightByMinMax(
// Note that the values 'min-content', 'max-content' and 'fit-content' should
// behave as the initial value if specified in the block direction.
const Length& logical_max_height = StyleRef().LogicalMaxHeight();
- if (!logical_max_height.IsMaxSizeNone() &&
- !logical_max_height.IsMinContent() &&
+ if (!logical_max_height.IsNone() && !logical_max_height.IsMinContent() &&
!logical_max_height.IsMaxContent() &&
!logical_max_height.IsFitContent()) {
LayoutUnit max_h = ComputeLogicalHeightUsing(kMaxSize, logical_max_height,
@@ -885,7 +1009,7 @@ LayoutUnit LayoutBox::ConstrainContentBoxLogicalHeightByMinMax(
// advantage of already knowing the current resolved percentage height
// to avoid recursing up through our containing blocks again to determine it.
const ComputedStyle& style_to_use = StyleRef();
- if (!style_to_use.LogicalMaxHeight().IsMaxSizeNone()) {
+ if (!style_to_use.LogicalMaxHeight().IsNone()) {
if (style_to_use.LogicalMaxHeight().IsPercent() &&
style_to_use.LogicalHeight().IsPercent()) {
LayoutUnit available_logical_height(
@@ -1083,9 +1207,9 @@ void LayoutBox::Autoscroll(const PhysicalOffset& position_in_root_frame) {
ScrollRectToVisibleRecursive(
PhysicalRect(absolute_position,
PhysicalSize(LayoutUnit(1), LayoutUnit(1))),
- WebScrollIntoViewParams(ScrollAlignment::kAlignToEdgeIfNeeded,
- ScrollAlignment::kAlignToEdgeIfNeeded,
- kUserScroll));
+ ScrollAlignment::CreateScrollIntoViewParams(
+ ScrollAlignment::ToEdgeIfNeeded(), ScrollAlignment::ToEdgeIfNeeded(),
+ mojom::blink::ScrollType::kUser));
}
bool LayoutBox::CanAutoscroll() const {
@@ -1155,11 +1279,6 @@ LayoutBox* LayoutBox::FindAutoscrollable(LayoutObject* layout_object,
: nullptr;
}
-void LayoutBox::MayUpdateHoverWhenContentUnderMouseChanged(
- EventHandler& event_handler) {
- event_handler.MayUpdateHoverAfterScroll(AbsoluteBoundingBoxFloatRect());
-}
-
void LayoutBox::ScrollByRecursively(const ScrollOffset& delta) {
if (delta.IsZero() || !HasOverflowClip())
return;
@@ -1168,7 +1287,8 @@ void LayoutBox::ScrollByRecursively(const ScrollOffset& delta) {
DCHECK(scrollable_area);
ScrollOffset new_scroll_offset = scrollable_area->GetScrollOffset() + delta;
- scrollable_area->SetScrollOffset(new_scroll_offset, kProgrammaticScroll);
+ scrollable_area->SetScrollOffset(new_scroll_offset,
+ mojom::blink::ScrollType::kProgrammatic);
// If this layer can't do the scroll we ask the next layer up that can
// scroll to try.
@@ -1336,7 +1456,7 @@ bool LayoutBox::MapContentsRectToBoxSpace(
}
bool LayoutBox::ContainedContentsScroll(const LayoutObject& contents) const {
- if (IsLayoutView() &&
+ if (IsA<LayoutView>(this) &&
contents.StyleRef().GetPosition() == EPosition::kFixed) {
return false;
}
@@ -1366,40 +1486,23 @@ bool LayoutBox::ApplyBoxClips(
return does_intersect;
}
-void LayoutBox::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
- min_logical_width =
- MinPreferredLogicalWidth() - BorderAndPaddingLogicalWidth();
- max_logical_width =
- MaxPreferredLogicalWidth() - BorderAndPaddingLogicalWidth();
+MinMaxSizes LayoutBox::PreferredLogicalWidths() const {
+ NOTREACHED();
+ return MinMaxSizes();
}
-LayoutUnit LayoutBox::MinPreferredLogicalWidth() const {
- if (PreferredLogicalWidthsDirty()) {
-#if DCHECK_IS_ON()
- SetLayoutNeededForbiddenScope layout_forbidden_scope(
- const_cast<LayoutBox&>(*this));
-#endif
- const_cast<LayoutBox*>(this)->ComputePreferredLogicalWidths();
- DCHECK(!PreferredLogicalWidthsDirty());
- }
-
- return min_preferred_logical_width_;
-}
+void LayoutBox::UpdateCachedIntrinsicLogicalWidthsIfNeeded() {
+ if (!IntrinsicLogicalWidthsDirty())
+ return;
-DISABLE_CFI_PERF
-LayoutUnit LayoutBox::MaxPreferredLogicalWidth() const {
- if (PreferredLogicalWidthsDirty()) {
#if DCHECK_IS_ON()
- SetLayoutNeededForbiddenScope layout_forbidden_scope(
- const_cast<LayoutBox&>(*this));
+ SetLayoutNeededForbiddenScope layout_forbidden_scope(*this);
#endif
- const_cast<LayoutBox*>(this)->ComputePreferredLogicalWidths();
- DCHECK(!PreferredLogicalWidthsDirty());
- }
- return max_preferred_logical_width_;
+ intrinsic_logical_widths_ = ComputeIntrinsicLogicalWidths();
+ intrinsic_logical_widths_percentage_resolution_block_size_ =
+ LayoutUnit::Min();
+ ClearIntrinsicLogicalWidthsDirty();
}
LayoutUnit LayoutBox::OverrideLogicalWidth() const {
@@ -1771,7 +1874,7 @@ bool LayoutBox::GetBackgroundPaintedExtent(PhysicalRect& painted_extent) const {
// LayoutView is special in the sense that it expands to the whole canvas,
// thus can't be handled by this function.
- DCHECK(!IsLayoutView());
+ DCHECK(!IsA<LayoutView>(this));
PhysicalRect background_rect(PhysicalBorderBoxRect());
@@ -1901,7 +2004,7 @@ bool LayoutBox::ComputeBackgroundIsKnownToBeObscured() const {
if (!StyleRef().HasBackground())
return false;
// Root background painting is special.
- if (IsLayoutView())
+ if (IsA<LayoutView>(this))
return false;
// FIXME: box-shadow is painted while background painting.
if (StyleRef().BoxShadow())
@@ -2020,10 +2123,6 @@ void LayoutBox::SizeChanged() {
// object for paint invalidation.
if (!NeedsLayout())
SetShouldCheckForPaintInvalidation();
-
- if (auto* element = DynamicTo<Element>(GetNode())) {
- element->SetNeedsResizeObserverUpdate();
- }
}
bool LayoutBox::IntersectsVisibleViewport() const {
@@ -2089,12 +2188,33 @@ PhysicalRect LayoutBox::OverflowClipRect(
if (HasOverflowClip())
ExcludeScrollbars(clip_rect, overlay_scrollbar_clip_behavior);
- if (HasControlClip())
- clip_rect.Intersect(ControlClipRect(location));
+ auto* input = DynamicTo<HTMLInputElement>(GetNode());
+ if (UNLIKELY(input)) {
+ // As for LayoutButton, ControlClip is to for not BUTTONs but INPUT
+ // buttons for IE/Firefox compatibility.
+ if (IsTextField() || IsLayoutButton()) {
+ DCHECK(HasControlClip());
+ PhysicalRect control_clip = PhysicalPaddingBoxRect();
+ control_clip.Move(location);
+ clip_rect.Intersect(control_clip);
+ }
+ } else if (UNLIKELY(IsMenuList(this))) {
+ DCHECK(HasControlClip());
+ PhysicalRect control_clip = PhysicalContentBoxRect();
+ control_clip.Move(location);
+ clip_rect.Intersect(control_clip);
+ } else {
+ DCHECK(!HasControlClip());
+ }
return clip_rect;
}
+bool LayoutBox::HasControlClip() const {
+ return UNLIKELY(IsTextField() || IsFileUploadControl() || IsMenuList(this) ||
+ (IsLayoutButton() && IsA<HTMLInputElement>(GetNode())));
+}
+
void LayoutBox::ExcludeScrollbars(
PhysicalRect& rect,
OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
@@ -2343,6 +2463,17 @@ void LayoutBox::DirtyLineBoxes(bool full_layout) {
}
}
+bool LayoutBox::HasInlineFragments() const {
+ if (!IsInLayoutNGInlineFormattingContext())
+ return inline_box_wrapper_;
+ if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return first_paint_fragment_;
+ // TODO(yosin): We should use |first_fragment_item_index_|.
+ NGInlineCursor cursor;
+ cursor.MoveTo(*this);
+ return cursor;
+}
+
void LayoutBox::SetFirstInlineFragment(NGPaintFragment* fragment) {
CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
// TODO(yosin): Once we remove |NGPaintFragment|, we should get rid of
@@ -2361,7 +2492,9 @@ void LayoutBox::SetFirstInlineFragmentItemIndex(wtf_size_t index) {
CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK_NE(index, 0u);
- first_fragment_item_index_ = index;
+ // TDOO(yosin): Once we update all |LayoutObject::FirstInlineFragment()|,
+ // we should enable below.
+ // first_fragment_item_index_ = index;
}
void LayoutBox::InLayoutNGInlineFormattingContextWillChange(bool new_value) {
@@ -2372,33 +2505,76 @@ void LayoutBox::InLayoutNGInlineFormattingContextWillChange(bool new_value) {
DCHECK(new_value ? !first_paint_fragment_ : !inline_box_wrapper_);
}
-void LayoutBox::SetCachedLayoutResult(const NGLayoutResult& layout_result,
- const NGBreakToken* break_token) {
- DCHECK_EQ(layout_result.Status(), NGLayoutResult::kSuccess);
+void LayoutBox::SetCachedLayoutResult(
+ scoped_refptr<const NGLayoutResult> result) {
+ DCHECK(!result->PhysicalFragment().BreakToken());
+ DCHECK(!result->IsSingleUse());
- if (break_token)
- return;
- if (layout_result.PhysicalFragment().BreakToken())
- return;
+ if (result->GetConstraintSpaceForCaching().CacheSlot() ==
+ NGCacheSlot::kMeasure) {
+ if (measure_result_)
+ InvalidateItems(*measure_result_);
+ measure_result_ = result;
+ // When setting the "measure" result we also set the "layout" result.
+ }
- ClearCachedLayoutResult();
- cached_layout_result_ = &layout_result;
+ AddLayoutResult(std::move(result), 0);
}
-void LayoutBox::ClearCachedLayoutResult() {
- if (!cached_layout_result_)
- return;
+void LayoutBox::AddLayoutResult(scoped_refptr<const NGLayoutResult> result,
+ wtf_size_t index) {
+ DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
+ if (index != WTF::kNotFound)
+ ShrinkLayoutResults(index);
+ layout_results_.push_back(std::move(result));
+}
+void LayoutBox::ClearLayoutResults() {
+ if (measure_result_)
+ InvalidateItems(*measure_result_);
+ measure_result_ = nullptr;
+
+ ShrinkLayoutResults(0);
+}
+
+void LayoutBox::ShrinkLayoutResults(wtf_size_t results_to_keep) {
+ DCHECK_GE(layout_results_.size(), results_to_keep);
// Invalidate if inline |DisplayItemClient|s will be destroyed.
- if (const auto* box_fragment = DynamicTo<NGPhysicalBoxFragment>(
- &cached_layout_result_->PhysicalFragment())) {
- if (box_fragment->HasItems()) {
- DCHECK_EQ(this, box_fragment->GetLayoutObject());
- ObjectPaintInvalidator(*this).SlowSetPaintingLayerNeedsRepaint();
- }
- }
+ for (wtf_size_t i = results_to_keep; i < layout_results_.size(); i++)
+ InvalidateItems(*layout_results_[i]);
+ layout_results_.Shrink(results_to_keep);
+}
+
+void LayoutBox::InvalidateItems(const NGLayoutResult& result) {
+ // Invalidate if inline |DisplayItemClient|s will be destroyed.
+ const auto& box_fragment =
+ To<NGPhysicalBoxFragment>(result.PhysicalFragment());
+ if (!box_fragment.HasItems())
+ return;
+
+ DCHECK_EQ(this, box_fragment.GetLayoutObject());
+ ObjectPaintInvalidator(*this).SlowSetPaintingLayerNeedsRepaint();
+}
+
+const NGLayoutResult* LayoutBox::GetCachedLayoutResult() const {
+ if (layout_results_.IsEmpty())
+ return nullptr;
+ // Only return re-usable results.
+ const NGLayoutResult* result = layout_results_[0].get();
+ if (result->IsSingleUse())
+ return nullptr;
+ DCHECK_EQ(layout_results_.size(), 1u);
+ return result;
+}
+
+const NGLayoutResult* LayoutBox::GetCachedMeasureResult() const {
+ if (!measure_result_)
+ return nullptr;
+
+ if (measure_result_->IsSingleUse())
+ return nullptr;
- cached_layout_result_ = nullptr;
+ return measure_result_.get();
}
scoped_refptr<const NGLayoutResult> LayoutBox::CachedLayoutResult(
@@ -2409,10 +2585,12 @@ scoped_refptr<const NGLayoutResult> LayoutBox::CachedLayoutResult(
NGLayoutCacheStatus* out_cache_status) {
*out_cache_status = NGLayoutCacheStatus::kNeedsLayout;
- if (!RuntimeEnabledFeatures::LayoutNGFragmentCachingEnabled())
- return nullptr;
+ const NGLayoutResult* cached_layout_result =
+ new_space.CacheSlot() == NGCacheSlot::kLayout &&
+ !layout_results_.IsEmpty()
+ ? GetCachedLayoutResult()
+ : GetCachedMeasureResult();
- const NGLayoutResult* cached_layout_result = GetCachedLayoutResult();
if (!cached_layout_result)
return nullptr;
@@ -2509,8 +2687,7 @@ scoped_refptr<const NGLayoutResult> LayoutBox::CachedLayoutResult(
bool is_exclusion_space_equal =
new_space.ExclusionSpace() == old_space.ExclusionSpace();
- bool is_new_formatting_context =
- physical_fragment.IsBlockFormattingContextRoot();
+ bool is_new_formatting_context = physical_fragment.IsFormattingContextRoot();
// If a node *doesn't* establish a new formatting context it may be affected
// by floats, or clearance.
@@ -2545,7 +2722,7 @@ scoped_refptr<const NGLayoutResult> LayoutBox::CachedLayoutResult(
// "simplified" layout then abort now.
*out_cache_status = cache_status;
if (*out_cache_status == NGLayoutCacheStatus::kNeedsSimplifiedLayout)
- return nullptr;
+ return cached_layout_result;
physical_fragment.CheckType();
@@ -2587,11 +2764,29 @@ scoped_refptr<const NGLayoutResult> LayoutBox::CachedLayoutResult(
bfc_block_offset, block_offset_delta));
if (needs_cached_result_update)
- SetCachedLayoutResult(*new_result, break_token);
+ SetCachedLayoutResult(new_result);
return new_result;
}
+const NGPhysicalBoxFragment* LayoutBox::GetPhysicalFragment(
+ wtf_size_t index) const {
+ return &To<NGPhysicalBoxFragment>(layout_results_[index]->PhysicalFragment());
+}
+
+const FragmentData* LayoutBox::FragmentDataFromPhysicalFragment(
+ const NGPhysicalBoxFragment& physical_fragment) const {
+ const FragmentData* fragment_data = &FirstFragment();
+ for (const auto& result : layout_results_) {
+ if (&result->PhysicalFragment() == &physical_fragment)
+ return fragment_data;
+ DCHECK(fragment_data->NextFragment());
+ fragment_data = fragment_data->NextFragment();
+ }
+ NOTREACHED();
+ return fragment_data;
+}
+
void LayoutBox::PositionLineBox(InlineBox* box) {
if (IsOutOfFlowPositioned()) {
// Cache the x position only if we were an INLINE type originally.
@@ -2772,27 +2967,6 @@ bool LayoutBox::NeedsForcedBreakBefore(
return IsForcedFragmentainerBreakValue(break_value);
}
-bool LayoutBox::PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
- if (HasNonCompositedScrollbars() || IsSelected() ||
- HasBoxDecorationBackground() || StyleRef().HasBoxDecorations() ||
- StyleRef().HasVisualOverflowingEffect())
- return false;
-
- // Both mask and clip-path generates drawing display items that depends on
- // the size of the box.
- if (HasMask() || HasClipPath())
- return false;
-
- // If the box paints into its own backing, we can assume that it's painting
- // may have some effect. For example, honoring the border-radius clip on
- // a composited child paints into a mask for an otherwise non-painting
- // element, because children of that element will require the mask.
- if (HasLayer() && Layer()->GetCompositingState() == kPaintsIntoOwnBacking)
- return false;
-
- return true;
-}
-
PhysicalRect LayoutBox::LocalVisualRectIgnoringVisibility() const {
return PhysicalSelfVisualOverflowRect();
}
@@ -2900,10 +3074,10 @@ bool LayoutBox::MapToVisualRectInAncestorSpaceInternal(
return true;
}
- if (container->IsLayoutView()) {
+ if (auto* layout_view = DynamicTo<LayoutView>(container)) {
bool use_fixed_position_adjustment =
position == EPosition::kFixed && container == ancestor;
- return ToLayoutView(container)->MapToVisualRectInAncestorSpaceInternal(
+ return layout_view->MapToVisualRectInAncestorSpaceInternal(
ancestor, transform_state, use_fixed_position_adjustment ? kIsFixed : 0,
visual_rect_flags);
} else {
@@ -2926,7 +3100,7 @@ void LayoutBox::InflateVisualRectForFilter(
static bool ShouldRecalculateMinMaxWidthsAffectedByAncestor(
const LayoutBox* box) {
- if (box->PreferredLogicalWidthsDirty()) {
+ if (box->IntrinsicLogicalWidthsDirty()) {
// If the preferred widths are already dirty at this point (during layout),
// it actually means that we never need to calculate them, since that should
// have been carried out by an ancestor that's sized based on preferred
@@ -2937,7 +3111,7 @@ static bool ShouldRecalculateMinMaxWidthsAffectedByAncestor(
}
if (const LayoutBox* containing_block = box->ContainingBlock()) {
if (containing_block->NeedsPreferredWidthsRecalculation() &&
- !containing_block->PreferredLogicalWidthsDirty()) {
+ !containing_block->IntrinsicLogicalWidthsDirty()) {
// If our containing block also has min/max widths that are affected by
// the ancestry, we have already dealt with this object as well. Avoid
// unnecessary work and O(n^2) time complexity.
@@ -2956,14 +3130,14 @@ void LayoutBox::UpdateLogicalWidth() {
// bottom-up, but that's not always the case), so since the containing
// block size may have changed, we need to recalculate the min/max widths
// of this object, and every child that has the same issue, recursively.
- SetPreferredLogicalWidthsDirty(kMarkOnlyThis);
+ SetIntrinsicLogicalWidthsDirty(kMarkOnlyThis);
// Since all this takes place during actual layout, instead of being part
// of min/max the width calculation machinery, we need to enter said
- // machinery here, to make sure that what was dirtied is actualy
+ // machinery here, to make sure that what was dirtied is actually
// recalculated. Leaving things dirty would mean that any subsequent
// dirtying of descendants would fail.
- ComputePreferredLogicalWidths();
+ UpdateCachedIntrinsicLogicalWidthsIfNeeded();
}
}
@@ -3058,7 +3232,7 @@ void LayoutBox::ComputeLogicalWidth(
if (treat_as_replaced) {
computed_values.extent_ = std::max(
ComputeReplacedLogicalWidth() + BorderAndPaddingLogicalWidth(),
- MinPreferredLogicalWidth());
+ PreferredLogicalWidths().min_size);
}
return;
}
@@ -3163,33 +3337,27 @@ LayoutUnit LayoutBox::FillAvailableMeasure(LayoutUnit available_logical_width,
DISABLE_CFI_PERF
LayoutUnit LayoutBox::ComputeIntrinsicLogicalWidthUsing(
const Length& logical_width_length,
- LayoutUnit available_logical_width,
- LayoutUnit border_and_padding) const {
+ LayoutUnit available_logical_width) const {
if (logical_width_length.IsFillAvailable()) {
if (!IsA<HTMLMarqueeElement>(GetNode())) {
UseCounter::Count(GetDocument(),
WebFeature::kCSSFillAvailableLogicalWidth);
}
- return std::max(border_and_padding,
+ return std::max(BorderAndPaddingLogicalWidth(),
FillAvailableMeasure(available_logical_width));
}
- LayoutUnit min_logical_width;
- LayoutUnit max_logical_width;
- ComputeIntrinsicLogicalWidths(min_logical_width, max_logical_width);
+ MinMaxSizes sizes = IntrinsicLogicalWidths();
if (logical_width_length.IsMinContent())
- return min_logical_width + border_and_padding;
+ return sizes.min_size;
if (logical_width_length.IsMaxContent())
- return max_logical_width + border_and_padding;
+ return sizes.max_size;
if (logical_width_length.IsFitContent()) {
- min_logical_width += border_and_padding;
- max_logical_width += border_and_padding;
- return std::max(min_logical_width,
- std::min(max_logical_width,
- FillAvailableMeasure(available_logical_width)));
+ return sizes.ClampSizeToMinAndMax(
+ FillAvailableMeasure(available_logical_width));
}
NOTREACHED();
@@ -3214,9 +3382,10 @@ LayoutUnit LayoutBox::ComputeLogicalWidthUsing(
ValueForLength(logical_width, available_logical_width));
}
- if (logical_width.IsIntrinsic())
- return ComputeIntrinsicLogicalWidthUsing(
- logical_width, available_logical_width, BorderAndPaddingLogicalWidth());
+ if (logical_width.IsIntrinsic()) {
+ return ComputeIntrinsicLogicalWidthUsing(logical_width,
+ available_logical_width);
+ }
LayoutUnit margin_start;
LayoutUnit margin_end;
@@ -3238,9 +3407,9 @@ LayoutUnit LayoutBox::ComputeLogicalWidthUsing(
// TODO(crbug.com/710026): Remove const_cast
LayoutUnit w = LogicalWidth();
const_cast<LayoutBox*>(this)->SetLogicalWidth(LayoutUnit());
+ MinMaxSizes preferred_logical_widths = PreferredLogicalWidths();
LayoutUnit result =
- std::max(MinPreferredLogicalWidth(),
- std::min(MaxPreferredLogicalWidth(), logical_width_result));
+ preferred_logical_widths.ClampSizeToMinAndMax(logical_width_result);
const_cast<LayoutBox*>(this)->SetLogicalWidth(w);
return result;
}
@@ -3513,10 +3682,16 @@ void LayoutBox::ComputeLogicalHeight(
if (HasOverrideIntrinsicContentLogicalHeight()) {
height = OverrideIntrinsicContentLogicalHeight() +
BorderAndPaddingLogicalHeight() + ScrollbarLogicalHeight();
- } else if (ShouldApplySizeContainment() && !IsLayoutGrid()) {
- height = BorderAndPaddingLogicalHeight() + ScrollbarLogicalHeight();
} else {
- height = LogicalHeight();
+ LayoutUnit default_height = DefaultIntrinsicContentBlockSize();
+ if (default_height != kIndefiniteSize) {
+ height = default_height + BorderAndPaddingLogicalHeight() +
+ ScrollbarLogicalHeight();
+ } else if (ShouldApplySizeContainment() && !IsLayoutGrid()) {
+ height = BorderAndPaddingLogicalHeight() + ScrollbarLogicalHeight();
+ } else {
+ height = LogicalHeight();
+ }
}
ComputeLogicalHeight(height, LogicalTop(), computed_values);
}
@@ -3564,22 +3739,13 @@ void LayoutBox::ComputeLogicalHeight(
return;
}
- // FIXME: Account for writing-mode in flexible boxes.
- // https://bugs.webkit.org/show_bug.cgi?id=46418
- bool in_horizontal_box =
- Parent()->IsDeprecatedFlexibleBox() &&
- Parent()->StyleRef().BoxOrient() == EBoxOrient::kHorizontal;
- bool stretching =
- Parent()->StyleRef().BoxAlign() == EBoxAlignment::kStretch;
- bool treat_as_replaced =
- ShouldComputeSizeAsReplaced() && (!in_horizontal_box || !stretching);
bool check_min_max_height = false;
// The parent box is flexing us, so it has increased or decreased our
// height. We have to grab our cached flexible height.
if (HasOverrideLogicalHeight()) {
h = Length::Fixed(OverrideLogicalHeight());
- } else if (treat_as_replaced) {
+ } else if (ShouldComputeSizeAsReplaced()) {
h = Length::Fixed(ComputeReplacedLogicalHeight() +
BorderAndPaddingLogicalHeight());
} else {
@@ -3587,16 +3753,6 @@ void LayoutBox::ComputeLogicalHeight(
check_min_max_height = true;
}
- // Block children of horizontal flexible boxes fill the height of the box.
- // FIXME: Account for writing-mode in flexible boxes.
- // https://bugs.webkit.org/show_bug.cgi?id=46418
- if (h.IsAuto() && in_horizontal_box &&
- ToLayoutDeprecatedFlexibleBox(Parent())->IsStretchingChildren()) {
- h = Length::Fixed(ParentBox()->ContentLogicalHeight() - MarginBefore() -
- MarginAfter());
- check_min_max_height = false;
- }
-
LayoutUnit height_result;
if (check_min_max_height) {
height_result = ComputeLogicalHeightUsing(
@@ -3793,7 +3949,7 @@ LayoutUnit LayoutBox::ContainingBlockLogicalHeightForPercentageResolution(
const LayoutBox* containing_block_child = this;
bool skipped_auto_height_containing_block = false;
LayoutUnit root_margin_border_padding_height;
- while (!cb->IsLayoutView() &&
+ while (!IsA<LayoutView>(cb) &&
(IsHorizontalWritingMode() == cb->IsHorizontalWritingMode() &&
SkipContainingBlockForPercentHeightCalculation(cb))) {
if ((cb->IsBody() || cb->IsDocumentElement()) &&
@@ -3931,7 +4087,7 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalWidthRespectingMinMaxWidth(
LayoutUnit max_logical_width =
(should_compute_preferred == kComputePreferred &&
StyleRef().LogicalMaxWidth().IsPercentOrCalc()) ||
- StyleRef().LogicalMaxWidth().IsMaxSizeNone()
+ StyleRef().LogicalMaxWidth().IsNone()
? logical_width
: ComputeReplacedLogicalWidthUsing(kMaxSize,
StyleRef().LogicalMaxWidth());
@@ -3955,8 +4111,7 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalWidthUsing(
// MinContent/MaxContent don't need the availableLogicalWidth argument.
LayoutUnit available_logical_width;
return ComputeIntrinsicLogicalWidthUsing(logical_width,
- available_logical_width,
- BorderAndPaddingLogicalWidth()) -
+ available_logical_width) -
BorderAndPaddingLogicalWidth();
}
case Length::kFitContent:
@@ -3978,8 +4133,7 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalWidthUsing(
// FIXME: Handle cases when containing block width is calculated or
// viewport percent. https://bugs.webkit.org/show_bug.cgi?id=91071
if (logical_width.IsIntrinsic())
- return ComputeIntrinsicLogicalWidthUsing(
- logical_width, cw, BorderAndPaddingLogicalWidth()) -
+ return ComputeIntrinsicLogicalWidthUsing(logical_width, cw) -
BorderAndPaddingLogicalWidth();
if (cw > 0 || (!cw && (container_logical_width.IsFixed() ||
container_logical_width.IsPercentOrCalc())))
@@ -3988,7 +4142,7 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalWidthUsing(
return LayoutUnit();
}
case Length::kAuto:
- case Length::kMaxSizeNone:
+ case Length::kNone:
return IntrinsicLogicalWidth();
case Length::kExtendToZoom:
case Length::kDeviceWidth:
@@ -4025,6 +4179,11 @@ bool LayoutBox::LogicalHeightComputesAsNone(SizeType size_type) const {
if (logical_height == initial_logical_height)
return true;
+ if (logical_height.IsPercentOrCalc() &&
+ HasOverrideContainingBlockContentLogicalHeight() &&
+ OverrideContainingBlockContentLogicalHeight() == kIndefiniteSize)
+ return true;
+
// CustomLayout items can resolve their percentages against an available or
// percentage size override.
if (IsCustomItem() && (HasOverrideContainingBlockContentLogicalHeight() ||
@@ -4114,7 +4273,7 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalHeightUsing(
// FIXME: This needs to be made writing-mode-aware. If the cell and
// image are perpendicular writing-modes, this isn't right.
// https://bugs.webkit.org/show_bug.cgi?id=46997
- while (cb && !cb->IsLayoutView() &&
+ while (!IsA<LayoutView>(cb) &&
(cb->StyleRef().LogicalHeight().IsAuto() ||
cb->StyleRef().LogicalHeight().IsPercentOrCalc())) {
if (cb->IsTableCell()) {
@@ -4173,10 +4332,10 @@ LayoutUnit LayoutBox::AvailableLogicalHeight(
LayoutUnit LayoutBox::AvailableLogicalHeightUsing(
const Length& h,
AvailableLogicalHeightType height_type) const {
- if (IsLayoutView()) {
+ if (auto* layout_view = DynamicTo<LayoutView>(this)) {
return LayoutUnit(IsHorizontalWritingMode()
- ? ToLayoutView(this)->GetFrameView()->Size().Height()
- : ToLayoutView(this)->GetFrameView()->Size().Width());
+ ? layout_view->GetFrameView()->Size().Height()
+ : layout_view->GetFrameView()->Size().Width());
}
// We need to stop here, since we don't want to increase the height of the
@@ -4192,10 +4351,17 @@ LayoutUnit LayoutBox::AvailableLogicalHeightUsing(
return LogicalHeight() - BorderAndPaddingLogicalHeight();
}
- if (IsFlexItem()) {
- const LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
- if (flex_box.UseOverrideLogicalHeightForPerentageResolution(*this))
- return OverrideContentLogicalHeight();
+ if (IsFlexItemIncludingNG()) {
+ if (IsFlexItem()) {
+ const LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
+ if (flex_box.UseOverrideLogicalHeightForPerentageResolution(*this))
+ return OverrideContentLogicalHeight();
+ } else if (GetCachedLayoutResult()) {
+ const NGConstraintSpace& space =
+ GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ if (space.IsFixedBlockSize() && !space.IsFixedBlockSizeIndefinite())
+ return space.AvailableSize().block_size;
+ }
}
if (h.IsPercentOrCalc() && IsOutOfFlowPositioned()) {
@@ -4271,9 +4437,9 @@ LayoutUnit LayoutBox::ContainingBlockLogicalWidthForPositioned(
return ContainingBlockLogicalHeightForPositioned(containing_block, false);
// Use viewport as container for top-level fixed-position elements.
- if (StyleRef().GetPosition() == EPosition::kFixed &&
- containing_block->IsLayoutView() && !GetDocument().Printing()) {
- const LayoutView* view = ToLayoutView(containing_block);
+ const auto* view = DynamicTo<LayoutView>(containing_block);
+ if (StyleRef().GetPosition() == EPosition::kFixed && view &&
+ !GetDocument().Printing()) {
if (LocalFrameView* frame_view = view->GetFrameView()) {
// Don't use visibleContentRect since the PaintLayer's size has not been
// set yet.
@@ -4342,9 +4508,9 @@ LayoutUnit LayoutBox::ContainingBlockLogicalHeightForPositioned(
return ContainingBlockLogicalWidthForPositioned(containing_block, false);
// Use viewport as container for top-level fixed-position elements.
- if (StyleRef().GetPosition() == EPosition::kFixed &&
- containing_block->IsLayoutView() && !GetDocument().Printing()) {
- const LayoutView* view = ToLayoutView(containing_block);
+ const auto* view = DynamicTo<LayoutView>(containing_block);
+ if (StyleRef().GetPosition() == EPosition::kFixed && view &&
+ !GetDocument().Printing()) {
if (LocalFrameView* frame_view = view->GetFrameView()) {
// Don't use visibleContentRect since the PaintLayer's size has not been
// set yet.
@@ -4368,7 +4534,7 @@ LayoutUnit LayoutBox::ContainingBlockLogicalHeightForPositioned(
const LayoutInline* flow = ToLayoutInline(containing_block);
// If the containing block is empty, return a height of 0.
- if (flow->IsEmpty())
+ if (!flow->HasInlineFragments())
return LayoutUnit();
LayoutUnit height_result;
@@ -4583,7 +4749,7 @@ void LayoutBox::ComputePositionedLogicalWidth(
margin_logical_right, computed_values);
// Calculate constraint equation values for 'max-width' case.
- if (!StyleRef().LogicalMaxWidth().IsMaxSizeNone()) {
+ if (!StyleRef().LogicalMaxWidth().IsNone()) {
LogicalExtentComputedValues max_values;
ComputePositionedLogicalWidthUsing(
@@ -4653,13 +4819,9 @@ void LayoutBox::ComputeLogicalLeftPositionedOffset(
LayoutUnit LayoutBox::ShrinkToFitLogicalWidth(
LayoutUnit available_logical_width,
LayoutUnit borders_plus_padding) const {
- LayoutUnit preferred_logical_width =
- MaxPreferredLogicalWidth() - borders_plus_padding;
- LayoutUnit preferred_min_logical_width =
- MinPreferredLogicalWidth() - borders_plus_padding;
- return std::min(
- std::max(preferred_min_logical_width, available_logical_width),
- preferred_logical_width);
+ MinMaxSizes sizes = PreferredLogicalWidths();
+ sizes -= borders_plus_padding;
+ return sizes.ShrinkToFit(available_logical_width);
}
void LayoutBox::ComputePositionedLogicalWidthUsing(
@@ -4678,16 +4840,16 @@ void LayoutBox::ComputePositionedLogicalWidthUsing(
DCHECK(width_size_type == kMinSize ||
width_size_type == kMainOrPreferredSize || !logical_width.IsAuto());
- if (width_size_type == kMinSize && logical_width.IsAuto())
+ if (width_size_type == kMinSize && logical_width.IsAuto()) {
logical_width_value = LayoutUnit();
- else if (logical_width.IsIntrinsic())
- logical_width_value =
- ComputeIntrinsicLogicalWidthUsing(
- logical_width, container_logical_width, borders_plus_padding) -
- borders_plus_padding;
- else
+ } else if (logical_width.IsIntrinsic()) {
+ logical_width_value = ComputeIntrinsicLogicalWidthUsing(
+ logical_width, container_logical_width) -
+ borders_plus_padding;
+ } else {
logical_width_value = AdjustContentBoxLogicalWidthForBoxSizing(
ValueForLength(logical_width, container_logical_width));
+ }
// 'left' and 'right' cannot both be 'auto' because one would of been
// converted to the static position already
@@ -4996,8 +5158,7 @@ void LayoutBox::ComputePositionedLogicalHeight(
// Calculate constraint equation values for 'max-height' case.
const Length& logical_max_height = style_to_use.LogicalMaxHeight();
- if (!logical_max_height.IsMaxSizeNone() &&
- !logical_max_height.IsMinContent() &&
+ if (!logical_max_height.IsNone() && !logical_max_height.IsMinContent() &&
!logical_max_height.IsMaxContent() &&
!logical_max_height.IsFitContent()) {
LogicalExtentComputedValues max_values;
@@ -5695,7 +5856,7 @@ void LayoutBox::AddLayoutOverflow(const LayoutRect& rect) {
// For overflow clip objects, we don't want to propagate overflow into
// unreachable areas.
LayoutRect overflow_rect(rect);
- if (HasOverflowClip() || IsLayoutView()) {
+ if (HasOverflowClip() || IsA<LayoutView>(this)) {
// Overflow is in the block's coordinate space and thus is flipped for
// vertical-rl writing
// mode. At this stage that is actually a simplification, since we can
@@ -5813,7 +5974,7 @@ bool LayoutBox::HasUnsplittableScrollingOverflow() const {
// world and is what we used to do in the old model anyway.
return !StyleRef().LogicalHeight().IsIntrinsicOrAuto() ||
(!StyleRef().LogicalMaxHeight().IsIntrinsicOrAuto() &&
- !StyleRef().LogicalMaxHeight().IsMaxSizeNone() &&
+ !StyleRef().LogicalMaxHeight().IsNone() &&
(!StyleRef().LogicalMaxHeight().IsPercentOrCalc() ||
PercentageLogicalHeightIsResolvable())) ||
(!StyleRef().LogicalMinHeight().IsIntrinsicOrAuto() &&
@@ -6029,7 +6190,7 @@ static void MarkBoxForRelayoutAfterSplit(LayoutBox* box) {
ToInterface<LayoutNGTableSectionInterface>(box)->SetNeedsCellRecalc();
}
- box->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ box->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kAnonymousBlockChange);
}
@@ -6336,11 +6497,11 @@ void LayoutBox::ReassignSnapAreas(LayoutBox& new_container) {
}
bool LayoutBox::AllowedToPropagateRecursiveScrollToParentFrame(
- const WebScrollIntoViewParams& params) {
+ const mojom::blink::ScrollIntoViewParamsPtr& params) {
if (!GetFrameView()->SafeToPropagateScrollToParent())
return false;
- if (params.GetScrollType() != kProgrammaticScroll)
+ if (params->type != mojom::blink::ScrollType::kProgrammatic)
return true;
return !GetDocument().IsVerticalScrollEnforced();
@@ -6420,7 +6581,7 @@ TextDirection LayoutBox::ResolvedDirection() const {
NGInlineCursor cursor;
cursor.MoveTo(*this);
if (cursor)
- return cursor.CurrentResolvedDirection();
+ return cursor.Current().ResolvedDirection();
}
if (InlineBoxWrapper())
return InlineBoxWrapper()->Direction();
@@ -6428,4 +6589,15 @@ TextDirection LayoutBox::ResolvedDirection() const {
return StyleRef().Direction();
}
+bool LayoutBox::NeedsScrollNode(
+ CompositingReasons direct_compositing_reasons) const {
+ if (!HasOverflowClip())
+ return false;
+
+ if (direct_compositing_reasons & CompositingReason::kRootScroller)
+ return true;
+
+ return GetScrollableArea()->ScrollsOverflow();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box.h b/chromium/third_party/blink/renderer/core/layout/layout_box.h
index d7c8e1e3355..a9484751df2 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box.h
@@ -26,16 +26,16 @@
#include <memory>
#include "base/macros.h"
+#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
-#include "third_party/blink/renderer/core/layout/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "third_party/blink/renderer/core/layout/overflow_model.h"
#include "third_party/blink/renderer/platform/graphics/scroll_types.h"
namespace blink {
class CustomLayoutChild;
-class EventHandler;
class LayoutBlockFlow;
class LayoutMultiColumnSpannerPlaceholder;
class NGBoxFragmentBuilder;
@@ -49,7 +49,6 @@ enum class NGLayoutCacheStatus;
class NGLayoutResult;
struct NGPhysicalBoxStrut;
struct PaintInfo;
-struct WebScrollIntoViewParams;
enum SizeType { kMainOrPreferredSize, kMinSize, kMaxSize };
enum AvailableLogicalHeightType {
@@ -66,12 +65,12 @@ enum ShouldComputePreferred { kComputeActual, kComputePreferred };
using SnapAreaSet = HashSet<LayoutBox*>;
-struct LayoutBoxRareData {
- USING_FAST_MALLOC(LayoutBoxRareData);
-
+struct LayoutBoxRareData final : public GarbageCollected<LayoutBoxRareData> {
public:
LayoutBoxRareData();
+ void Trace(Visitor* visitor);
+
// For spanners, the spanner placeholder that lays us out within the multicol
// container.
LayoutMultiColumnSpannerPlaceholder* spanner_placeholder_;
@@ -115,7 +114,7 @@ struct LayoutBoxRareData {
// Used by CSSLayoutDefinition::Instance::Layout. Represents the script
// object for this box that web developers can query style, and perform
// layout upon. Only created if IsCustomItem() is true.
- Persistent<CustomLayoutChild> layout_child_;
+ Member<CustomLayoutChild> layout_child_;
DISALLOW_COPY_AND_ASSIGN(LayoutBoxRareData);
};
@@ -224,6 +223,11 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
virtual bool BackgroundShouldAlwaysBeClipped() const { return false; }
+ // Returns whether this object needs a scroll paint property tree node. These
+ // are a requirement for composited scrolling but are also created for
+ // non-composited scrollers.
+ bool NeedsScrollNode(CompositingReasons direct_compositing_reasons) const;
+
// Use this with caution! No type checking is done!
LayoutBox* FirstChildBox() const;
LayoutBox* FirstInFlowChildBox() const;
@@ -408,16 +412,17 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
ClientHeight());
}
- // TODO(crbu.com/962299): This method is only correct when |offset| is the
- // correct paint offset. It's also incrrect in flipped blocks writing mode.
- IntRect PixelSnappedBorderBoxRect(const PhysicalOffset& offset) const {
- return PixelSnappedBorderBoxRect(offset.ToLayoutSize());
- }
- IntRect PixelSnappedBorderBoxRect(
- const LayoutSize& offset = LayoutSize()) const {
+ // TODO(crbug.com/962299): This method snaps to pixels incorrectly because
+ // Location() is not the correct paint offset. It's also incorrect in flipped
+ // blocks writing mode.
+ IntRect PixelSnappedBorderBoxRect() const {
return IntRect(IntPoint(),
- PixelSnappedIntSize(frame_rect_.Size(),
- frame_rect_.Location() + offset));
+ PixelSnappedBorderBoxSize(PhysicalOffset(Location())));
+ }
+ // TODO(crbug.com/962299): This method is only correct when |offset| is the
+ // correct paint offset.
+ IntSize PixelSnappedBorderBoxSize(const PhysicalOffset& offset) const {
+ return PixelSnappedIntSize(Size(), offset.ToLayoutPoint());
}
IntRect BorderBoundingBox() const final {
return PixelSnappedBorderBoxRect();
@@ -635,6 +640,11 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
: OverrideIntrinsicContentWidth();
}
+ // Returns element-native intrinsic size. Returns kIndefiniteSize if no such
+ // size.
+ LayoutUnit DefaultIntrinsicContentInlineSize() const;
+ LayoutUnit DefaultIntrinsicContentBlockSize() const;
+
// IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines
// (LayoutFlow) to return the remaining width on a given line (and the height
// of a single line).
@@ -718,8 +728,9 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
void ScrollByRecursively(const ScrollOffset& delta);
// If makeVisibleInVisualViewport is set, the visual viewport will be scrolled
// if required to make the rect visible.
- PhysicalRect ScrollRectToVisibleRecursive(const PhysicalRect&,
- const WebScrollIntoViewParams&);
+ PhysicalRect ScrollRectToVisibleRecursive(
+ const PhysicalRect&,
+ mojom::blink::ScrollIntoViewParamsPtr);
LayoutRectOutsets MarginBoxOutsets() const { return margin_box_outsets_; }
LayoutUnit MarginTop() const override { return margin_box_outsets_.Top(); }
@@ -795,8 +806,11 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
const PhysicalOffset& accumulated_offset,
HitTestAction) override;
- LayoutUnit MinPreferredLogicalWidth() const override;
- LayoutUnit MaxPreferredLogicalWidth() const override;
+ // This function calculates the preferred widths for an object.
+ //
+ // See INTRINSIC SIZES / PREFERRED LOGICAL WIDTHS in layout_object.h for more
+ // details about those widths.
+ MinMaxSizes PreferredLogicalWidths() const override;
LayoutUnit OverrideLogicalHeight() const;
LayoutUnit OverrideLogicalWidth() const;
@@ -941,17 +955,27 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
void SetInlineBoxWrapper(InlineBox*);
void DeleteLineBoxWrapper();
+ bool HasInlineFragments() const final;
NGPaintFragment* FirstInlineFragment() const final;
void SetFirstInlineFragment(NGPaintFragment*) final;
wtf_size_t FirstInlineFragmentItemIndex() const final;
void ClearFirstInlineFragmentItemIndex() final;
void SetFirstInlineFragmentItemIndex(wtf_size_t) final;
- void SetCachedLayoutResult(const NGLayoutResult&, const NGBreakToken*);
- void ClearCachedLayoutResult();
- const NGLayoutResult* GetCachedLayoutResult() const {
- return cached_layout_result_.get();
- }
+ void InvalidateItems(const NGLayoutResult&);
+
+ void SetCachedLayoutResult(scoped_refptr<const NGLayoutResult>);
+
+ // Store one layout result (with its physical fragment) at the specified
+ // index, and delete all entries following it.
+ void AddLayoutResult(scoped_refptr<const NGLayoutResult>, wtf_size_t index);
+
+ void ShrinkLayoutResults(wtf_size_t results_to_keep);
+ void ClearLayoutResults();
+
+ const NGLayoutResult* GetCachedLayoutResult() const;
+ const NGLayoutResult* GetCachedMeasureResult() const;
+
// Returns the last layout result for this block flow with the given
// constraint space and break token, or null if it is not up-to-date or
// otherwise unavailable.
@@ -969,6 +993,11 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
base::Optional<NGFragmentGeometry>* initial_fragment_geometry,
NGLayoutCacheStatus* out_cache_status);
+ const NGPhysicalBoxFragment* GetPhysicalFragment(wtf_size_t i) const;
+ const FragmentData* FragmentDataFromPhysicalFragment(
+ const NGPhysicalBoxFragment&) const;
+ wtf_size_t PhysicalFragmentCount() const { return layout_results_.size(); }
+
void SetSpannerPlaceholder(LayoutMultiColumnSpannerPlaceholder&);
void ClearSpannerPlaceholder();
LayoutMultiColumnSpannerPlaceholder* SpannerPlaceholder() const final {
@@ -1018,7 +1047,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
// value of the previous in-flow sibling.
bool NeedsForcedBreakBefore(EBreakBetween previous_break_after_value) const;
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override;
bool MapToVisualRectInAncestorSpaceInternal(
const LayoutBoxModelObject* ancestor,
TransformState&,
@@ -1076,6 +1104,7 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LayoutUnit ShrinkLogicalWidthToAvoidFloats(LayoutUnit child_margin_start,
LayoutUnit child_margin_end,
const LayoutBlockFlow* cb) const;
+ bool AutoWidthShouldFitContent() const;
LayoutUnit ComputeLogicalWidthUsing(
SizeType,
@@ -1166,8 +1195,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
const FloatPoint& point_in_root_frame) const;
static LayoutBox* FindAutoscrollable(LayoutObject*,
bool is_middle_click_autoscroll);
- virtual void StopAutoscroll() {}
- virtual void MayUpdateHoverWhenContentUnderMouseChanged(EventHandler&);
DISABLE_CFI_PERF bool HasAutoVerticalScrollbar() const {
return HasOverflowClip() && StyleRef().HasAutoVerticalScroll();
@@ -1315,6 +1342,8 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
bool IsGridItem() const { return Parent() && Parent()->IsLayoutGrid(); }
+ bool IsMathItem() const { return Parent() && Parent()->IsMathML(); }
+
LayoutUnit LineHeight(
bool first_line,
LineDirectionMode,
@@ -1501,6 +1530,12 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
const HitTestLocation&,
const PhysicalOffset& border_box_location) const;
+ virtual bool HitTestOverflowControl(HitTestResult&,
+ const HitTestLocation&,
+ const PhysicalOffset&) const {
+ return false;
+ }
+
// Returns true if the box intersects the viewport visible to the user.
bool IntersectsVisibleViewport() const;
@@ -1508,7 +1543,7 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
void EnsureIsReadyForPaintInvalidation() override;
- virtual bool HasControlClip() const { return false; }
+ bool HasControlClip() const;
class MutableForPainting : public LayoutObject::MutableForPainting {
public:
@@ -1553,46 +1588,53 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
: PhysicalRect(PhysicalOffset(), PreviousSize());
}
- // This function calculates the preferred widths for an object.
+ // Calculates the intrinsic logical widths for this layout box.
+ // https://drafts.csswg.org/css-sizing-3/#intrinsic
//
- // This function is only expected to be called if
- // the boolean preferredLogicalWidthsDirty is true. It also MUST clear the
- // boolean before returning.
+ // intrinsicWidth is defined as:
+ // intrinsic size of content (with our border and padding) +
+ // scrollbarWidth.
//
- // See INTRINSIC SIZES / PREFERRED LOGICAL WIDTHS in layout_object.h for more
- // details about those widths.
+ // preferredWidth is defined as:
+ // fixedWidth OR (intrinsicWidth plus border and padding).
+ // Note: fixedWidth includes border and padding and scrollbarWidth.
//
- // This function is public only for use by LayoutNG. Other callers should go
- // through MinPreferredLogicalWidth/MaxPreferredLogicalWidth.
- virtual void ComputePreferredLogicalWidths() {
- ClearPreferredLogicalWidthsDirty();
+ // This is public only for use by LayoutNG. Do not call this elsewhere.
+ virtual MinMaxSizes ComputeIntrinsicLogicalWidths() const = 0;
+
+ // Returns the (maybe cached) intrinsic logical widths for this layout box.
+ MinMaxSizes IntrinsicLogicalWidths() const {
+ const_cast<LayoutBox*>(this)->UpdateCachedIntrinsicLogicalWidthsIfNeeded();
+ return intrinsic_logical_widths_;
}
- // LayoutNG can use this function to update our cache of preferred logical
+ // If |IntrinsicLogicalWidthsDirty()| is true, recalculates the intrinsic
+ // logical widths.
+ void UpdateCachedIntrinsicLogicalWidthsIfNeeded();
+
+ // LayoutNG can use this function to update our cache of intrinsic logical
// widths when the layout object is managed by NG. Should not be called by
// regular code.
- // Also clears the "dirty" flag for preferred widths.
- void SetPreferredLogicalWidthsFromNG(MinMaxSize sizes) {
- min_preferred_logical_width_ = sizes.min_size;
- max_preferred_logical_width_ = sizes.max_size;
- ClearPreferredLogicalWidthsDirty();
+ //
+ // Also clears the "dirty" flag for the intrinsic logical widths.
+ void SetIntrinsicLogicalWidthsFromNG(
+ const MinMaxSizes& sizes,
+ LayoutUnit intrinsic_logical_widths_percentage_resolution_block_size) {
+ intrinsic_logical_widths_ = sizes;
+ intrinsic_logical_widths_percentage_resolution_block_size_ =
+ intrinsic_logical_widths_percentage_resolution_block_size;
+
+ ClearIntrinsicLogicalWidthsDirty();
}
- // Calculates the intrinsic(https://drafts.csswg.org/css-sizing-3/#intrinsic)
- // logical widths for this layout box.
- //
- // intrinsicWidth is defined as:
- // intrinsic size of content (without our border and padding) +
- // scrollbarWidth.
- //
- // preferredWidth is defined as:
- // fixedWidth OR (intrinsicWidth plus border and padding).
- // Note: fixedWidth includes border and padding and scrollbarWidth.
+ // Returns what %-resolution-block-size was used in the intrinsic logical
+ // widths phase.
//
- // This is public only for use by LayoutNG. Do not call this elsewhere.
- virtual void ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const;
+ // For non-LayoutNG code this is always LayoutUnit::Min(), and should not be
+ // used for caching purposes.
+ LayoutUnit IntrinsicLogicalWidthsPercentageResolutionBlockSize() const {
+ return intrinsic_logical_widths_percentage_resolution_block_size_;
+ }
// Make it public.
using LayoutObject::BackgroundIsKnownToBeObscured;
@@ -1601,9 +1643,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
~LayoutBox() override;
virtual bool ComputeShouldClipOverflow() const;
- virtual PhysicalRect ControlClipRect(const PhysicalOffset&) const {
- return PhysicalRect();
- }
void WillBeDestroyed() override;
@@ -1636,8 +1675,7 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LayoutUnit ComputeIntrinsicLogicalWidthUsing(
const Length& logical_width_length,
- LayoutUnit available_logical_width,
- LayoutUnit border_and_padding) const;
+ LayoutUnit available_logical_width) const;
LayoutUnit ComputeIntrinsicLogicalContentHeightUsing(
const Length& logical_height_length,
LayoutUnit intrinsic_content_height,
@@ -1645,11 +1683,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LayoutObject* SplitAnonymousBoxesAroundChild(LayoutObject* before_child);
- virtual bool HitTestOverflowControl(HitTestResult&,
- const HitTestLocation&,
- const PhysicalOffset&) {
- return false;
- }
virtual bool HitTestChildren(HitTestResult&,
const HitTestLocation&,
const PhysicalOffset& accumulated_offset,
@@ -1726,7 +1759,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
void ClearScrollSnapMapping();
void AddScrollSnapMapping();
- bool AutoWidthShouldFitContent() const;
LayoutUnit ShrinkToFitLogicalWidth(LayoutUnit available_logical_width,
LayoutUnit borders_plus_padding) const;
@@ -1766,8 +1798,8 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LayoutBoxRareData& EnsureRareData() {
if (!rare_data_)
- rare_data_ = std::make_unique<LayoutBoxRareData>();
- return *rare_data_.get();
+ rare_data_ = MakeGarbageCollected<LayoutBoxRareData>();
+ return *rare_data_.Get();
}
bool LogicalHeightComputesAsNone(SizeType) const;
@@ -1794,7 +1826,7 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
// Returns true when the current recursive scroll into visible could propagate
// to parent frame.
bool AllowedToPropagateRecursiveScrollToParentFrame(
- const WebScrollIntoViewParams&);
+ const mojom::blink::ScrollIntoViewParamsPtr&);
PhysicalRect DebugRect() const override;
@@ -1845,16 +1877,8 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
mutable LayoutUnit intrinsic_content_logical_height_;
protected:
- // The logical width of the element if it were to break its lines at every
- // possible opportunity.
- //
- // See LayoutObject::minPreferredLogicalWidth() for more details.
- LayoutUnit min_preferred_logical_width_;
-
- // The logical width of the element if it never breaks any lines at all.
- //
- // See LayoutObject::maxPreferredLogicalWidth() for more details.
- LayoutUnit max_preferred_logical_width_;
+ MinMaxSizes intrinsic_logical_widths_;
+ LayoutUnit intrinsic_logical_widths_percentage_resolution_block_size_;
// LayoutBoxUtils is used for the LayoutNG code querying protected methods on
// this class, e.g. determining the static-position of OOF elements.
@@ -1892,8 +1916,9 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
wtf_size_t first_fragment_item_index_;
};
- std::unique_ptr<LayoutBoxRareData> rare_data_;
- scoped_refptr<const NGLayoutResult> cached_layout_result_;
+ Persistent<LayoutBoxRareData> rare_data_;
+ scoped_refptr<const NGLayoutResult> measure_result_;
+ Vector<scoped_refptr<const NGLayoutResult>, 1> layout_results_;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutBox, IsBox());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc
index 21782639cd2..e3b20800d32 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc
@@ -29,6 +29,7 @@
#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/html_body_element.h"
#include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
#include "third_party/blink/renderer/core/layout/layout_block.h"
@@ -36,6 +37,8 @@
#include "third_party/blink/renderer/core/layout/layout_geometry_map.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h"
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
#include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
@@ -85,10 +88,6 @@ void LayoutBoxModelObject::ContentChanged(ContentChangeType change_type) {
Layer()->ContentChanged(change_type);
}
-bool LayoutBoxModelObject::HasAcceleratedCompositing() const {
- return View()->Compositor()->HasAcceleratedCompositing();
-}
-
LayoutBoxModelObject::LayoutBoxModelObject(ContainerNode* node)
: LayoutObject(node) {}
@@ -97,9 +96,10 @@ bool LayoutBoxModelObject::UsesCompositedScrolling() const {
Layer()->GetScrollableArea()->UsesCompositedScrolling();
}
-BackgroundPaintLocation LayoutBoxModelObject::GetBackgroundPaintLocation(
+BackgroundPaintLocation
+LayoutBoxModelObject::ComputeBackgroundPaintLocationIfComposited(
uint32_t* main_thread_scrolling_reasons) const {
- bool may_have_scrolling_layers_without_scrolling = IsLayoutView();
+ bool may_have_scrolling_layers_without_scrolling = IsA<LayoutView>(this);
const auto* scrollable_area = GetScrollableArea();
bool scrolls_overflow = scrollable_area && scrollable_area->ScrollsOverflow();
if (!scrolls_overflow && !may_have_scrolling_layers_without_scrolling)
@@ -108,9 +108,8 @@ BackgroundPaintLocation LayoutBoxModelObject::GetBackgroundPaintLocation(
// If we care about LCD text, paint root backgrounds into scrolling contents
// layer even if style suggests otherwise. (For non-root scrollers, we just
// avoid compositing - see PLSA::ComputeNeedsCompositedScrolling.)
- if (IsLayoutView()) {
- DCHECK(Layer()->Compositor());
- if (!Layer()->Compositor()->PreferCompositingToLCDTextEnabled())
+ if (IsA<LayoutView>(this)) {
+ if (!GetDocument().GetSettings()->GetPreferCompositingToLCDTextEnabled())
return kBackgroundPaintInScrollingContents;
}
@@ -283,13 +282,9 @@ void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
// block/inline position.
// Position changes and other types of display changes are handled elsewhere.
if (old_style && IsOutOfFlowPositioned() && Parent() &&
- (Parent() != ContainingBlock()) &&
(StyleRef().GetPosition() == old_style->GetPosition()) &&
- (StyleRef().OriginalDisplay() != old_style->OriginalDisplay()) &&
- ((StyleRef().OriginalDisplay() == EDisplay::kBlock) ||
- (StyleRef().OriginalDisplay() == EDisplay::kInlineBlock)) &&
- ((old_style->OriginalDisplay() == EDisplay::kBlock) ||
- (old_style->OriginalDisplay() == EDisplay::kInlineBlock)))
+ (StyleRef().IsOriginalDisplayInlineType() !=
+ old_style->IsOriginalDisplayInlineType()))
Parent()->SetNeedsLayout(layout_invalidation_reason::kChildChanged,
kMarkContainerChain);
@@ -320,7 +315,7 @@ void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
if (EverHadLayout())
SetChildNeedsLayout();
if (had_transform_related_property) {
- SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kStyleChange);
}
if (!NeedsLayout()) {
@@ -444,7 +439,6 @@ void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
// Remove sticky constraints for this layer.
if (Layer()) {
- DisableCompositingQueryAsserts disabler;
if (const PaintLayer* ancestor_overflow_layer =
Layer()->AncestorOverflowLayer()) {
if (PaintLayerScrollableArea* scrollable_area =
@@ -519,7 +513,6 @@ void LayoutBoxModelObject::InvalidateStickyConstraints() {
// This intentionally uses the stale ancestor overflow layer compositing input
// as if we have saved constraints for this layer they were saved in the
// previous frame.
- DisableCompositingQueryAsserts disabler;
if (const PaintLayer* ancestor_overflow_layer =
enclosing->AncestorOverflowLayer()) {
if (PaintLayerScrollableArea* ancestor_scrollable_area =
@@ -537,6 +530,8 @@ void LayoutBoxModelObject::CreateLayerAfterStyleChange() {
// Creating a layer may affect existence of the LocalBorderBoxProperties, so
// we need to ensure that we update paint properties.
SetNeedsPaintPropertyUpdate();
+ if (GetScrollableArea())
+ GetScrollableArea()->InvalidateScrollTimeline();
}
void LayoutBoxModelObject::DestroyLayer() {
@@ -546,6 +541,7 @@ void LayoutBoxModelObject::DestroyLayer() {
// Removing a layer may affect existence of the LocalBorderBoxProperties, so
// we need to ensure that we update paint properties.
SetNeedsPaintPropertyUpdate();
+ SetBackgroundPaintLocation(kBackgroundPaintInGraphicsLayer);
}
bool LayoutBoxModelObject::HasSelfPaintingLayer() const {
@@ -679,7 +675,7 @@ LayoutBlock* LayoutBoxModelObject::ContainingBlockForAutoHeightDetection(
// Match LayoutBox::availableLogicalHeightUsing by special casing the layout
// view. The available height is taken from the frame.
- if (cb->IsLayoutView())
+ if (IsA<LayoutView>(cb))
return nullptr;
if (IsOutOfFlowPositionedWithImplicitHeight(cb))
@@ -700,10 +696,17 @@ bool LayoutBoxModelObject::HasAutoHeightOrContainingBlockWithAutoHeight(
logical_height_length.IsPercentOrCalc() && cb && IsBox()) {
cb->AddPercentHeightDescendant(const_cast<LayoutBox*>(ToLayoutBox(this)));
}
- if (this_box && this_box->IsFlexItem()) {
- const LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
- if (flex_box.UseOverrideLogicalHeightForPerentageResolution(*this_box))
- return false;
+ if (this_box && this_box->IsFlexItemIncludingNG()) {
+ if (this_box->IsFlexItem()) {
+ const LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
+ if (flex_box.UseOverrideLogicalHeightForPerentageResolution(*this_box))
+ return false;
+ } else if (this_box->GetCachedLayoutResult()) {
+ const NGConstraintSpace& space =
+ this_box->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ if (space.IsFixedBlockSize() && !space.IsFixedBlockSizeIndefinite())
+ return false;
+ }
}
if (this_box && this_box->IsGridItem() &&
this_box->HasOverrideContainingBlockContentLogicalHeight())
@@ -722,8 +725,14 @@ bool LayoutBoxModelObject::HasAutoHeightOrContainingBlockWithAutoHeight(
// resolve the block-size of the descendant, except when in quirks mode.
// Flexboxes follow strict behavior even in quirks mode, though.
if (!GetDocument().InQuirksMode() ||
- cb->IsFlexibleBoxIncludingDeprecatedAndNG())
+ cb->IsFlexibleBoxIncludingDeprecatedAndNG()) {
+ if (this_box &&
+ this_box->HasOverrideContainingBlockContentLogicalHeight()) {
+ return this_box->OverrideContainingBlockContentLogicalHeight() ==
+ LayoutUnit(-1);
+ }
return !cb->HasDefiniteLogicalHeight();
+ }
}
return false;
@@ -881,7 +890,7 @@ void LayoutBoxModelObject::UpdateStickyPositionConstraints() const {
ToLayoutBox(Layer()->AncestorOverflowLayer()->GetLayoutObject());
LayoutUnit max_container_width =
- containing_block->IsLayoutView()
+ IsA<LayoutView>(containing_block)
? containing_block->LogicalWidth()
: containing_block->ContainingBlockLogicalWidthForContent();
// Sticky positioned element ignore any override logical width on the
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h
index 40b2a33964e..dd19932660c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object.h
@@ -185,13 +185,13 @@ class CORE_EXPORT LayoutBoxModelObject : public LayoutObject {
bool UsesCompositedScrolling() const;
- // Returns which layers backgrounds should be painted into for overflow
- // scrolling boxes.
+ // Returns which layers backgrounds should be painted into for a overflow
+ // scrolling box if it uses composited scrolling.
// TODO(yigu): PaintLayerScrollableArea::ComputeNeedsCompositedScrolling
// calls this method to obtain main thread scrolling reasons due to
// background paint location. Once the cases get handled on compositor the
// parameter "reasons" could be removed.
- BackgroundPaintLocation GetBackgroundPaintLocation(
+ BackgroundPaintLocation ComputeBackgroundPaintLocationIfComposited(
uint32_t* main_thread_scrolling_reasons = nullptr) const;
// These return the CSS computed padding values.
@@ -415,7 +415,6 @@ class CORE_EXPORT LayoutBoxModelObject : public LayoutObject {
LayoutGeometryMap&) const override;
void ContentChanged(ContentChangeType);
- bool HasAcceleratedCompositing() const;
// Returns true if the background is painted opaque in the given rect.
// The query rect is given in local coordinate system.
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc
index b4c95094980..990362b2148 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc
@@ -423,7 +423,8 @@ TEST_F(LayoutBoxModelObjectTest, StickyPositionConstraintInvalidation) {
.at(sticky->Layer())
.scroll_container_relative_sticky_box_rect.X());
To<HTMLElement>(target->GetNode())->classList().Add("hide");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
// Layout should invalidate the sticky constraints of the sticky element and
// mark it as needing a compositing inputs update.
EXPECT_FALSE(
@@ -1075,7 +1076,8 @@ TEST_F(LayoutBoxModelObjectTest, InvalidatePaintLayerOnStackedChange) {
EXPECT_NE(parent, original_compositing_container->GetLayoutObject());
target_element->setAttribute(html_names::kClassAttr, "non-stacked");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(target->StyleRef().IsStacked());
EXPECT_TRUE(target->Layer()->SelfNeedsRepaint());
@@ -1085,7 +1087,8 @@ TEST_F(LayoutBoxModelObjectTest, InvalidatePaintLayerOnStackedChange) {
UpdateAllLifecyclePhasesForTest();
target_element->setAttribute(html_names::kClassAttr, "stacked");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(target->StyleRef().IsStacked());
EXPECT_TRUE(target->Layer()->SelfNeedsRepaint());
@@ -1156,13 +1159,15 @@ TEST_F(LayoutBoxModelObjectTest, BackfaceVisibilityChange) {
target->setAttribute(html_names::kStyleAttr,
base_style + "; backface-visibility: hidden");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(target_layer->SelfNeedsRepaint());
UpdateAllLifecyclePhasesForTest();
EXPECT_FALSE(target_layer->SelfNeedsRepaint());
target->setAttribute(html_names::kStyleAttr, base_style);
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(target_layer->SelfNeedsRepaint());
UpdateAllLifecyclePhasesForTest();
EXPECT_FALSE(target_layer->SelfNeedsRepaint());
@@ -1216,7 +1221,8 @@ TEST_F(LayoutBoxModelObjectTest,
EXPECT_EQ(target->Layer(), target->Layer()->NearestContainedLayoutLayer());
To<HTMLElement>(target->GetNode())->classList().Remove("contained");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(target->Layer()->NeedsCompositingInputsUpdate());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_box_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_box_test.cc
index e298eb904a7..99bcb9ca795 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box_test.cc
@@ -392,12 +392,7 @@ TEST_P(LayoutBoxTest, ControlClip) {
EXPECT_TRUE(target->HasControlClip());
EXPECT_TRUE(target->HasClipRelatedProperty());
EXPECT_TRUE(target->ShouldClipOverflow());
-#if defined(OS_MACOSX)
- EXPECT_EQ(PhysicalRect(0, 0, 100, 18),
- target->ClippingRect(PhysicalOffset()));
-#else
EXPECT_EQ(PhysicalRect(2, 2, 96, 46), target->ClippingRect(PhysicalOffset()));
-#endif
}
TEST_P(LayoutBoxTest, LocalVisualRectWithMask) {
@@ -1436,7 +1431,8 @@ TEST_P(LayoutBoxTest, HasNonCollapsedBorderDecoration) {
To<Element>(div->GetNode())
->setAttribute(html_names::kStyleAttr, "border: 1px solid black");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason ::kTest);
EXPECT_TRUE(div->HasNonCollapsedBorderDecoration());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_button.cc b/chromium/third_party/blink/renderer/core/layout/layout_button.cc
index c743f0cd09a..28d3a96c0a5 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_button.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_button.cc
@@ -73,14 +73,6 @@ void LayoutButton::UpdateAnonymousChildStyle(const LayoutObject* child,
child_style.SetAlignContent(StyleRef().AlignContent());
}
-PhysicalRect LayoutButton::ControlClipRect(
- const PhysicalOffset& additional_offset) const {
- // Clip to the padding box to at least give content the extra padding space.
- PhysicalRect rect(additional_offset, Size());
- rect.Expand(BorderInsets());
- return rect;
-}
-
LayoutUnit LayoutButton::BaselinePosition(
FontBaseline baseline,
bool first_line,
@@ -106,8 +98,4 @@ LayoutUnit LayoutButton::BaselinePosition(
line_position_mode);
}
-// For compatibility with IE/FF we only clip overflow on input elements.
-bool LayoutButton::HasControlClip() const {
- return !IsA<HTMLButtonElement>(GetNode());
-}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_button.h b/chromium/third_party/blink/renderer/core/layout/layout_button.h
index b9aaedc709e..60ce95bc9a4 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_button.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_button.h
@@ -48,9 +48,6 @@ class LayoutButton final : public LayoutFlexibleBox {
void RemoveLeftoverAnonymousBlock(LayoutBlock*) override {}
bool CreatesAnonymousWrapper() const override { return true; }
- bool HasControlClip() const override;
- PhysicalRect ControlClipRect(const PhysicalOffset&) const override;
-
LayoutUnit BaselinePosition(FontBaseline,
bool first_line,
LineDirectionMode,
@@ -60,10 +57,6 @@ class LayoutButton final : public LayoutFlexibleBox {
void UpdateAnonymousChildStyle(const LayoutObject* child,
ComputedStyle& child_style) const override;
- bool HasLineIfEmpty() const override {
- return IsA<HTMLInputElement>(GetNode());
- }
-
LayoutBlock* inner_;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_counter.cc b/chromium/third_party/blink/renderer/core/layout/layout_counter.cc
index d7c8f9d0587..d3a3e1359e0 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_counter.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_counter.cc
@@ -474,23 +474,21 @@ void LayoutCounter::WillBeDestroyed() {
scoped_refptr<StringImpl> LayoutCounter::OriginalText() const {
if (!counter_node_) {
- LayoutObject* before_after_container = Parent();
+ LayoutObject* container = Parent();
while (true) {
- if (!before_after_container)
+ if (!container)
return nullptr;
- if (!before_after_container->IsAnonymous() &&
- !before_after_container->IsPseudoElement())
- return nullptr; // LayoutCounters are restricted to before and after
- // pseudo elements
- PseudoId container_style = before_after_container->StyleRef().StyleType();
+ if (!container->IsAnonymous() && !container->IsPseudoElement())
+ return nullptr; // LayoutCounters are restricted to before, after and
+ // marker pseudo elements
+ PseudoId container_style = container->StyleRef().StyleType();
if ((container_style == kPseudoIdBefore) ||
(container_style == kPseudoIdAfter) ||
(container_style == kPseudoIdMarker))
break;
- before_after_container = before_after_container->Parent();
+ container = container->Parent();
}
- MakeCounterNodeIfNeeded(*before_after_container, counter_.Identifier(),
- true)
+ MakeCounterNodeIfNeeded(*container, counter_.Identifier(), true)
->AddLayoutObject(const_cast<LayoutCounter*>(this));
DCHECK(counter_node_);
}
@@ -522,7 +520,7 @@ void LayoutCounter::Invalidate() {
DCHECK(!counter_node_);
if (DocumentBeingDestroyed())
return;
- SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kCountersChanged);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.cc b/chromium/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.cc
index 92de8406cde..e44c69567e7 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.cc
@@ -141,7 +141,7 @@ int LayoutCustomScrollbarPart::ComputeScrollbarWidth(
int min_width = CalcScrollbarThicknessUsing(kMinSize, style->MinWidth(),
visible_size, theme);
int max_width = w;
- if (!style->MaxWidth().IsMaxSizeNone()) {
+ if (!style->MaxWidth().IsNone()) {
max_width = CalcScrollbarThicknessUsing(kMaxSize, style->MaxWidth(),
visible_size, theme);
}
@@ -158,7 +158,7 @@ int LayoutCustomScrollbarPart::ComputeScrollbarHeight(
int min_height = CalcScrollbarThicknessUsing(kMinSize, style->MinHeight(),
visible_size, theme);
int max_height = h;
- if (!style->MaxHeight().IsMaxSizeNone()) {
+ if (!style->MaxHeight().IsNone()) {
max_height = CalcScrollbarThicknessUsing(kMaxSize, style->MaxHeight(),
visible_size, theme);
}
@@ -211,13 +211,8 @@ void LayoutCustomScrollbarPart::UpdateScrollbarHeight() {
.Round()));
}
-void LayoutCustomScrollbarPart::ComputePreferredLogicalWidths() {
- if (!PreferredLogicalWidthsDirty())
- return;
-
- min_preferred_logical_width_ = max_preferred_logical_width_ = LayoutUnit();
-
- ClearPreferredLogicalWidthsDirty();
+MinMaxSizes LayoutCustomScrollbarPart::PreferredLogicalWidths() const {
+ return MinMaxSizes();
}
void LayoutCustomScrollbarPart::StyleWillChange(
@@ -235,7 +230,7 @@ void LayoutCustomScrollbarPart::StyleDidChange(StyleDifference diff,
SetInline(false);
ClearPositionedState();
SetFloating(false);
- if (old_style && (diff.NeedsFullPaintInvalidation() || diff.NeedsLayout()))
+ if (old_style && (diff.NeedsPaintInvalidation() || diff.NeedsLayout()))
SetNeedsPaintInvalidation();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.h b/chromium/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.h
index c6848666b51..dd1f0caf2cd 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_custom_scrollbar_part.h
@@ -83,7 +83,7 @@ class LayoutCustomScrollbarPart final : public LayoutBlock {
private:
LayoutCustomScrollbarPart(ScrollableArea*, CustomScrollbar*, ScrollbarPart);
- void ComputePreferredLogicalWidths() override;
+ MinMaxSizes PreferredLogicalWidths() const override;
// Have all padding getters return 0. The important point here is to avoid
// resolving percents against the containing block, since scroll bar corners
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc b/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc
index 3dbbe77bdda..8a44c7f8c14 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc
@@ -43,11 +43,7 @@ class FlexBoxIterator {
public:
FlexBoxIterator(LayoutDeprecatedFlexibleBox* parent)
: box_(parent), largest_ordinal_(1) {
- if (box_->StyleRef().BoxOrient() == EBoxOrient::kHorizontal &&
- !box_->StyleRef().IsLeftToRightDirection())
- forward_ = box_->StyleRef().BoxDirection() != EBoxDirection::kNormal;
- else
- forward_ = box_->StyleRef().BoxDirection() == EBoxDirection::kNormal;
+ forward_ = box_->StyleRef().BoxDirection() == EBoxDirection::kNormal;
if (!forward_) {
// No choice, since we're going backwards, we have to find out the highest
// ordinal up front.
@@ -271,10 +267,9 @@ static void ClearTruncation(LayoutBlockFlow* block_flow) {
}
}
-LayoutDeprecatedFlexibleBox::LayoutDeprecatedFlexibleBox(Element& element)
- : LayoutBlock(&element) {
+LayoutDeprecatedFlexibleBox::LayoutDeprecatedFlexibleBox(Element* element)
+ : LayoutBlock(element) {
DCHECK(!ChildrenInline());
- stretching_children_ = false;
if (!IsAnonymous()) {
const KURL& url = GetDocument().Url();
if (url.ProtocolIs("chrome")) {
@@ -305,18 +300,6 @@ static LayoutUnit MarginWidthForChild(LayoutBox* child) {
return margin;
}
-static LayoutUnit WidthForChild(LayoutBox* child) {
- if (child->HasOverrideLogicalWidth())
- return child->OverrideLogicalWidth();
- return child->LogicalWidth();
-}
-
-static LayoutUnit ContentWidthForChild(LayoutBox* child) {
- // TODO(rego): Shouldn't we subtract the scrollbar width too?
- return (WidthForChild(child) - child->BorderAndPaddingLogicalWidth())
- .ClampNegativeToZero();
-}
-
static LayoutUnit HeightForChild(LayoutBox* child) {
if (child->HasOverrideLogicalHeight())
return child->OverrideLogicalHeight();
@@ -339,43 +322,27 @@ void LayoutDeprecatedFlexibleBox::StyleWillChange(
LayoutBlock::StyleWillChange(diff, new_style);
}
-void LayoutDeprecatedFlexibleBox::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
- if (IsVertical()) {
- for (LayoutBox* child = FirstChildBox(); child;
- child = child->NextSiblingBox()) {
- if (child->IsOutOfFlowPositioned())
- continue;
-
- LayoutUnit margin = MarginWidthForChild(child);
- LayoutUnit width = child->MinPreferredLogicalWidth() + margin;
- min_logical_width = std::max(width, min_logical_width);
+MinMaxSizes LayoutDeprecatedFlexibleBox::ComputeIntrinsicLogicalWidths() const {
+ MinMaxSizes sizes;
+ for (LayoutBox* child = FirstChildBox(); child;
+ child = child->NextSiblingBox()) {
+ if (child->IsOutOfFlowPositioned())
+ continue;
- width = child->MaxPreferredLogicalWidth() + margin;
- max_logical_width = std::max(width, max_logical_width);
- }
- } else {
- for (LayoutBox* child = FirstChildBox(); child;
- child = child->NextSiblingBox()) {
- if (child->IsOutOfFlowPositioned())
- continue;
+ MinMaxSizes child_sizes = child->PreferredLogicalWidths();
+ child_sizes += MarginWidthForChild(child);
- LayoutUnit margin = MarginWidthForChild(child);
- min_logical_width += child->MinPreferredLogicalWidth() + margin;
- max_logical_width += child->MaxPreferredLogicalWidth() + margin;
- }
+ sizes.Encompass(child_sizes);
}
- max_logical_width = std::max(min_logical_width, max_logical_width);
-
- LayoutUnit scrollbar_width(ScrollbarLogicalWidth());
- max_logical_width += scrollbar_width;
- min_logical_width += scrollbar_width;
+ sizes.max_size = std::max(sizes.min_size, sizes.max_size);
+ sizes += BorderAndPaddingLogicalWidth() + ScrollbarLogicalWidth();
+ return sizes;
}
void LayoutDeprecatedFlexibleBox::UpdateBlockLayout(bool relayout_children) {
DCHECK(NeedsLayout());
+ DCHECK_EQ(StyleRef().BoxOrient(), EBoxOrient::kVertical);
UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxLayout);
@@ -417,23 +384,13 @@ void LayoutDeprecatedFlexibleBox::UpdateBlockLayout(bool relayout_children) {
TextAutosizer::LayoutScope text_autosizer_layout_scope(this);
- if (previous_size != Size() ||
- (Parent()->StyleRef().IsDeprecatedWebkitBox() &&
- Parent()->StyleRef().BoxOrient() == EBoxOrient::kHorizontal &&
- Parent()->StyleRef().BoxAlign() == EBoxAlignment::kStretch))
+ if (previous_size != Size())
relayout_children = true;
SetHeight(LayoutUnit());
- stretching_children_ = false;
-
- if (IsHorizontal()) {
- UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxLayoutHorizontal);
- LayoutHorizontalBox(relayout_children);
- } else {
- UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxLayoutVertical);
- LayoutVerticalBox(relayout_children);
- }
+ UseCounter::Count(GetDocument(), WebFeature::kWebkitBoxLayoutVertical);
+ LayoutVerticalBox(relayout_children);
LayoutUnit old_client_after_edge = ClientLogicalBottom();
UpdateLogicalHeight();
@@ -480,322 +437,6 @@ static void GatherFlexChildrenInfo(FlexBoxIterator& iterator,
}
}
-void LayoutDeprecatedFlexibleBox::LayoutHorizontalBox(bool relayout_children) {
- LayoutUnit to_add =
- BorderBottom() + PaddingBottom() + HorizontalScrollbarHeight();
- LayoutUnit y_pos = BorderTop() + PaddingTop();
- LayoutUnit x_pos = BorderLeft() + PaddingLeft();
- bool height_specified = false;
- bool paginated = View()->GetLayoutState()->IsPaginated();
- LayoutUnit old_height;
-
- LayoutUnit remaining_space;
-
- FlexBoxIterator iterator(this);
- bool have_flex = false, flexing_children = false;
- GatherFlexChildrenInfo(iterator, GetDocument(), relayout_children, have_flex);
-
- PaintLayerScrollableArea::DelayScrollOffsetClampScope delay_clamp_scope;
-
- // We do 2 passes. The first pass is simply to lay everyone out at
- // their preferred widths. The second pass handles flexing the children.
- do {
- // Reset our height.
- SetHeight(y_pos);
-
- x_pos = BorderLeft() + PaddingLeft();
-
- // Our first pass is done without flexing. We simply lay the children
- // out within the box. We have to do a layout first in order to determine
- // our box's intrinsic height.
- LayoutUnit max_ascent;
- LayoutUnit max_descent;
- for (LayoutBox* child = iterator.First(); child; child = iterator.Next()) {
- if (child->IsOutOfFlowPositioned())
- continue;
-
- SubtreeLayoutScope layout_scope(*child);
- // TODO(jchaffraix): It seems incorrect to check isAtomicInlineLevel in
- // this file.
- // We probably want to check if the element is replaced.
- if (relayout_children || (child->IsAtomicInlineLevel() &&
- (child->StyleRef().Width().IsPercentOrCalc() ||
- child->StyleRef().Height().IsPercentOrCalc())))
- layout_scope.SetChildNeedsLayout(child);
-
- // Compute the child's vertical margins.
- child->ComputeAndSetBlockDirectionMargins(this);
-
- if (!child->NeedsLayout())
- MarkChildForPaginationRelayoutIfNeeded(*child, layout_scope);
-
- // Now do the layout.
- child->LayoutIfNeeded();
-
- // Update our height and overflow height.
- if (StyleRef().BoxAlign() == EBoxAlignment::kBaseline) {
- LayoutUnit ascent(child->FirstLineBoxBaseline());
- if (ascent == -1)
- ascent = child->Size().Height() + child->MarginBottom();
- ascent += child->MarginTop();
- LayoutUnit descent =
- (child->Size().Height() + child->MarginHeight()) - ascent;
-
- // Update our maximum ascent.
- max_ascent = std::max(max_ascent, ascent);
-
- // Update our maximum descent.
- max_descent = std::max(max_descent, descent);
-
- // Now update our height.
- SetHeight(std::max(y_pos + max_ascent + max_descent, Size().Height()));
- } else {
- SetHeight(std::max(Size().Height(), y_pos + child->Size().Height() +
- child->MarginHeight()));
- }
-
- if (paginated)
- UpdateFragmentationInfoForChild(*child);
- }
-
- if (!iterator.First() && HasLineIfEmpty()) {
- SetHeight(Size().Height() +
- LineHeight(true,
- StyleRef().IsHorizontalWritingMode()
- ? kHorizontalLine
- : kVerticalLine,
- kPositionOfInteriorLineBoxes));
- }
-
- SetHeight(Size().Height() + to_add);
-
- old_height = Size().Height();
- UpdateLogicalHeight();
-
- relayout_children = false;
- if (old_height != Size().Height())
- height_specified = true;
-
- // Now that our height is actually known, we can place our boxes.
- stretching_children_ = (StyleRef().BoxAlign() == EBoxAlignment::kStretch);
- for (LayoutBox* child = iterator.First(); child; child = iterator.Next()) {
- if (child->IsOutOfFlowPositioned()) {
- child->ContainingBlock()->InsertPositionedObject(child);
- PaintLayer* child_layer = child->Layer();
- child_layer->SetStaticInlinePosition(x_pos);
- if (child_layer->StaticBlockPosition() != y_pos) {
- child_layer->SetStaticBlockPosition(y_pos);
- if (child->StyleRef().HasStaticBlockPosition(
- StyleRef().IsHorizontalWritingMode()))
- child->SetChildNeedsLayout(kMarkOnlyThis);
- }
- continue;
- }
-
- SubtreeLayoutScope layout_scope(*child);
-
- // We need to see if this child's height will change, since we make block
- // elements fill the height of a containing box by default. We cannot
- // actually *set* the new height here, though. Need to do that from
- // within layout, or we won't be able to detect the change and duly
- // notify any positioned descendants that are affected by it.
- LayoutUnit old_child_height = child->LogicalHeight();
- LogicalExtentComputedValues computed_values;
- child->ComputeLogicalHeight(child->LogicalHeight(), child->LogicalTop(),
- computed_values);
- LayoutUnit new_child_height = computed_values.extent_;
- if (old_child_height != new_child_height)
- layout_scope.SetChildNeedsLayout(child);
-
- if (!child->NeedsLayout())
- MarkChildForPaginationRelayoutIfNeeded(*child, layout_scope);
-
- child->LayoutIfNeeded();
-
- // We can place the child now, using our value of box-align.
- x_pos += child->MarginLeft();
- LayoutUnit child_y = y_pos;
- switch (StyleRef().BoxAlign()) {
- case EBoxAlignment::kCenter:
- child_y += child->MarginTop() +
- ((ContentHeight() -
- (child->Size().Height() + child->MarginHeight())) /
- 2)
- .ClampNegativeToZero();
- break;
- case EBoxAlignment::kBaseline: {
- LayoutUnit ascent(child->FirstLineBoxBaseline());
- if (ascent == -1)
- ascent = child->Size().Height() + child->MarginBottom();
- ascent += child->MarginTop();
- child_y += child->MarginTop() + (max_ascent - ascent);
- break;
- }
- case EBoxAlignment::kEnd:
- child_y +=
- ContentHeight() - child->MarginBottom() - child->Size().Height();
- break;
- default: // BSTART
- child_y += child->MarginTop();
- break;
- }
-
- PlaceChild(child, LayoutPoint(x_pos, child_y));
-
- x_pos += child->Size().Width() + child->MarginRight();
- }
-
- remaining_space = Size().Width() - BorderRight() - PaddingRight() -
- VerticalScrollbarWidth() - x_pos;
-
- stretching_children_ = false;
- if (flexing_children) {
- have_flex = false; // We're done.
- } else if (have_flex) {
- // We have some flexible objects. See if we need to grow/shrink them at
- // all.
- if (!remaining_space)
- break;
-
- // Allocate the remaining space among the flexible objects.
- bool expanding = remaining_space > 0;
- do {
- // Flexing consists of multiple passes, since we have to change
- // ratios every time an object hits its max/min-width For a given
- // pass, we always start off by computing the totalFlex of all
- // objects that can grow/shrink at all, and computing the allowed
- // growth before an object hits its min/max width (and thus forces a
- // totalFlex recomputation).
- LayoutUnit remaining_space_at_beginning = remaining_space;
- float total_flex = 0.0f;
- for (LayoutBox* child = iterator.First(); child;
- child = iterator.Next()) {
- if (AllowedChildFlex(child, expanding))
- total_flex += child->StyleRef().BoxFlex();
- }
- LayoutUnit space_available_this_pass = remaining_space;
- for (LayoutBox* child = iterator.First(); child;
- child = iterator.Next()) {
- LayoutUnit allowed_flex = AllowedChildFlex(child, expanding);
- if (allowed_flex) {
- LayoutUnit projected_flex =
- (allowed_flex == LayoutUnit::Max())
- ? allowed_flex
- : LayoutUnit(allowed_flex *
- (total_flex / child->StyleRef().BoxFlex()));
- space_available_this_pass =
- expanding ? std::min(space_available_this_pass, projected_flex)
- : std::max(space_available_this_pass, projected_flex);
- }
- }
-
- // If we can't grow/shrink anymore, break.
- if (!space_available_this_pass || total_flex == 0.0f)
- break;
-
- // Now distribute the space to objects.
- for (LayoutBox* child = iterator.First();
- child && space_available_this_pass && total_flex;
- child = iterator.Next()) {
- if (AllowedChildFlex(child, expanding)) {
- LayoutUnit space_add =
- LayoutUnit(space_available_this_pass *
- (child->StyleRef().BoxFlex() / total_flex));
- if (space_add) {
- child->SetOverrideLogicalWidth(WidthForChild(child) + space_add);
- flexing_children = true;
- relayout_children = true;
- }
-
- space_available_this_pass -= space_add;
- remaining_space -= space_add;
-
- total_flex -= child->StyleRef().BoxFlex();
- }
- }
- if (remaining_space == remaining_space_at_beginning) {
- // This is not advancing, avoid getting stuck by distributing the
- // remaining pixels.
- LayoutUnit space_add = LayoutUnit(remaining_space > 0 ? 1 : -1);
- for (LayoutBox* child = iterator.First(); child && remaining_space;
- child = iterator.Next()) {
- if (AllowedChildFlex(child, expanding)) {
- child->SetOverrideLogicalWidth(WidthForChild(child) + space_add);
- flexing_children = true;
- relayout_children = true;
- remaining_space -= space_add;
- }
- }
- }
- } while (AbsoluteValue(remaining_space) >= 1);
-
- // We didn't find any children that could grow.
- if (have_flex && !flexing_children)
- have_flex = false;
- }
- } while (have_flex);
-
- if (remaining_space > 0 && ((StyleRef().IsLeftToRightDirection() &&
- StyleRef().BoxPack() != EBoxPack::kStart) ||
- (!StyleRef().IsLeftToRightDirection() &&
- StyleRef().BoxPack() != EBoxPack::kEnd))) {
- // Children must be repositioned.
- LayoutUnit offset;
- if (StyleRef().BoxPack() == EBoxPack::kJustify) {
- // Determine the total number of children.
- int total_children = 0;
- for (LayoutBox* child = iterator.First(); child;
- child = iterator.Next()) {
- if (child->IsOutOfFlowPositioned())
- continue;
- ++total_children;
- }
-
- // Iterate over the children and space them out according to the
- // justification level.
- if (total_children > 1) {
- --total_children;
- bool first_child = true;
- for (LayoutBox* child = iterator.First(); child;
- child = iterator.Next()) {
- if (child->IsOutOfFlowPositioned())
- continue;
-
- if (first_child) {
- first_child = false;
- continue;
- }
-
- offset += remaining_space / total_children;
- remaining_space -= (remaining_space / total_children);
- --total_children;
-
- PlaceChild(child,
- child->Location() + LayoutSize(offset, LayoutUnit()));
- }
- }
- } else {
- if (StyleRef().BoxPack() == EBoxPack::kCenter)
- offset += remaining_space / 2;
- else // END for LTR, START for RTL
- offset += remaining_space;
- for (LayoutBox* child = iterator.First(); child;
- child = iterator.Next()) {
- if (child->IsOutOfFlowPositioned())
- continue;
-
- PlaceChild(child, child->Location() + LayoutSize(offset, LayoutUnit()));
- }
- }
- }
-
- // So that the computeLogicalHeight in layoutBlock() knows to relayout
- // positioned objects because of a height change, we revert our height back
- // to the intrinsic height before returning.
- if (height_specified)
- SetHeight(old_height);
-}
-
void LayoutDeprecatedFlexibleBox::LayoutVerticalBox(bool relayout_children) {
LayoutUnit y_pos = BorderTop() + PaddingTop();
LayoutUnit to_add =
@@ -1021,6 +662,8 @@ void LayoutDeprecatedFlexibleBox::LayoutVerticalBox(bool relayout_children) {
// Children must be repositioned.
LayoutUnit offset;
if (StyleRef().BoxPack() == EBoxPack::kJustify) {
+ UseCounter::Count(GetDocument(),
+ WebFeature::kWebkitBoxPackJustifyDoesSomething);
// Determine the total number of children.
int total_children = 0;
for (LayoutBox* child = iterator.First(); child;
@@ -1054,10 +697,15 @@ void LayoutDeprecatedFlexibleBox::LayoutVerticalBox(bool relayout_children) {
}
}
} else {
- if (StyleRef().BoxPack() == EBoxPack::kCenter)
+ if (StyleRef().BoxPack() == EBoxPack::kCenter) {
+ UseCounter::Count(GetDocument(),
+ WebFeature::kWebkitBoxPackCenterDoesSomething);
offset += remaining_space / 2;
- else // END
+ } else { // END
+ UseCounter::Count(GetDocument(),
+ WebFeature::kWebkitBoxPackEndDoesSomething);
offset += remaining_space;
+ }
for (LayoutBox* child = iterator.First(); child;
child = iterator.Next()) {
if (child->IsOutOfFlowPositioned())
@@ -1248,16 +896,6 @@ LayoutUnit LayoutDeprecatedFlexibleBox::AllowedChildFlex(LayoutBox* child,
return LayoutUnit();
if (expanding) {
- if (IsHorizontal()) {
- // FIXME: For now just handle fixed values.
- LayoutUnit max_width = LayoutUnit::Max();
- LayoutUnit width = ContentWidthForChild(child);
- if (child->StyleRef().MaxWidth().IsFixed())
- max_width = LayoutUnit(child->StyleRef().MaxWidth().Value());
- if (max_width == LayoutUnit::Max())
- return max_width;
- return (max_width - width).ClampNegativeToZero();
- }
// FIXME: For now just handle fixed values.
LayoutUnit max_height = LayoutUnit::Max();
LayoutUnit height = ContentHeightForChild(child);
@@ -1269,18 +907,6 @@ LayoutUnit LayoutDeprecatedFlexibleBox::AllowedChildFlex(LayoutBox* child,
}
// FIXME: For now just handle fixed values.
- if (IsHorizontal()) {
- LayoutUnit min_width = child->MinPreferredLogicalWidth();
- LayoutUnit width = ContentWidthForChild(child);
- const Length& min_width_length = child->StyleRef().MinWidth();
- if (min_width_length.IsFixed())
- min_width = LayoutUnit(min_width_length.Value());
- else if (min_width_length.IsAuto())
- min_width = LayoutUnit();
-
- LayoutUnit allowed_shrinkage = (min_width - width).ClampPositiveToZero();
- return allowed_shrinkage;
- }
const Length& min_height_length = child->StyleRef().MinHeight();
if (min_height_length.IsFixed() || min_height_length.IsAuto()) {
LayoutUnit min_height(min_height_length.Value());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h b/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
index d05ba26dc16..4ee630f91b7 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h
@@ -33,7 +33,7 @@ class FlexBoxIterator;
// eventually be replaced by LayoutFlexibleBox.
class LayoutDeprecatedFlexibleBox final : public LayoutBlock {
public:
- LayoutDeprecatedFlexibleBox(Element&);
+ LayoutDeprecatedFlexibleBox(Element* element);
~LayoutDeprecatedFlexibleBox() override;
const char* GetName() const override { return "LayoutDeprecatedFlexibleBox"; }
@@ -42,38 +42,22 @@ class LayoutDeprecatedFlexibleBox final : public LayoutBlock {
const ComputedStyle& new_style) override;
void UpdateBlockLayout(bool relayout_children) override;
- void LayoutHorizontalBox(bool relayout_children);
void LayoutVerticalBox(bool relayout_children);
bool IsDeprecatedFlexibleBox() const override { return true; }
bool IsFlexibleBoxIncludingDeprecatedAndNG() const override { return true; }
- bool IsStretchingChildren() const { return stretching_children_; }
void PlaceChild(LayoutBox* child, const LayoutPoint& location);
private:
- void ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const override;
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const override;
LayoutUnit AllowedChildFlex(LayoutBox* child, bool expanding);
- bool IsVertical() const {
- return StyleRef().BoxOrient() == EBoxOrient::kVertical;
- }
- bool IsHorizontal() const {
- return StyleRef().BoxOrient() == EBoxOrient::kHorizontal;
- }
-
void ApplyLineClamp(FlexBoxIterator&, bool relayout_children);
void ClearLineClamp();
-
- bool stretching_children_;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutDeprecatedFlexibleBox,
- IsDeprecatedFlexibleBox());
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_DEPRECATED_FLEXIBLE_BOX_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_details_marker.h b/chromium/third_party/blink/renderer/core/layout/layout_details_marker.h
index 087b367b199..a2efcbffdfa 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_details_marker.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_details_marker.h
@@ -41,9 +41,6 @@ class LayoutDetailsMarker final : public LayoutBlockFlow {
LayoutBlockFlow::IsOfType(type);
}
void Paint(const PaintInfo&) const override;
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override {
- return false;
- }
bool IsOpen() const;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.cc b/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.cc
index f768337c124..41b92eaa2eb 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.cc
@@ -24,6 +24,7 @@
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
+#include "third_party/blink/public/common/features.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
#include "third_party/blink/renderer/core/frame/embedded_content_view.h"
@@ -68,8 +69,7 @@ void LayoutEmbeddedContent::WillBeDestroyed() {
LayoutReplaced::WillBeDestroyed();
}
-void LayoutEmbeddedContent::Destroy() {
- WillBeDestroyed();
+void LayoutEmbeddedContent::DeleteThis() {
// We call clearNode here because LayoutEmbeddedContent is ref counted. This
// call to destroy may not actually destroy the layout object. We can keep it
// around because of references from the LocalFrameView class. (The actual
@@ -95,7 +95,7 @@ FrameView* LayoutEmbeddedContent::ChildFrameView() const {
WebPluginContainerImpl* LayoutEmbeddedContent::Plugin() const {
EmbeddedContentView* embedded_content_view = GetEmbeddedContentView();
if (embedded_content_view && embedded_content_view->IsPluginView())
- return ToWebPluginContainerImpl(embedded_content_view);
+ return To<WebPluginContainerImpl>(embedded_content_view);
return nullptr;
}
@@ -128,8 +128,15 @@ bool LayoutEmbeddedContent::RequiresAcceleratedCompositing() const {
if (!element)
return false;
- if (element->ContentFrame() && element->ContentFrame()->IsRemoteFrame())
- return true;
+ if (Frame* content_frame = element->ContentFrame()) {
+ if (content_frame->IsRemoteFrame())
+ return true;
+ if (base::FeatureList::IsEnabled(
+ blink::features::kCompositeCrossOriginIframes) &&
+ content_frame->IsCrossOriginToParentFrame()) {
+ return true;
+ }
+ }
if (Document* content_document = element->contentDocument()) {
auto* layout_view = content_document->GetLayoutView();
@@ -302,7 +309,7 @@ void LayoutEmbeddedContent::InvalidatePaint(
}
CursorDirective LayoutEmbeddedContent::GetCursor(const PhysicalOffset& point,
- Cursor& cursor) const {
+ ui::Cursor& cursor) const {
if (Plugin()) {
// A plugin is responsible for setting the cursor when the pointer is over
// it.
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.h b/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.h
index cde0a2f09aa..ce5d1ef6a97 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_embedded_content.h
@@ -27,6 +27,10 @@
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/layout/layout_replaced.h"
+namespace ui {
+class Cursor;
+}
+
namespace blink {
class EmbeddedContentView;
@@ -75,15 +79,16 @@ class CORE_EXPORT LayoutEmbeddedContent : public LayoutReplaced {
void PaintReplaced(const PaintInfo&,
const PhysicalOffset& paint_offset) const override;
void InvalidatePaint(const PaintInvalidatorContext&) const final;
- CursorDirective GetCursor(const PhysicalOffset&, Cursor&) const final;
+ CursorDirective GetCursor(const PhysicalOffset&, ui::Cursor&) const final;
bool CanBeSelectionLeafInternal() const final { return true; }
private:
+ bool CanHaveAdditionalCompositingReasons() const override { return true; }
CompositingReasons AdditionalCompositingReasons() const override;
void WillBeDestroyed() final;
- void Destroy() final;
+ void DeleteThis() final;
bool NodeAtPointOverEmbeddedContentView(
HitTestResult&,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc b/chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc
index eaf12e75073..7fba1ae5141 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_fieldset.cc
@@ -32,14 +32,14 @@ namespace blink {
LayoutFieldset::LayoutFieldset(Element* element) : LayoutBlockFlow(element) {}
-void LayoutFieldset::ComputePreferredLogicalWidths() {
- LayoutBlockFlow::ComputePreferredLogicalWidths();
+MinMaxSizes LayoutFieldset::PreferredLogicalWidths() const {
+ MinMaxSizes sizes = LayoutBlockFlow::PreferredLogicalWidths();
// Size-contained elements don't consider their contents for preferred sizing.
if (ShouldApplySizeContainment())
- return;
+ return sizes;
if (LayoutBox* legend = FindInFlowLegend()) {
- int legend_min_width = legend->MinPreferredLogicalWidth().ToInt();
+ int legend_min_width = legend->PreferredLogicalWidths().min_size.ToInt();
const Length& legend_margin_left = legend->StyleRef().MarginLeft();
const Length& legend_margin_right = legend->StyleRef().MarginRight();
@@ -50,10 +50,11 @@ void LayoutFieldset::ComputePreferredLogicalWidths() {
if (legend_margin_right.IsFixed())
legend_min_width += legend_margin_right.Value();
- min_preferred_logical_width_ =
- max(min_preferred_logical_width_,
- legend_min_width + BorderAndPaddingWidth());
+ sizes.min_size =
+ max(sizes.min_size, legend_min_width + BorderAndPaddingWidth());
}
+
+ return sizes;
}
LayoutObject* LayoutFieldset::LayoutSpecialExcludedChild(bool relayout_children,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_fieldset.h b/chromium/third_party/blink/renderer/core/layout/layout_fieldset.h
index 16db91bde89..e5edff116ae 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_fieldset.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_fieldset.h
@@ -49,7 +49,7 @@ class LayoutFieldset final : public LayoutBlockFlow {
LayoutObject* LayoutSpecialExcludedChild(bool relayout_children,
SubtreeLayoutScope&) override;
- void ComputePreferredLogicalWidths() override;
+ MinMaxSizes PreferredLogicalWidths() const override;
void PaintBoxDecorationBackground(
const PaintInfo&,
@@ -58,8 +58,6 @@ class LayoutFieldset final : public LayoutBlockFlow {
const PhysicalOffset& paint_offset) const override;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutFieldset, IsFieldset());
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_FIELDSET_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.cc b/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.cc
index 737a0bca9c0..589ba9e2cba 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.cc
@@ -21,47 +21,35 @@
#include "third_party/blink/renderer/core/layout/layout_file_upload_control.h"
#include <math.h>
-#include "third_party/blink/public/strings/grit/blink_strings.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
#include "third_party/blink/renderer/core/fileapi/file_list.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/paint/file_upload_control_painter.h"
#include "third_party/blink/renderer/platform/fonts/font.h"
-#include "third_party/blink/renderer/platform/text/platform_locale.h"
+#include "third_party/blink/renderer/platform/fonts/string_truncator.h"
#include "third_party/blink/renderer/platform/text/text_run.h"
namespace blink {
-const int kDefaultWidthNumChars = 34;
const int kButtonShadowHeight = 2;
-LayoutFileUploadControl::LayoutFileUploadControl(HTMLInputElement* input)
- : LayoutBlockFlow(input),
- can_receive_dropped_files_(input->CanReceiveDroppedFiles()) {}
+LayoutFileUploadControl::LayoutFileUploadControl(Element* input)
+ : LayoutBlockFlow(input) {
+ DCHECK_EQ(To<HTMLInputElement>(input)->type(), input_type_names::kFile);
+}
LayoutFileUploadControl::~LayoutFileUploadControl() = default;
-void LayoutFileUploadControl::UpdateFromElement() {
- auto* input = To<HTMLInputElement>(GetNode());
- DCHECK_EQ(input->type(), input_type_names::kFile);
-
- if (HTMLInputElement* button = UploadButton()) {
- bool new_can_receive_dropped_files_state = input->CanReceiveDroppedFiles();
- if (can_receive_dropped_files_ != new_can_receive_dropped_files_state) {
- can_receive_dropped_files_ = new_can_receive_dropped_files_state;
- button->SetActive(new_can_receive_dropped_files_state);
- }
- }
-
- // This only supports clearing out the files, but that's OK because for
- // security reasons that's the only change the DOM is allowed to make.
- FileList* files = input->files();
- DCHECK(files);
- if (files && files->IsEmpty())
- SetShouldDoFullPaintInvalidation();
+bool LayoutFileUploadControl::IsChildAllowed(LayoutObject* child,
+ const ComputedStyle& style) const {
+ const Node* child_node = child->GetNode();
+ // Reject shadow nodes other than UploadButton.
+ if (child_node && child_node->OwnerShadowHost() == GetNode() &&
+ child_node != UploadButton())
+ return false;
+ return LayoutBlockFlow::IsChildAllowed(child, style);
}
int LayoutFileUploadControl::MaxFilenameWidth() const {
@@ -79,110 +67,27 @@ void LayoutFileUploadControl::PaintObject(
FileUploadControlPainter(*this).PaintObject(paint_info, paint_offset);
}
-void LayoutFileUploadControl::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
- // Figure out how big the filename space needs to be for a given number of
- // characters (using "0" as the nominal character).
- const UChar kCharacter = '0';
- const String character_as_string = String(&kCharacter, 1);
- const Font& font = StyleRef().GetFont();
- float min_default_label_width =
- kDefaultWidthNumChars *
- font.Width(ConstructTextRun(font, character_as_string, StyleRef(),
- TextRun::kAllowTrailingExpansion));
-
- const String label = To<HTMLInputElement>(GetNode())->GetLocale().QueryString(
- IDS_FORM_FILE_NO_FILE_LABEL);
- float default_label_width = font.Width(ConstructTextRun(
- font, label, StyleRef(), TextRun::kAllowTrailingExpansion));
- if (HTMLInputElement* button = UploadButton()) {
- if (LayoutObject* button_layout_object = button->GetLayoutObject())
- default_label_width += button_layout_object->MaxPreferredLogicalWidth() +
- kAfterButtonSpacing;
- }
- max_logical_width =
- LayoutUnit(ceilf(std::max(min_default_label_width, default_label_width)));
-
- if (!StyleRef().Width().IsPercentOrCalc())
- min_logical_width = max_logical_width;
-}
-
-void LayoutFileUploadControl::ComputePreferredLogicalWidths() {
- DCHECK(PreferredLogicalWidthsDirty());
-
- min_preferred_logical_width_ = LayoutUnit();
- max_preferred_logical_width_ = LayoutUnit();
- const ComputedStyle& style_to_use = StyleRef();
-
- if (style_to_use.Width().IsFixed() && style_to_use.Width().Value() > 0)
- min_preferred_logical_width_ = max_preferred_logical_width_ =
- AdjustContentBoxLogicalWidthForBoxSizing(
- LayoutUnit(style_to_use.Width().Value()));
- else
- ComputeIntrinsicLogicalWidths(min_preferred_logical_width_,
- max_preferred_logical_width_);
-
- if (style_to_use.MinWidth().IsFixed() &&
- style_to_use.MinWidth().Value() > 0) {
- max_preferred_logical_width_ =
- std::max(max_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- LayoutUnit(style_to_use.MinWidth().Value())));
- min_preferred_logical_width_ =
- std::max(min_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- LayoutUnit(style_to_use.MinWidth().Value())));
- }
-
- if (style_to_use.MaxWidth().IsFixed()) {
- max_preferred_logical_width_ =
- std::min(max_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- LayoutUnit(style_to_use.MaxWidth().Value())));
- min_preferred_logical_width_ =
- std::min(min_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- LayoutUnit(style_to_use.MaxWidth().Value())));
- }
-
- int to_add = BorderAndPaddingWidth().ToInt();
- min_preferred_logical_width_ += to_add;
- max_preferred_logical_width_ += to_add;
-
- ClearPreferredLogicalWidthsDirty();
-}
-
-PositionWithAffinity LayoutFileUploadControl::PositionForPoint(
- const PhysicalOffset&) const {
- return PositionWithAffinity();
-}
-
HTMLInputElement* LayoutFileUploadControl::UploadButton() const {
- // FIXME: This should be on HTMLInputElement as an API like
- // innerButtonElement().
- auto* input = To<HTMLInputElement>(GetNode());
- return DynamicTo<HTMLInputElement>(
- input->UserAgentShadowRoot()->firstChild());
-}
-
-String LayoutFileUploadControl::ButtonValue() {
- if (HTMLInputElement* button = UploadButton())
- return button->value();
-
- return String();
+ return To<HTMLInputElement>(GetNode())->UploadButton();
}
String LayoutFileUploadControl::FileTextValue() const {
+ int width = MaxFilenameWidth();
+ if (width <= 0)
+ return String();
auto* input = To<HTMLInputElement>(GetNode());
DCHECK(input->files());
- return LayoutTheme::GetTheme().FileListNameForWidth(
- input->GetLocale(), input->files(), StyleRef().GetFont(),
- MaxFilenameWidth());
+ String text = input->FileStatusText();
+ if (input->files()->length() >= 2)
+ return StringTruncator::RightTruncate(text, width, StyleRef().GetFont());
+ return StringTruncator::CenterTruncate(text, width, StyleRef().GetFont());
}
-PhysicalRect LayoutFileUploadControl::ControlClipRect(
- const PhysicalOffset& additional_offset) const {
+// Override to allow effective clip rect to be bigger than the padding box
+// because of kButtonShadowHeight.
+PhysicalRect LayoutFileUploadControl::OverflowClipRect(
+ const PhysicalOffset& additional_offset,
+ OverlayScrollbarClipBehavior) const {
PhysicalRect rect(additional_offset, Size());
rect.Expand(BorderInsets());
rect.offset.top -= LayoutUnit(kButtonShadowHeight);
@@ -190,12 +95,4 @@ PhysicalRect LayoutFileUploadControl::ControlClipRect(
return rect;
}
-// Override to allow effective ControlClipRect to be bigger than the padding
-// box because of kButtonShadowHeight.
-PhysicalRect LayoutFileUploadControl::OverflowClipRect(
- const PhysicalOffset& additional_offset,
- OverlayScrollbarClipBehavior) const {
- return ControlClipRect(additional_offset);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.h b/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.h
index 83aceca59f4..372714a41ef 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_file_upload_control.h
@@ -27,8 +27,6 @@
namespace blink {
-class HTMLInputElement;
-
// Each LayoutFileUploadControl contains a LayoutButton (for opening the file
// chooser), and sufficient space to draw a file icon and filename. The
// LayoutButton has a shadow node associated with it to receive click/hover
@@ -36,7 +34,7 @@ class HTMLInputElement;
class CORE_EXPORT LayoutFileUploadControl final : public LayoutBlockFlow {
public:
- LayoutFileUploadControl(HTMLInputElement*);
+ explicit LayoutFileUploadControl(Element*);
~LayoutFileUploadControl() override;
bool IsOfType(LayoutObjectType type) const override {
@@ -44,39 +42,24 @@ class CORE_EXPORT LayoutFileUploadControl final : public LayoutBlockFlow {
LayoutBlockFlow::IsOfType(type);
}
- String ButtonValue();
String FileTextValue() const;
HTMLInputElement* UploadButton() const;
- int UploadButtonWidth();
- bool HasControlClip() const override { return true; }
- PhysicalRect ControlClipRect(const PhysicalOffset&) const override;
PhysicalRect OverflowClipRect(const PhysicalOffset&,
OverlayScrollbarClipBehavior) const override;
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override {
- return false;
- }
-
static const int kAfterButtonSpacing = 4;
const char* GetName() const override { return "LayoutFileUploadControl"; }
private:
- void UpdateFromElement() override;
- void ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const override;
- void ComputePreferredLogicalWidths() override;
+ bool IsChildAllowed(LayoutObject* child,
+ const ComputedStyle& style) const override;
void PaintObject(const PaintInfo&,
const PhysicalOffset& paint_offset) const override;
int MaxFilenameWidth() const;
-
- PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
-
- bool can_receive_dropped_files_;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutFileUploadControl, IsFileUploadControl());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc
index 97ebd2901a5..0e51f4ec744 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc
@@ -33,10 +33,12 @@
#include <limits>
#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
+#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
#include "third_party/blink/renderer/core/layout/flexible_box_algorithm.h"
#include "third_party/blink/renderer/core/layout/layout_state.h"
+#include "third_party/blink/renderer/core/layout/layout_video.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
-#include "third_party/blink/renderer/core/layout/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/text_autosizer.h"
@@ -52,7 +54,7 @@
namespace blink {
static bool HasAspectRatio(const LayoutBox& child) {
- return child.IsImage() || child.IsCanvas() || child.IsVideo();
+ return child.IsImage() || child.IsCanvas() || IsA<LayoutVideo>(child);
}
LayoutFlexibleBox::LayoutFlexibleBox(Element* element)
@@ -66,19 +68,37 @@ LayoutFlexibleBox::LayoutFlexibleBox(Element* element)
LayoutFlexibleBox::~LayoutFlexibleBox() = default;
-void LayoutFlexibleBox::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
- LayoutUnit scrollbar_width(ScrollbarLogicalWidth());
+bool LayoutFlexibleBox::IsChildAllowed(LayoutObject* object,
+ const ComputedStyle& style) const {
+ const auto* select = DynamicTo<HTMLSelectElement>(GetNode());
+ if (UNLIKELY(select && select->UsesMenuList())) {
+ // For a size=1 <select>, we only render the active option label through the
+ // InnerElement. We do not allow adding layout objects for options and
+ // optgroups.
+ return object->GetNode() == &select->InnerElement();
+ }
+ return LayoutBlock::IsChildAllowed(object, style);
+}
+
+MinMaxSizes LayoutFlexibleBox::ComputeIntrinsicLogicalWidths() const {
+ MinMaxSizes sizes;
+ sizes += BorderAndPaddingLogicalWidth() + ScrollbarLogicalWidth();
+
if (HasOverrideIntrinsicContentLogicalWidth()) {
- max_logical_width = min_logical_width =
- OverrideIntrinsicContentLogicalWidth() + scrollbar_width;
- return;
+ sizes += OverrideIntrinsicContentLogicalWidth();
+ return sizes;
}
- if (ShouldApplySizeContainment()) {
- max_logical_width = min_logical_width = scrollbar_width;
- return;
+ LayoutUnit default_inline_size = DefaultIntrinsicContentInlineSize();
+ if (default_inline_size != kIndefiniteSize) {
+ sizes.max_size += default_inline_size;
+ if (!StyleRef().LogicalWidth().IsPercentOrCalc())
+ sizes.min_size = sizes.max_size;
+ return sizes;
}
+ if (ShouldApplySizeContainment())
+ return sizes;
+
+ MinMaxSizes child_sizes;
// FIXME: We're ignoring flex-basis here and we shouldn't. We can't start
// honoring it though until the flex shorthand stops setting it to 0. See
@@ -95,7 +115,7 @@ void LayoutFlexibleBox::ComputeIntrinsicLogicalWidths(
LayoutUnit min_preferred_logical_width;
LayoutUnit max_preferred_logical_width;
if (child->NeedsPreferredWidthsRecalculation())
- child->SetPreferredLogicalWidthsDirty();
+ child->SetIntrinsicLogicalWidthsDirty();
ComputeChildPreferredLogicalWidths(*child, min_preferred_logical_width,
max_preferred_logical_width);
DCHECK_GE(min_preferred_logical_width, LayoutUnit());
@@ -103,35 +123,35 @@ void LayoutFlexibleBox::ComputeIntrinsicLogicalWidths(
min_preferred_logical_width += margin;
max_preferred_logical_width += margin;
if (!IsColumnFlow()) {
- max_logical_width += max_preferred_logical_width;
+ child_sizes.max_size += max_preferred_logical_width;
if (IsMultiline()) {
// For multiline, the min preferred width is if you put a break between
// each item.
- min_logical_width =
- std::max(min_logical_width, min_preferred_logical_width);
+ child_sizes.min_size =
+ std::max(child_sizes.min_size, min_preferred_logical_width);
} else {
- min_logical_width += min_preferred_logical_width;
+ child_sizes.min_size += min_preferred_logical_width;
}
} else {
- min_logical_width =
- std::max(min_preferred_logical_width, min_logical_width);
- max_logical_width =
- std::max(max_preferred_logical_width, max_logical_width);
+ child_sizes.min_size =
+ std::max(min_preferred_logical_width, child_sizes.min_size);
+ child_sizes.max_size =
+ std::max(max_preferred_logical_width, child_sizes.max_size);
}
previous_max_content_flex_fraction = CountIntrinsicSizeForAlgorithmChange(
max_preferred_logical_width, child, previous_max_content_flex_fraction);
}
- max_logical_width = std::max(min_logical_width, max_logical_width);
+ child_sizes.max_size = std::max(child_sizes.min_size, child_sizes.max_size);
// Due to negative margins, it is possible that we calculated a negative
// intrinsic width. Make sure that we never return a negative width.
- min_logical_width = std::max(LayoutUnit(), min_logical_width);
- max_logical_width = std::max(LayoutUnit(), max_logical_width);
+ child_sizes.min_size = std::max(LayoutUnit(), child_sizes.min_size);
+ child_sizes.max_size = std::max(LayoutUnit(), child_sizes.max_size);
- max_logical_width += scrollbar_width;
- min_logical_width += scrollbar_width;
+ sizes += child_sizes;
+ return sizes;
}
float LayoutFlexibleBox::CountIntrinsicSizeForAlgorithmChange(
@@ -622,9 +642,9 @@ LayoutUnit LayoutFlexibleBox::ComputeMainAxisExtentForChild(
// that here. (Compare code in LayoutBlock::computePreferredLogicalWidths)
if (child.StyleRef().LogicalWidth().IsAuto() && !HasAspectRatio(child)) {
if (size.IsMinContent())
- return child.MinPreferredLogicalWidth() - border_and_padding;
+ return child.PreferredLogicalWidths().min_size - border_and_padding;
if (size.IsMaxContent())
- return child.MaxPreferredLogicalWidth() - border_and_padding;
+ return child.PreferredLogicalWidths().max_size - border_and_padding;
}
return child.ComputeLogicalWidthUsing(size_type, size, ContentLogicalWidth(),
this) -
@@ -808,7 +828,7 @@ void LayoutFlexibleBox::CacheChildMainSize(const LayoutBox& child) {
DisplayLockLifecycleTarget::kChildren));
LayoutUnit main_size;
if (MainAxisIsInlineAxis(child)) {
- main_size = child.MaxPreferredLogicalWidth();
+ main_size = child.PreferredLogicalWidths().max_size;
} else {
if (FlexBasisForChild(child).IsPercentOrCalc() &&
!MainAxisLengthIsDefinite(child, FlexBasisForChild(child))) {
@@ -861,7 +881,7 @@ LayoutUnit LayoutFlexibleBox::ComputeInnerFlexBaseSizeForChild(
LayoutBox& child,
LayoutUnit main_axis_border_and_padding,
ChildLayoutType child_layout_type) {
- if (child.IsImage() || child.IsVideo() || child.IsCanvas())
+ if (child.IsImage() || IsA<LayoutVideo>(child) || child.IsCanvas())
UseCounter::Count(GetDocument(), WebFeature::kAspectRatioFlexItem);
Length flex_basis = FlexBasisForChild(child);
@@ -895,7 +915,7 @@ LayoutUnit LayoutFlexibleBox::ComputeInnerFlexBaseSizeForChild(
if (MainAxisIsInlineAxis(child)) {
// We don't need to add ScrollbarLogicalWidth here because the preferred
// width includes the scrollbar, even for overflow: auto.
- main_axis_extent = child.MaxPreferredLogicalWidth();
+ main_axis_extent = child.PreferredLogicalWidths().max_size;
} else {
// The needed value here is the logical height. This value does not include
// the border/scrollbar/padding size, so we have to add the scrollbar.
@@ -1019,28 +1039,20 @@ void LayoutFlexibleBox::PrepareOrderIteratorAndMargins() {
continue;
// Before running the flex algorithm, 'auto' has a margin of 0.
- // Also, if we're not auto sizing, we don't do a layout that computes the
- // start/end margins.
- if (IsHorizontalFlow()) {
- child->SetMarginLeft(
- ComputeChildMarginValue(child->StyleRef().MarginLeft()));
- child->SetMarginRight(
- ComputeChildMarginValue(child->StyleRef().MarginRight()));
- } else {
- child->SetMarginTop(
- ComputeChildMarginValue(child->StyleRef().MarginTop()));
- child->SetMarginBottom(
- ComputeChildMarginValue(child->StyleRef().MarginBottom()));
- }
+ const ComputedStyle& style = child->StyleRef();
+ child->SetMarginTop(ComputeChildMarginValue(style.MarginTop()));
+ child->SetMarginRight(ComputeChildMarginValue(style.MarginRight()));
+ child->SetMarginBottom(ComputeChildMarginValue(style.MarginBottom()));
+ child->SetMarginLeft(ComputeChildMarginValue(style.MarginLeft()));
}
}
DISABLE_CFI_PERF
-MinMaxSize LayoutFlexibleBox::ComputeMinAndMaxSizesForChild(
+MinMaxSizes LayoutFlexibleBox::ComputeMinAndMaxSizesForChild(
const FlexLayoutAlgorithm& algorithm,
const LayoutBox& child,
LayoutUnit border_and_padding) const {
- MinMaxSize sizes{LayoutUnit(), LayoutUnit::Max()};
+ MinMaxSizes sizes{LayoutUnit(), LayoutUnit::Max()};
const Length& max = IsHorizontalFlow() ? child.StyleRef().MaxWidth()
: child.StyleRef().MaxHeight();
@@ -1204,21 +1216,25 @@ void LayoutFlexibleBox::ConstructAndAppendFlexItem(
}
}
- LayoutUnit border_and_padding = IsHorizontalFlow()
- ? child.BorderAndPaddingWidth()
- : child.BorderAndPaddingHeight();
+ LayoutUnit main_axis_border_padding = IsHorizontalFlow()
+ ? child.BorderAndPaddingWidth()
+ : child.BorderAndPaddingHeight();
+ LayoutUnit cross_axis_border_padding = IsHorizontalFlow()
+ ? child.BorderAndPaddingHeight()
+ : child.BorderAndPaddingWidth();
- LayoutUnit child_inner_flex_base_size =
- ComputeInnerFlexBaseSizeForChild(child, border_and_padding, layout_type);
+ LayoutUnit child_inner_flex_base_size = ComputeInnerFlexBaseSizeForChild(
+ child, main_axis_border_padding, layout_type);
- MinMaxSize sizes =
- ComputeMinAndMaxSizesForChild(*algorithm, child, border_and_padding);
+ MinMaxSizes sizes = ComputeMinAndMaxSizesForChild(*algorithm, child,
+ main_axis_border_padding);
- LayoutUnit margin =
- IsHorizontalFlow() ? child.MarginWidth() : child.MarginHeight();
- algorithm->emplace_back(&child, child_inner_flex_base_size, sizes,
- /* cross axis min max sizes */ base::nullopt,
- border_and_padding, margin);
+ NGPhysicalBoxStrut physical_margins(child.MarginTop(), child.MarginRight(),
+ child.MarginBottom(), child.MarginLeft());
+ algorithm->emplace_back(
+ &child, child.StyleRef(), child_inner_flex_base_size, sizes,
+ /* min_max_cross_sizes */ base::nullopt, main_axis_border_padding,
+ cross_axis_border_padding, physical_margins);
}
void LayoutFlexibleBox::SetOverrideMainAxisContentSizeForChild(FlexItem& item) {
@@ -1455,6 +1471,7 @@ void LayoutFlexibleBox::ApplyLineItemsPosition(FlexLine* current_line) {
const FlexItem& flex_item = current_line->line_items[i];
LayoutBox* child = flex_item.box;
SetFlowAwareLocationForChild(*child, flex_item.desired_location);
+ child->SetMargin(flex_item.physical_margins);
if (is_paginated)
UpdateFragmentationInfoForChild(*child);
@@ -1558,6 +1575,7 @@ void LayoutFlexibleBox::AlignChildren(FlexLayoutAlgorithm& algorithm) {
flex_item.needs_relayout_for_stretch = false;
}
ResetAlignmentForChild(*flex_item.box, flex_item.desired_location.Y());
+ flex_item.box->SetMargin(flex_item.physical_margins);
}
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h
index 903f746a233..3b3d34ea1ca 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h
@@ -41,7 +41,7 @@ class FlexItem;
class FlexItemVectorView;
class FlexLayoutAlgorithm;
class FlexLine;
-struct MinMaxSize;
+struct MinMaxSizes;
class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
public:
@@ -55,6 +55,8 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
bool IsFlexibleBoxIncludingDeprecatedAndNG() const final { return true; }
void UpdateBlockLayout(bool relayout_children) final;
+ bool IsChildAllowed(LayoutObject* object,
+ const ComputedStyle& style) const override;
LayoutUnit BaselinePosition(
FontBaseline,
bool first_line,
@@ -99,9 +101,7 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
LayoutUnit CrossAxisContentExtent() const;
protected:
- void ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const override;
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const override;
bool HitTestChildren(HitTestResult&,
const HitTestLocation&,
@@ -177,9 +177,10 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
LayoutUnit ComputeChildMarginValue(const Length& margin);
void PrepareOrderIteratorAndMargins();
- MinMaxSize ComputeMinAndMaxSizesForChild(const FlexLayoutAlgorithm& algorithm,
- const LayoutBox& child,
- LayoutUnit border_and_padding) const;
+ MinMaxSizes ComputeMinAndMaxSizesForChild(
+ const FlexLayoutAlgorithm& algorithm,
+ const LayoutBox& child,
+ LayoutUnit border_and_padding) const;
LayoutUnit AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
const LayoutBox& child,
LayoutUnit child_size) const;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box_test.cc
index 781b9c7e0fb..07853d0ae57 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_flexible_box_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_flexible_box_test.cc
@@ -496,11 +496,12 @@ TEST_P(LayoutFlexibleBoxTest, ResizedFlexChildRequiresVisualOverflowRecalc) {
auto* child1_element = GetElementById("child1");
auto* child2_element = GetElementById("child2");
child2_element->setAttribute(html_names::kStyleAttr, "height: 100px;");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
auto* child1_box = ToLayoutBox(child1_element->GetLayoutObject());
ASSERT_TRUE(child1_box->HasSelfPaintingLayer());
- EXPECT_TRUE(child1_box->Layer()->NeedsVisualOverflowRecalcForTesting());
+ EXPECT_TRUE(child1_box->Layer()->NeedsVisualOverflowRecalc());
UpdateAllLifecyclePhasesForTest();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_flow_thread.h b/chromium/third_party/blink/renderer/core/layout/layout_flow_thread.h
index 51130666c56..d43f6eb612d 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_flow_thread.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_flow_thread.h
@@ -105,6 +105,8 @@ class CORE_EXPORT LayoutFlowThread : public LayoutBlockFlow {
// can easily avoid drawing the children directly.
PaintLayerType LayerTypeRequired() const final { return kNormalPaintLayer; }
+ bool NeedsPreferredWidthsRecalculation() const final { return true; }
+
virtual void FlowThreadDescendantWasInserted(LayoutObject*) {}
virtual void FlowThreadDescendantWillBeRemoved(LayoutObject*) {}
virtual void FlowThreadDescendantStyleWillChange(
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc b/chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc
index 8fe99fd5403..fc00cf0cf40 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_frame_set.cc
@@ -32,7 +32,7 @@
#include "third_party/blink/renderer/core/layout/layout_frame.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/paint/frame_set_painter.h"
-#include "third_party/blink/renderer/platform/cursor.h"
+#include "third_party/blink/renderer/platform/cursors.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
namespace blink {
@@ -65,12 +65,6 @@ void LayoutFrameSet::Paint(const PaintInfo& paint_info) const {
FrameSetPainter(*this).Paint(paint_info);
}
-void LayoutFrameSet::ComputePreferredLogicalWidths() {
- min_preferred_logical_width_ = LayoutUnit();
- max_preferred_logical_width_ = LayoutUnit();
- ClearPreferredLogicalWidthsDirty();
-}
-
void LayoutFrameSet::GridAxis::Resize(int size) {
sizes_.resize(size);
deltas_.resize(size);
@@ -577,7 +571,7 @@ bool LayoutFrameSet::IsChildAllowed(LayoutObject* child,
}
CursorDirective LayoutFrameSet::GetCursor(const PhysicalOffset& point,
- Cursor& cursor) const {
+ ui::Cursor& cursor) const {
IntPoint rounded_point = RoundedIntPoint(point);
if (CanResizeRow(rounded_point)) {
cursor = RowResizeCursor();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_frame_set.h b/chromium/third_party/blink/renderer/core/layout/layout_frame_set.h
index 3d193caad5c..6c9aae4e7c9 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_frame_set.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_frame_set.h
@@ -132,9 +132,15 @@ class LayoutFrameSet final : public LayoutBox {
void UpdateLayout() override;
void Paint(const PaintInfo&) const override;
- void ComputePreferredLogicalWidths() override;
+
+ MinMaxSizes PreferredLogicalWidths() const override { return MinMaxSizes(); }
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const final {
+ NOTREACHED();
+ return MinMaxSizes();
+ }
+
bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override;
- CursorDirective GetCursor(const PhysicalOffset&, Cursor&) const override;
+ CursorDirective GetCursor(const PhysicalOffset&, ui::Cursor&) const override;
void SetIsResizing(bool);
@@ -149,10 +155,6 @@ class LayoutFrameSet final : public LayoutBox {
void StartResizing(GridAxis&, int position);
void ContinueResizing(GridAxis&, int position);
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override {
- return false;
- }
-
LayoutObjectChildList children_;
GridAxis rows_;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_geometry_map.cc b/chromium/third_party/blink/renderer/core/layout/layout_geometry_map.cc
index 8a933f61e59..5333c86d923 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_geometry_map.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_geometry_map.cc
@@ -28,6 +28,7 @@
#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#define LAYOUT_GEOMETRY_MAP_LOGGING 0
@@ -105,7 +106,7 @@ void LayoutGeometryMap::MapToAncestor(
}
}
- if (in_fixed && current_step.layout_object_->IsLayoutView()) {
+ if (in_fixed && IsA<LayoutView>(current_step.layout_object_)) {
transform_state.Move(current_step.offset_for_fixed_position_);
in_fixed = false;
}
@@ -119,7 +120,7 @@ void LayoutGeometryMap::MapToAncestor(
const LayoutGeometryMapStep& current_step = mapping_[i];
if (current_step.flags_ & (kContainsFixedPosition | kIsFixedPosition))
break;
- if (current_step.layout_object_->IsLayoutView()) {
+ if (IsA<LayoutView>(current_step.layout_object_)) {
transform_state.Move(current_step.offset_for_fixed_position_);
break;
}
@@ -282,7 +283,7 @@ void LayoutGeometryMap::PushMappingsToAncestor(
// The LayoutView must be pushed first.
if (!mapping_.size()) {
- DCHECK(ancestor_layer->GetLayoutObject().IsLayoutView());
+ DCHECK(IsA<LayoutView>(ancestor_layer->GetLayoutObject()));
PushMappingsToAncestor(&ancestor_layer->GetLayoutObject(), nullptr);
}
@@ -311,9 +312,9 @@ void LayoutGeometryMap::Push(const LayoutObject* layout_object,
#endif
DCHECK_NE(insertion_position_, kNotFound);
- DCHECK(!layout_object->IsLayoutView() || !insertion_position_ ||
+ DCHECK(!IsA<LayoutView>(layout_object) || !insertion_position_ ||
map_coordinates_flags_ & kTraverseDocumentBoundaries);
- DCHECK(offset_for_fixed_position.IsZero() || layout_object->IsLayoutView());
+ DCHECK(offset_for_fixed_position.IsZero() || IsA<LayoutView>(layout_object));
mapping_.insert(insertion_position_,
LayoutGeometryMapStep(layout_object, flags));
@@ -330,9 +331,9 @@ void LayoutGeometryMap::Push(const LayoutObject* layout_object,
GeometryInfoFlags flags,
PhysicalOffset offset_for_fixed_position) {
DCHECK_NE(insertion_position_, kNotFound);
- DCHECK(!layout_object->IsLayoutView() || !insertion_position_ ||
+ DCHECK(!IsA<LayoutView>(layout_object) || !insertion_position_ ||
map_coordinates_flags_ & kTraverseDocumentBoundaries);
- DCHECK(offset_for_fixed_position.IsZero() || layout_object->IsLayoutView());
+ DCHECK(offset_for_fixed_position.IsZero() || IsA<LayoutView>(layout_object));
mapping_.insert(insertion_position_,
LayoutGeometryMapStep(layout_object, flags));
@@ -411,7 +412,7 @@ void LayoutGeometryMap::StepRemoved(const LayoutGeometryMapStep& step) {
#if DCHECK_IS_ON()
bool LayoutGeometryMap::IsTopmostLayoutView(
const LayoutObject* layout_object) const {
- if (!layout_object->IsLayoutView())
+ if (!IsA<LayoutView>(layout_object))
return false;
// If we're not working with multiple LayoutViews, then any view is considered
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
index e04efaedda7..381b7eb16ad 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc
@@ -144,7 +144,7 @@ class LayoutGeometryMapTest : public testing::Test {
void UpdateAllLifecyclePhases(WebView* web_view) {
web_view->MainFrameWidget()->UpdateAllLifecyclePhases(
- WebWidget::LifecycleUpdateReason::kTest);
+ DocumentUpdateReason::kTest);
}
const std::string base_url_;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_grid.cc b/chromium/third_party/blink/renderer/core/layout/layout_grid.cc
index 0d9e5a5dc20..1b03b70feb3 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_grid.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_grid.cc
@@ -194,7 +194,12 @@ bool LayoutGrid::ExplicitGridDidResize(const ComputedStyle& old_style) const {
bool LayoutGrid::NamedGridLinesDefinitionDidChange(
const ComputedStyle& old_style) const {
return old_style.NamedGridRowLines() != StyleRef().NamedGridRowLines() ||
- old_style.NamedGridColumnLines() != StyleRef().NamedGridColumnLines();
+ old_style.NamedGridColumnLines() !=
+ StyleRef().NamedGridColumnLines() ||
+ old_style.ImplicitNamedGridRowLines() !=
+ StyleRef().ImplicitNamedGridRowLines() ||
+ old_style.ImplicitNamedGridColumnLines() !=
+ StyleRef().ImplicitNamedGridColumnLines();
}
void LayoutGrid::ComputeTrackSizesForDefiniteSize(
@@ -246,11 +251,8 @@ void LayoutGrid::RepeatTracksSizingIfNeeded(
void LayoutGrid::UpdateBlockLayout(bool relayout_children) {
DCHECK(NeedsLayout());
- // We cannot perform a simplifiedLayout() on a dirty grid that
- // has positioned items to be laid out.
- if (!relayout_children &&
- (!grid_->NeedsItemsPlacement() || !PosChildNeedsLayout()) &&
- SimplifiedLayout())
+ // We cannot perform a |SimplifiedLayout()| with a dirty grid.
+ if (!relayout_children && !grid_->NeedsItemsPlacement() && SimplifiedLayout())
return;
SubtreeLayoutScope layout_scope(*this);
@@ -502,17 +504,13 @@ LayoutUnit LayoutGrid::GuttersSize(
return gap_accumulator;
}
-void LayoutGrid::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
- LayoutUnit scrollbar_width = LayoutUnit(ScrollbarLogicalWidth());
- min_logical_width = scrollbar_width;
- max_logical_width = scrollbar_width;
+MinMaxSizes LayoutGrid::ComputeIntrinsicLogicalWidths() const {
+ MinMaxSizes sizes;
+ sizes += BorderAndPaddingLogicalWidth() + ScrollbarLogicalWidth();
if (HasOverrideIntrinsicContentLogicalWidth()) {
- min_logical_width += OverrideIntrinsicContentLogicalWidth();
- max_logical_width = min_logical_width;
- return;
+ sizes += OverrideIntrinsicContentLogicalWidth();
+ return sizes;
}
std::unique_ptr<Grid> grid = Grid::Create(this);
@@ -538,8 +536,9 @@ void LayoutGrid::ComputeIntrinsicLogicalWidths(
LayoutUnit total_gutters_size = GuttersSize(
algorithm.GetGrid(), kForColumns, 0, number_of_tracks, base::nullopt);
- min_logical_width += algorithm.MinContentSize() + total_gutters_size;
- max_logical_width += algorithm.MaxContentSize() + total_gutters_size;
+ sizes.min_size += algorithm.MinContentSize() + total_gutters_size;
+ sizes.max_size += algorithm.MaxContentSize() + total_gutters_size;
+ return sizes;
}
void LayoutGrid::ComputeTrackSizesForIndefiniteSize(
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_grid.h b/chromium/third_party/blink/renderer/core/layout/layout_grid.h
index abfcb38ae67..9b9bb6b31d7 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_grid.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_grid.h
@@ -128,9 +128,7 @@ class LayoutGrid final : public LayoutBlock {
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectLayoutGrid || LayoutBlock::IsOfType(type);
}
- void ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const override;
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const override;
void AddChild(LayoutObject* new_child,
LayoutObject* before_child = nullptr) override;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.cc b/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.cc
index 8f8c5d015d4..1023bca17ae 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.cc
@@ -61,23 +61,8 @@ void LayoutHTMLCanvas::CanvasSizeChanged() {
if (!Parent())
return;
- if (!PreferredLogicalWidthsDirty())
- SetPreferredLogicalWidthsDirty();
-
- LayoutSize old_size = Size();
- UpdateLogicalWidth();
- UpdateLogicalHeight();
- if (old_size == Size() && !HasOverrideLogicalWidth() &&
- !HasOverrideLogicalHeight()) {
- // If we have an override size, then we're probably a flex item, and the
- // check above is insufficient because updateLogical{Width,Height} just
- // used the override size. We actually have to mark ourselves as needing
- // layout so the flex algorithm can run and compute our size correctly.
- return;
- }
-
- if (!SelfNeedsLayout())
- SetNeedsLayout(layout_invalidation_reason::kSizeChanged);
+ SetIntrinsicLogicalWidthsDirty();
+ SetNeedsLayout(layout_invalidation_reason::kSizeChanged);
}
void LayoutHTMLCanvas::InvalidatePaint(
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h b/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h
index 55c979f7e9d..d1b8612e2c7 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_html_canvas.h
@@ -56,6 +56,7 @@ class CORE_EXPORT LayoutHTMLCanvas final : public LayoutReplaced {
const PhysicalOffset& paint_offset) const override;
void IntrinsicSizeChanged() override { CanvasSizeChanged(); }
+ bool CanHaveAdditionalCompositingReasons() const override { return true; }
CompositingReasons AdditionalCompositingReasons() const override;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_iframe.h b/chromium/third_party/blink/renderer/core/layout/layout_iframe.h
index eab361c0b9a..5de2e13470c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_iframe.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_iframe.h
@@ -50,8 +50,6 @@ class LayoutIFrame final : public LayoutEmbeddedContent {
PaintLayerType LayerTypeRequired() const override;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutIFrame, IsLayoutIFrame());
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_IFRAME_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image.cc b/chromium/third_party/blink/renderer/core/layout/layout_image.cc
index 571e7c8926a..6f2a3ae49ac 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image.cc
@@ -35,10 +35,12 @@
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/html/html_area_element.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
+#include "third_party/blink/renderer/core/html/media/html_video_element.h"
#include "third_party/blink/renderer/core/html/media/media_element_parser_helpers.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
+#include "third_party/blink/renderer/core/layout/layout_video.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
#include "third_party/blink/renderer/core/paint/image_element_timing.h"
@@ -156,6 +158,10 @@ bool LayoutImage::NeedsLayoutOnIntrinsicSizeChange() const {
kDontRegisterPercentageDescendant);
if (!image_size_is_constrained)
return true;
+ // Flex layout algorithm uses the intrinsic image width/height even if
+ // width/height are specified.
+ if (IsFlexItemIncludingNG())
+ return true;
// FIXME: We only need to recompute the containing block's preferred size if
// the containing block's size depends on the image's size (i.e., the
// container uses shrink-to-fit sizing). There's no easy way to detect that
@@ -179,7 +185,7 @@ void LayoutImage::InvalidatePaintAndMarkForLayoutIfNeeded(
return;
if (old_intrinsic_size != new_intrinsic_size) {
- SetPreferredLogicalWidthsDirty();
+ SetIntrinsicLogicalWidthsDirty();
if (NeedsLayoutOnIntrinsicSizeChange()) {
SetNeedsLayoutAndFullPaintInvalidation(
@@ -306,20 +312,19 @@ bool LayoutImage::NodeAtPoint(HitTestResult& result,
return inside;
}
-IntSize LayoutImage::GetOverriddenIntrinsicSize() const {
- if (auto* image_element = DynamicTo<HTMLImageElement>(GetNode())) {
- if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled())
- return image_element->GetOverriddenIntrinsicSize();
- }
- return IntSize();
+bool LayoutImage::HasOverriddenIntrinsicSize() const {
+ if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled())
+ return false;
+ auto* image_element = DynamicTo<HTMLImageElement>(GetNode());
+ return image_element && image_element->IsDefaultIntrinsicSize();
}
FloatSize LayoutImage::ImageSizeOverriddenByIntrinsicSize(
float multiplier) const {
- FloatSize overridden_intrinsic_size = FloatSize(GetOverriddenIntrinsicSize());
- if (overridden_intrinsic_size.IsEmpty())
+ if (!HasOverriddenIntrinsicSize())
return image_resource_->ImageSize(multiplier);
+ FloatSize overridden_intrinsic_size(kDefaultWidth, kDefaultHeight);
if (multiplier != 1) {
overridden_intrinsic_size.Scale(multiplier);
if (overridden_intrinsic_size.Width() < 1.0f)
@@ -333,11 +338,11 @@ FloatSize LayoutImage::ImageSizeOverriddenByIntrinsicSize(
bool LayoutImage::OverrideIntrinsicSizingInfo(
IntrinsicSizingInfo& intrinsic_sizing_info) const {
- IntSize overridden_intrinsic_size = GetOverriddenIntrinsicSize();
- if (overridden_intrinsic_size.IsEmpty())
+ if (!HasOverriddenIntrinsicSize())
return false;
- intrinsic_sizing_info.size = FloatSize(overridden_intrinsic_size);
+ FloatSize overridden_intrinsic_size(kDefaultWidth, kDefaultHeight);
+ intrinsic_sizing_info.size = overridden_intrinsic_size;
intrinsic_sizing_info.aspect_ratio = intrinsic_sizing_info.size;
if (!IsHorizontalWritingMode())
intrinsic_sizing_info.Transpose();
@@ -393,7 +398,8 @@ void LayoutImage::ComputeIntrinsicSizingInfo(
// we're painting alt text and/or a broken image.
// Video is excluded from this behavior because video elements have a default
// aspect ratio that a failed poster image load should not override.
- if (image_resource_ && image_resource_->ErrorOccurred() && !IsVideo()) {
+ if (image_resource_ && image_resource_->ErrorOccurred() &&
+ !IsA<LayoutVideo>(this)) {
intrinsic_sizing_info.aspect_ratio = FloatSize(1, 1);
return;
}
@@ -414,15 +420,18 @@ SVGImage* LayoutImage::EmbeddedSVGImage() const {
// https://crbug.com/761026
if (!cached_image || cached_image->IsCacheValidator())
return nullptr;
- return ToSVGImageOrNull(cached_image->GetImage());
+ return DynamicTo<SVGImage>(cached_image->GetImage());
}
void LayoutImage::UpdateAfterLayout() {
LayoutBox::UpdateAfterLayout();
Node* node = GetNode();
if (auto* image_element = DynamicTo<HTMLImageElement>(node)) {
- media_element_parser_helpers::ReportUnsizedMediaViolation(
+ media_element_parser_helpers::CheckUnsizedMediaViolation(
this, image_element->IsDefaultIntrinsicSize());
+ } else if (auto* video_element = DynamicTo<HTMLVideoElement>(node)) {
+ media_element_parser_helpers::CheckUnsizedMediaViolation(
+ this, video_element->IsDefaultIntrinsicSize());
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image.h b/chromium/third_party/blink/renderer/core/layout/layout_image.h
index 43364aaf8d3..3ed38c13197 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image.h
@@ -135,8 +135,8 @@ class CORE_EXPORT LayoutImage : public LayoutReplaced {
// Override intrinsic sizing info to default if "unsized-media"
// is disabled and the element has no sizing info.
bool OverrideIntrinsicSizingInfo(IntrinsicSizingInfo&) const;
+ bool HasOverriddenIntrinsicSize() const;
FloatSize ImageSizeOverriddenByIntrinsicSize(float multiplier) const;
- IntSize GetOverriddenIntrinsicSize() const;
// This member wraps the associated decoded image.
//
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc b/chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc
index 1f260426bcd..57bc7eb48e2 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image_resource.cc
@@ -168,7 +168,8 @@ scoped_refptr<Image> LayoutImageResource::GetImage(
layout_object_->StyleRef().EffectiveZoom());
}
- if (!image->IsSVGImage())
+ auto* svg_image = DynamicTo<SVGImage>(image);
+ if (!svg_image)
return image;
KURL url;
@@ -177,8 +178,8 @@ scoped_refptr<Image> LayoutImageResource::GetImage(
url = element->GetDocument().CompleteURL(url_string);
}
return SVGImageForContainer::Create(
- ToSVGImage(image), container_size,
- layout_object_->StyleRef().EffectiveZoom(), url);
+ svg_image, container_size, layout_object_->StyleRef().EffectiveZoom(),
+ url);
}
bool LayoutImageResource::MaybeAnimated() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image_resource.h b/chromium/third_party/blink/renderer/core/layout/layout_image_resource.h
index af9230cd5f0..808a0958044 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image_resource.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image_resource.h
@@ -70,7 +70,7 @@ class CORE_EXPORT LayoutImageResource
const LayoutSize&) const;
virtual WrappedImagePtr ImagePtr() const { return cached_image_.Get(); }
- virtual void Trace(blink::Visitor* visitor) { visitor->Trace(cached_image_); }
+ virtual void Trace(Visitor* visitor) { visitor->Trace(cached_image_); }
protected:
// Device scale factor for the associated LayoutObject.
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc b/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc
index 77873f52cef..ed8c3dfe576 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.cc
@@ -78,10 +78,11 @@ FloatSize LayoutImageResourceStyleImage::ImageSize(float multiplier) const {
FloatSize LayoutImageResourceStyleImage::ImageSizeWithDefaultSize(
float multiplier,
const LayoutSize& default_size) const {
- return style_image_->ImageSize(layout_object_->GetDocument(), multiplier,
- default_size);
+ return style_image_->ImageSize(
+ layout_object_->GetDocument(), multiplier, default_size,
+ LayoutObject::ShouldRespectImageOrientation(layout_object_));
}
-void LayoutImageResourceStyleImage::Trace(blink::Visitor* visitor) {
+void LayoutImageResourceStyleImage::Trace(Visitor* visitor) {
visitor->Trace(style_image_);
LayoutImageResource::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h b/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h
index 1b2bd849409..108d42d137f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image_resource_style_image.h
@@ -55,7 +55,7 @@ class LayoutImageResourceStyleImage final : public LayoutImageResource {
const LayoutSize&) const override;
WrappedImagePtr ImagePtr() const override { return style_image_->Data(); }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Member<StyleImage> style_image_;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_inline.cc b/chromium/third_party/blink/renderer/core/layout/layout_inline.cc
index a8a84440bd0..a7dd0e57408 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -171,7 +171,20 @@ void LayoutInline::SetFirstInlineFragmentItemIndex(wtf_size_t index) {
CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK_NE(index, 0u);
- first_fragment_item_index_ = index;
+ // TDOO(yosin): Once we update all |LayoutObject::FirstInlineFragment()|,
+ // we should enable below.
+ // first_fragment_item_index_ = index;
+}
+
+bool LayoutInline::HasInlineFragments() const {
+ if (!IsInLayoutNGInlineFormattingContext())
+ return FirstLineBox();
+ if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return first_paint_fragment_;
+ // TODO(yosin): We should use |first_fragment_item_index_|.
+ NGInlineCursor cursor;
+ cursor.MoveTo(*this);
+ return cursor;
}
void LayoutInline::InLayoutNGInlineFormattingContextWillChange(bool new_value) {
@@ -518,7 +531,7 @@ void LayoutInline::AddChildIgnoringContinuation(LayoutObject* new_child,
LayoutBoxModelObject::AddChild(new_child, before_child);
- new_child->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ new_child->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kChildChanged);
}
@@ -673,7 +686,7 @@ void LayoutInline::SplitFlow(LayoutObject* before_child,
o = no->NextSibling();
pre->Children()->AppendChildNode(
pre, block->Children()->RemoveChildNode(block, no));
- no->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ no->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kAnonymousBlockChange);
}
}
@@ -691,11 +704,11 @@ void LayoutInline::SplitFlow(LayoutObject* before_child,
// wrappers for images) get deleted properly. Because objects moves from the
// pre block into the post block, we want to make new line boxes instead of
// leaving the old line boxes around.
- pre->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ pre->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kAnonymousBlockChange);
- block->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ block->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kAnonymousBlockChange);
- post->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ post->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kAnonymousBlockChange);
}
@@ -790,9 +803,16 @@ void LayoutInline::CollectLineBoxRects(
const auto* box_fragment = ContainingBlockFlowFragmentOf(*this);
if (!box_fragment)
return;
- for (const auto& fragment :
- NGInlineFragmentTraversal::SelfFragmentsOf(*box_fragment, this))
- yield(fragment.RectInContainerBox());
+ if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ for (const auto& fragment :
+ NGInlineFragmentTraversal::SelfFragmentsOf(*box_fragment, this))
+ yield(fragment.RectInContainerBox());
+ return;
+ }
+ NGInlineCursor cursor;
+ cursor.MoveTo(*this);
+ for (; cursor; cursor.MoveToNextForSameLayoutObject())
+ yield(cursor.Current().RectInContainerBlock());
return;
}
if (!AlwaysCreateLineBoxes()) {
@@ -940,7 +960,7 @@ base::Optional<PhysicalOffset> LayoutInline::FirstLineBoxTopLeftInternal()
cursor.MoveTo(*this);
if (!cursor)
return base::nullopt;
- return cursor.CurrentOffset();
+ return cursor.Current().OffsetInContainerBlock();
}
if (const InlineBox* first_box = FirstLineBoxIncludingCulling()) {
LayoutPoint location = first_box->Location();
@@ -1027,21 +1047,41 @@ bool LayoutInline::NodeAtPoint(HitTestResult& result,
HitTestAction hit_test_action) {
if (ContainingNGBlockFlow()) {
// TODO(crbug.com/965976): We should fix the root cause of the missed
- // layout, and then turn this into a DCHECK.
- CHECK(!NeedsLayout()) << this;
+ // layout.
+ if (UNLIKELY(NeedsLayout())) {
+ NOTREACHED();
+ return false;
+ }
// In LayoutNG, we reach here only when called from
// PaintLayer::HitTestContents() without going through any ancestor, in
// which case the element must have self painting layer.
DCHECK(HasSelfPaintingLayer());
- for (const NGPaintFragment* fragment :
- NGPaintFragment::InlineFragmentsFor(this)) {
+ NGInlineCursor cursor;
+ for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject()) {
+ if (const NGPaintFragment* paint_fragment =
+ cursor.Current().PaintFragment()) {
+ // NGBoxFragmentPainter::NodeAtPoint() takes an offset that is
+ // accumulated up to the fragment itself. Compute this offset.
+ const PhysicalOffset child_offset =
+ accumulated_offset + paint_fragment->OffsetInContainerBlock();
+ if (NGBoxFragmentPainter(*paint_fragment)
+ .NodeAtPoint(result, hit_test_location, child_offset,
+ hit_test_action))
+ return true;
+ continue;
+ }
+ DCHECK(cursor.Current().Item());
+ const NGFragmentItem& item = *cursor.Current().Item();
+ const NGPhysicalBoxFragment* box_fragment = item.BoxFragment();
+ DCHECK(box_fragment);
// NGBoxFragmentPainter::NodeAtPoint() takes an offset that is accumulated
// up to the fragment itself. Compute this offset.
- PhysicalOffset adjusted_location =
- accumulated_offset + fragment->InlineOffsetToContainerBox();
- if (NGBoxFragmentPainter(*fragment).NodeAtPoint(
- result, hit_test_location, adjusted_location, hit_test_action))
+ const PhysicalOffset child_offset =
+ accumulated_offset + item.OffsetInContainerBlock();
+ if (NGBoxFragmentPainter(cursor, item, *box_fragment)
+ .NodeAtPoint(result, hit_test_location, child_offset,
+ accumulated_offset, hit_test_action))
return true;
}
return false;
@@ -1083,7 +1123,7 @@ bool LayoutInline::HitTestCulledInline(
container_fragment->PhysicalFragment().IsLineBox());
NGInlineCursor cursor(*container_fragment);
for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject())
- yield(cursor.CurrentRect());
+ yield(cursor.Current().RectInContainerBlock());
} else {
DCHECK(!ContainingNGBlockFlow());
CollectCulledLineBoxRects(yield);
@@ -1135,7 +1175,7 @@ PhysicalRect LayoutInline::PhysicalLinesBoundingBox() const {
cursor.MoveTo(*this);
PhysicalRect bounding_box;
for (; cursor; cursor.MoveToNextForSameLayoutObject())
- bounding_box.UniteIfNonZero(cursor.CurrentRect());
+ bounding_box.UniteIfNonZero(cursor.Current().RectInContainerBlock());
return bounding_box;
}
@@ -1283,8 +1323,8 @@ PhysicalRect LayoutInline::LinesVisualOverflowBoundingBox() const {
NGInlineCursor cursor;
cursor.MoveTo(*this);
for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
- PhysicalRect child_rect = cursor.CurrentInkOverflow();
- child_rect.offset += cursor.CurrentOffset();
+ PhysicalRect child_rect = cursor.Current().InkOverflow();
+ child_rect.offset += cursor.Current().OffsetInContainerBlock();
result.Unite(child_rect);
}
return result;
@@ -1394,7 +1434,7 @@ PhysicalRect LayoutInline::ReferenceBoxForClipPath() const {
NGInlineCursor cursor;
cursor.MoveTo(*this);
if (cursor)
- return cursor.CurrentRect();
+ return cursor.Current().RectInContainerBlock();
}
if (const InlineFlowBox* flow_box = FirstLineBox())
return FlipForWritingMode(flow_box->FrameRect());
@@ -1736,7 +1776,8 @@ void LayoutInline::InvalidateDisplayItemClients(
PaintInvalidationReason invalidation_reason) const {
ObjectPaintInvalidator paint_invalidator(*this);
- if (RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled()) {
+ if (RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled() &&
+ !RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
auto fragments = NGPaintFragment::InlineFragmentsFor(this);
if (fragments.IsInLayoutNGInlineFormattingContext()) {
for (NGPaintFragment* fragment : fragments) {
@@ -1748,13 +1789,14 @@ void LayoutInline::InvalidateDisplayItemClients(
}
if (IsInLayoutNGInlineFormattingContext()) {
- if (!ShouldCreateBoxFragment())
+ if (!ShouldCreateBoxFragment() &&
+ !RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
return;
NGInlineCursor cursor;
for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject()) {
- DCHECK_EQ(cursor.CurrentLayoutObject(), this);
+ DCHECK_EQ(cursor.Current().GetLayoutObject(), this);
paint_invalidator.InvalidateDisplayItemClient(
- *cursor.CurrentDisplayItemClient(), invalidation_reason);
+ *cursor.Current().GetDisplayItemClient(), invalidation_reason);
}
return;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_inline.h b/chromium/third_party/blink/renderer/core/layout/layout_inline.h
index a6a4fe2a5fa..448bf29cadd 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_inline.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_inline.h
@@ -172,16 +172,13 @@ class CORE_EXPORT LayoutInline : public LayoutBoxModelObject {
return AlwaysCreateLineBoxes() ? LastLineBox() : CulledInlineLastLineBox();
}
+ bool HasInlineFragments() const final;
NGPaintFragment* FirstInlineFragment() const final;
void SetFirstInlineFragment(NGPaintFragment*) final;
wtf_size_t FirstInlineFragmentItemIndex() const final;
void ClearFirstInlineFragmentItemIndex() final;
void SetFirstInlineFragmentItemIndex(wtf_size_t) final;
- // Return true if this inline doesn't occur on any lines, i.e. when it creates
- // no fragments.
- bool IsEmpty() const { return !FirstLineBox() && !FirstInlineFragment(); }
-
LayoutBoxModelObject* VirtualContinuation() const final {
return Continuation();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_inline_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_inline_test.cc
index 7570ca21718..2c8922ef27c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_inline_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_inline_test.cc
@@ -4,9 +4,11 @@
#include "third_party/blink/renderer/core/layout/layout_inline.h"
+#include "build/build_config.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
@@ -25,7 +27,9 @@ class ParameterizedLayoutInlineTest : public testing::WithParamInterface<bool>,
ParameterizedLayoutInlineTest() : ScopedLayoutNGForTest(GetParam()) {}
protected:
- bool LayoutNGEnabled() const { return GetParam(); }
+ bool LayoutNGEnabled() const {
+ return RuntimeEnabledFeatures::LayoutNGEnabled();
+ }
};
INSTANTIATE_TEST_SUITE_P(All, ParameterizedLayoutInlineTest, testing::Bool());
@@ -107,6 +111,14 @@ TEST_F(LayoutInlineTest, RegionHitTest) {
ToLayoutInline(GetLayoutObjectByElementId("lotsOfBoxes"));
ASSERT_TRUE(lots_of_boxes);
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ NGInlineCursor cursor;
+ cursor.MoveTo(*lots_of_boxes);
+ ASSERT_TRUE(cursor);
+ EXPECT_EQ(lots_of_boxes, cursor.Current().GetLayoutObject());
+ return;
+ }
+
HitTestRequest hit_request(HitTestRequest::kTouchEvent |
HitTestRequest::kListBased);
@@ -676,4 +688,119 @@ TEST_P(ParameterizedLayoutInlineTest, AddAnnotatedRegionsVerticalRL) {
EXPECT_TRUE(regions3.IsEmpty());
}
+TEST_P(ParameterizedLayoutInlineTest, VisualOverflowRecalcLegacyLayout) {
+ // "contenteditable" forces us to use legacy layout, other options could be
+ // using "display: -webkit-box", ruby, etc.
+ LoadAhem();
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body {
+ margin: 0;
+ font: 20px/20px Ahem;
+ }
+ target {
+ outline: 50px solid red;
+ }
+ </style>
+ <div contenteditable>
+ <span id="span">SPAN1</span>
+ <span id="span2">SPAN2</span>
+ </div>
+ )HTML");
+
+ auto* span = ToLayoutInline(GetLayoutObjectByElementId("span"));
+ auto* span_element = GetDocument().getElementById("span");
+ auto* span2_element = GetDocument().getElementById("span2");
+
+ span_element->setAttribute(html_names::kStyleAttr, "outline: 50px solid red");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(PhysicalRect(-50, -50, 200, 120),
+ span->PhysicalVisualOverflowRect());
+
+ span_element->setAttribute(html_names::kStyleAttr, "");
+ span2_element->setAttribute(html_names::kStyleAttr,
+ "outline: 50px solid red");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(PhysicalRect(0, 0, 100, 20), span->PhysicalVisualOverflowRect());
+
+ span2_element->setAttribute(html_names::kStyleAttr, "");
+ span_element->setAttribute(html_names::kStyleAttr, "outline: 50px solid red");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(PhysicalRect(-50, -50, 200, 120),
+ span->PhysicalVisualOverflowRect());
+
+ span_element->setAttribute(html_names::kStyleAttr, "");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(PhysicalRect(0, 0, 100, 20), span->PhysicalVisualOverflowRect());
+}
+
+TEST_P(ParameterizedLayoutInlineTest, VisualOverflowRecalcLayoutNG) {
+ LoadAhem();
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body {
+ margin: 0;
+ font: 20px/20px Ahem;
+ }
+ target {
+ outline: 50px solid red;
+ }
+ </style>
+ <div>
+ <span id="span">SPAN1</span>
+ <span id="span2">SPAN2</span>
+ </div>
+ )HTML");
+
+ auto* span = ToLayoutInline(GetLayoutObjectByElementId("span"));
+ auto* span_element = GetDocument().getElementById("span");
+ auto* span2_element = GetDocument().getElementById("span2");
+
+ span_element->setAttribute(html_names::kStyleAttr, "outline: 50px solid red");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(PhysicalRect(-50, -50, 200, 120),
+ span->PhysicalVisualOverflowRect());
+
+ span_element->setAttribute(html_names::kStyleAttr, "");
+ span2_element->setAttribute(html_names::kStyleAttr,
+ "outline: 50px solid red");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(PhysicalRect(0, 0, 100, 20), span->PhysicalVisualOverflowRect());
+
+ span2_element->setAttribute(html_names::kStyleAttr, "");
+ span_element->setAttribute(html_names::kStyleAttr, "outline: 50px solid red");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(PhysicalRect(-50, -50, 200, 120),
+ span->PhysicalVisualOverflowRect());
+
+ span_element->setAttribute(html_names::kStyleAttr, "");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(PhysicalRect(0, 0, 100, 20), span->PhysicalVisualOverflowRect());
+}
+
+TEST_P(ParameterizedLayoutInlineTest,
+ VisualOverflowRecalcLegacyLayoutPositionRelative) {
+ LoadAhem();
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body {
+ margin: 0;
+ font: 20px/20px Ahem;
+ }
+ span {
+ position: relative;
+ }
+ </style>
+ <span id="span">SPAN</span>
+ )HTML");
+
+ auto* span = ToLayoutInline(GetLayoutObjectByElementId("span"));
+ auto* span_element = GetDocument().getElementById("span");
+
+ span_element->setAttribute(html_names::kStyleAttr, "outline: 50px solid red");
+ UpdateAllLifecyclePhasesForTest();
+ EXPECT_EQ(PhysicalRect(-50, -50, 180, 120),
+ span->PhysicalVisualOverflowRect());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_inside_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/layout_inside_list_marker.cc
new file mode 100644
index 00000000000..ada7d6b11d0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/layout_inside_list_marker.cc
@@ -0,0 +1,14 @@
+// Copyright 2020 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_inside_list_marker.h"
+
+namespace blink {
+
+LayoutInsideListMarker::LayoutInsideListMarker(Element* element)
+ : LayoutListMarker(element) {}
+
+LayoutInsideListMarker::~LayoutInsideListMarker() = default;
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_inside_list_marker.h b/chromium/third_party/blink/renderer/core/layout/layout_inside_list_marker.h
new file mode 100644
index 00000000000..22426dfdec1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/layout_inside_list_marker.h
@@ -0,0 +1,33 @@
+// Copyright 2020 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_INSIDE_LIST_MARKER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_INSIDE_LIST_MARKER_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/layout_list_marker.h"
+
+namespace blink {
+
+// Used to layout the list item's inside marker.
+// The LayoutInsideListMarker always has to be a child of a LayoutListItem.
+class CORE_EXPORT LayoutInsideListMarker final : public LayoutListMarker {
+ public:
+ explicit LayoutInsideListMarker(Element*);
+ ~LayoutInsideListMarker() override;
+
+ const char* GetName() const override { return "LayoutInsideListMarker"; }
+
+ private:
+ bool IsOfType(LayoutObjectType type) const override {
+ return type == kLayoutObjectInsideListMarker ||
+ LayoutListMarker::IsOfType(type);
+ }
+};
+
+DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutInsideListMarker, IsInsideListMarker());
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_INSIDE_LIST_MARKER_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_box.cc b/chromium/third_party/blink/renderer/core/layout/layout_list_box.cc
deleted file mode 100644
index 1e9c1061abc..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_box.cc
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
- * 2009 Torch Mobile Inc. All rights reserved.
- * (http://www.torchmobile.com/)
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "third_party/blink/renderer/core/layout/layout_list_box.h"
-
-#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
-#include "third_party/blink/renderer/core/dom/element_traversal.h"
-#include "third_party/blink/renderer/core/html/forms/html_opt_group_element.h"
-#include "third_party/blink/renderer/core/html/forms/html_option_element.h"
-#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
-#include "third_party/blink/renderer/core/html/html_div_element.h"
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
-#include "third_party/blink/renderer/core/scroll/scroll_alignment.h"
-#include "third_party/blink/renderer/core/scroll/scroll_types.h"
-
-namespace blink {
-
-// Default size when the multiple attribute is present but size attribute is
-// absent.
-const int kDefaultSize = 4;
-
-const int kDefaultPaddingBottom = 1;
-
-LayoutListBox::LayoutListBox(Element* element) : LayoutBlockFlow(element) {
- DCHECK(element);
- DCHECK(element->IsHTMLElement());
- DCHECK(IsA<HTMLSelectElement>(element));
-}
-
-LayoutListBox::~LayoutListBox() = default;
-
-inline HTMLSelectElement* LayoutListBox::SelectElement() const {
- return To<HTMLSelectElement>(GetNode());
-}
-
-unsigned LayoutListBox::size() const {
- unsigned specified_size = SelectElement()->size();
- if (specified_size >= 1)
- return specified_size;
-
- return kDefaultSize;
-}
-
-LayoutUnit LayoutListBox::DefaultItemHeight() const {
- const SimpleFontData* font_data = StyleRef().GetFont().PrimaryFont();
- if (!font_data)
- return LayoutUnit();
- return LayoutUnit(font_data->GetFontMetrics().Height() +
- kDefaultPaddingBottom);
-}
-
-LayoutUnit LayoutListBox::ItemHeight() const {
- // If the intrinsic-inline-size is specified, then we shouldn't ever need to
- // get the ItemHeight.
- DCHECK(!HasOverrideIntrinsicContentLogicalHeight());
-
- HTMLSelectElement* select = SelectElement();
- if (!select)
- return LayoutUnit();
-
- const auto& items = select->GetListItems();
- if (items.IsEmpty() || ShouldApplySizeContainment())
- return DefaultItemHeight();
-
- LayoutUnit max_height;
- for (Element* element : items) {
- if (auto* optgroup = DynamicTo<HTMLOptGroupElement>(element))
- element = &optgroup->OptGroupLabelElement();
- LayoutObject* layout_object = element->GetLayoutObject();
- LayoutUnit item_height;
- if (layout_object && layout_object->IsBox())
- item_height = ToLayoutBox(layout_object)->Size().Height();
- else
- item_height = DefaultItemHeight();
- max_height = std::max(max_height, item_height);
- }
- return max_height;
-}
-
-void LayoutListBox::ComputeLogicalHeight(
- LayoutUnit,
- LayoutUnit logical_top,
- LogicalExtentComputedValues& computed_values) const {
- LayoutUnit height;
- if (HasOverrideIntrinsicContentLogicalHeight()) {
- height = OverrideIntrinsicContentLogicalHeight();
- } else {
- height = ItemHeight() * size();
- }
-
- // FIXME: The item height should have been added before updateLogicalHeight
- // was called to avoid this hack.
- SetIntrinsicContentLogicalHeight(height);
-
- height += BorderAndPaddingHeight();
-
- LayoutBox::ComputeLogicalHeight(height, logical_top, computed_values);
-}
-
-void LayoutListBox::StopAutoscroll() {
- HTMLSelectElement* select = SelectElement();
- if (select->IsDisabledFormControl())
- return;
- select->HandleMouseRelease();
-}
-
-void LayoutListBox::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
- LayoutBlockFlow::ComputeIntrinsicLogicalWidths(min_logical_width,
- max_logical_width);
- if (StyleRef().Width().IsPercentOrCalc())
- min_logical_width = LayoutUnit();
-}
-
-void LayoutListBox::ScrollToRect(const PhysicalRect& absolute_rect) {
- if (HasOverflowClip()) {
- DCHECK(Layer());
- DCHECK(Layer()->GetScrollableArea());
- Layer()->GetScrollableArea()->ScrollIntoView(
- absolute_rect, WebScrollIntoViewParams(
- ScrollAlignment::kAlignToEdgeIfNeeded,
- ScrollAlignment::kAlignToEdgeIfNeeded,
- kProgrammaticScroll, false, kScrollBehaviorInstant));
- }
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_box.h b/chromium/third_party/blink/renderer/core/layout/layout_list_box.h
deleted file mode 100644
index 91e76c1b097..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_box.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * This file is part of the select element layoutObject in WebCore.
- *
- * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
- * its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_LIST_BOX_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_LIST_BOX_H_
-
-#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
-
-namespace blink {
-
-class HTMLSelectElement;
-
-class CORE_EXPORT LayoutListBox final : public LayoutBlockFlow {
- public:
- explicit LayoutListBox(Element*);
- ~LayoutListBox() override;
-
- unsigned size() const;
-
- // Unlike scrollRectToVisible this will not scroll parent boxes.
- void ScrollToRect(const PhysicalRect&);
-
- const char* GetName() const override { return "LayoutListBox"; }
-
- private:
- HTMLSelectElement* SelectElement() const;
-
- bool IsOfType(LayoutObjectType type) const override {
- return type == kLayoutObjectListBox || LayoutBlockFlow::IsOfType(type);
- }
-
- void ComputeLogicalHeight(LayoutUnit logical_height,
- LayoutUnit logical_top,
- LogicalExtentComputedValues&) const override;
- void ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const override;
-
- void StopAutoscroll() override;
-
- LayoutUnit DefaultItemHeight() const;
- LayoutUnit ItemHeight() const;
-};
-
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutListBox, IsListBox());
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_LIST_BOX_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_item.cc b/chromium/third_party/blink/renderer/core/layout/layout_list_item.cc
index 6f882e11a4a..df0dd904451 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_item.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_item.cc
@@ -36,7 +36,6 @@ namespace blink {
LayoutListItem::LayoutListItem(Element* element)
: LayoutBlockFlow(element),
- marker_(nullptr),
need_block_direction_align_(false) {
SetInline(false);
@@ -51,13 +50,7 @@ void LayoutListItem::StyleDidChange(StyleDifference diff,
StyleImage* current_image = StyleRef().ListStyleImage();
if (StyleRef().ListStyleType() != EListStyleType::kNone ||
(current_image && !current_image->ErrorOccurred())) {
- if (!marker_)
- marker_ = LayoutListMarker::CreateAnonymous(this);
- marker_->ListItemStyleDidChange();
NotifyOfSubtreeChange();
- } else if (marker_) {
- marker_->Destroy();
- marker_ = nullptr;
}
StyleImage* old_image = old_style ? old_style->ListStyleImage() : nullptr;
@@ -70,11 +63,6 @@ void LayoutListItem::StyleDidChange(StyleDifference diff,
}
void LayoutListItem::WillBeDestroyed() {
- if (marker_) {
- marker_->Destroy();
- marker_ = nullptr;
- }
-
LayoutBlockFlow::WillBeDestroyed();
if (Style() && StyleRef().ListStyleImage())
@@ -94,7 +82,8 @@ void LayoutListItem::WillBeRemovedFromTree() {
}
void LayoutListItem::SubtreeDidChange() {
- if (!marker_)
+ LayoutListMarker* marker = Marker();
+ if (!marker)
return;
if (!UpdateMarkerLocation())
@@ -102,8 +91,8 @@ void LayoutListItem::SubtreeDidChange() {
// If the marker is inside we need to redo the preferred width calculations
// as the size of the item now includes the size of the list marker.
- if (marker_->IsInside())
- SetPreferredLogicalWidthsDirty();
+ if (marker->IsInsideListMarker())
+ SetIntrinsicLogicalWidthsDirty();
}
int LayoutListItem::Value() const {
@@ -112,13 +101,12 @@ int LayoutListItem::Value() const {
}
bool LayoutListItem::IsEmpty() const {
- return LastChild() == marker_;
+ return LastChild() == Marker();
}
namespace {
-LayoutObject* GetParentOfFirstLineBox(LayoutBlockFlow* curr,
- LayoutObject* marker) {
+LayoutObject* GetParentOfFirstLineBox(LayoutBlockFlow* curr) {
LayoutObject* first_child = curr->FirstChild();
if (!first_child)
return nullptr;
@@ -126,7 +114,7 @@ LayoutObject* GetParentOfFirstLineBox(LayoutBlockFlow* curr,
bool in_quirks_mode = curr->GetDocument().InQuirksMode();
for (LayoutObject* curr_child = first_child; curr_child;
curr_child = curr_child->NextSibling()) {
- if (curr_child == marker)
+ if (curr_child->IsOutsideListMarker())
continue;
if (curr_child->IsInline() &&
@@ -150,7 +138,7 @@ LayoutObject* GetParentOfFirstLineBox(LayoutBlockFlow* curr,
IsA<HTMLOListElement>(*curr_child->GetNode())))
break;
- LayoutObject* line_box = GetParentOfFirstLineBox(child_block_flow, marker);
+ LayoutObject* line_box = GetParentOfFirstLineBox(child_block_flow);
if (line_box)
return line_box;
}
@@ -186,21 +174,27 @@ void ForceLogicalHeight(LayoutObject& layout_object, const Length& height) {
// marker_container to 0px; else restore it to LogicalHeight of <li>.
bool LayoutListItem::PrepareForBlockDirectionAlign(
const LayoutObject* line_box_parent) {
- LayoutObject* marker_parent = marker_->Parent();
+ LayoutListMarker* marker = Marker();
+ LayoutObject* marker_parent = marker->Parent();
+ bool is_inside = marker->IsInsideListMarker();
// Deal with the situation of layout tree changed.
if (marker_parent && marker_parent->IsAnonymous()) {
+ bool marker_parent_has_lines =
+ line_box_parent && line_box_parent->IsDescendantOf(marker_parent);
// When list-position-style change from outside to inside, we need to
- // restore LogicalHeight to auto. So add IsInside().
- if (marker_->IsInside() || marker_->NextSibling()) {
+ // restore LogicalHeight to auto. So add is_inside.
+ if (is_inside || marker_parent_has_lines) {
// Set marker_container's LogicalHeight to auto.
if (marker_parent->StyleRef().LogicalHeight().IsZero())
ForceLogicalHeight(*marker_parent, Length());
- // If marker_parent isn't the ancestor of line_box_parent, marker might
- // generate a new empty line. We need to remove marker here.E.g:
- // <li><span><div>text<div><span></li>
- if (line_box_parent && !line_box_parent->IsDescendantOf(marker_parent)) {
- marker_->Remove();
+ // If marker_parent_has_lines and the marker is outside, we need to move
+ // the marker into another parent with 'height: 0' to avoid generating a
+ // new empty line in cases like <li><span><div>text<div><span></li>
+ // If the marker is inside and there are inline contents, we want them to
+ // share the same block container to avoid a line break between them.
+ if (is_inside != marker_parent_has_lines) {
+ marker->Remove();
marker_parent = nullptr;
}
} else if (line_box_parent) {
@@ -211,19 +205,18 @@ bool LayoutListItem::PrepareForBlockDirectionAlign(
// Create marker_container, set its height to 0px, and add it to li.
if (!marker_parent) {
LayoutObject* before_child = FirstNonMarkerChild(this);
- if (!marker_->IsInside() && before_child && !before_child->IsInline()) {
+ if (!is_inside && before_child && !before_child->IsInline()) {
// Create marker_container and set its LogicalHeight to 0px.
LayoutBlock* marker_container = CreateAnonymousBlock();
if (line_box_parent)
ForceLogicalHeight(*marker_container, Length::Fixed(0));
- marker_container->AddChild(marker_,
- FirstNonMarkerChild(marker_container));
+ marker_container->AddChild(marker, FirstNonMarkerChild(marker_container));
AddChild(marker_container, before_child);
} else {
- AddChild(marker_, before_child);
+ AddChild(marker, before_child);
}
- marker_->UpdateMarginsAndContent();
+ marker->UpdateMarginsAndContent();
return true;
}
return false;
@@ -241,13 +234,24 @@ static bool IsFirstLeafChild(LayoutObject* container, LayoutObject* child) {
}
bool LayoutListItem::UpdateMarkerLocation() {
- DCHECK(marker_);
+ DCHECK(Marker());
- LayoutObject* marker_parent = marker_->Parent();
+ LayoutListMarker* marker = Marker();
+ LayoutObject* marker_parent = marker->Parent();
LayoutObject* line_box_parent = nullptr;
- if (!marker_->IsInside())
- line_box_parent = GetParentOfFirstLineBox(this, marker_);
+ // Make sure a marker originated by a ::before or ::after precedes the
+ // generated contents.
+ if (IsPseudoElement()) {
+ LayoutObject* first_child = marker_parent->SlowFirstChild();
+ if (marker != first_child) {
+ marker->Remove();
+ AddChild(marker, first_child);
+ }
+ }
+
+ if (marker->IsOutsideListMarker())
+ line_box_parent = GetParentOfFirstLineBox(this);
if (line_box_parent && (line_box_parent->HasOverflowClip() ||
!line_box_parent->IsLayoutBlockFlow() ||
(line_box_parent->IsBox() &&
@@ -277,13 +281,13 @@ bool LayoutListItem::UpdateMarkerLocation() {
if (!marker_parent ||
(marker_parent != line_box_parent && NormalChildNeedsLayout())) {
- marker_->Remove();
- line_box_parent->AddChild(marker_, FirstNonMarkerChild(line_box_parent));
+ marker->Remove();
+ line_box_parent->AddChild(marker, FirstNonMarkerChild(line_box_parent));
// TODO(rhogan): line_box_parent and marker_parent may be deleted by
// AddChild, so they are not safe to reference here. Once we have a safe way
// of referencing them delete marker_parent if it is an empty anonymous
// block.
- marker_->UpdateMarginsAndContent();
+ marker->UpdateMarginsAndContent();
return true;
}
@@ -309,6 +313,7 @@ void LayoutListItem::ComputeVisualOverflow(bool recompute_floats) {
AddVisualOverflowFromFloats();
if (VisualOverflowRect() != previous_visual_overflow_rect) {
+ InvalidateIntersectionObserverCachedRects();
SetShouldCheckForPaintInvalidation();
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
}
@@ -327,7 +332,8 @@ void LayoutListItem::AlignMarkerInBlockDirection() {
// layout pass. So if there's no line box in line_box_parent make sure it
// back to its original position.
bool back_to_original_baseline = false;
- LayoutObject* line_box_parent = GetParentOfFirstLineBox(this, marker_);
+ LayoutListMarker* marker = Marker();
+ LayoutObject* line_box_parent = GetParentOfFirstLineBox(this);
LayoutBox* line_box_parent_block = nullptr;
if (!line_box_parent || !line_box_parent->IsBox()) {
back_to_original_baseline = true;
@@ -339,12 +345,12 @@ void LayoutListItem::AlignMarkerInBlockDirection() {
back_to_original_baseline = true;
}
- InlineBox* marker_inline_box = marker_->InlineBoxWrapper();
+ InlineBox* marker_inline_box = marker->InlineBoxWrapper();
RootInlineBox& marker_root = marker_inline_box->Root();
auto* line_box_parent_block_flow =
DynamicTo<LayoutBlockFlow>(line_box_parent_block);
if (line_box_parent_block && line_box_parent_block_flow) {
- // If marker_ and line_box_parent_block share a same RootInlineBox, no need
+ // If marker and line_box_parent_block share a same RootInlineBox, no need
// to align marker.
if (line_box_parent_block_flow->FirstRootBox() == &marker_root)
return;
@@ -355,7 +361,7 @@ void LayoutListItem::AlignMarkerInBlockDirection() {
offset = line_box_parent_block->FirstLineBoxBaseline();
if (back_to_original_baseline || offset == -1) {
- line_box_parent_block = marker_->ContainingBlock();
+ line_box_parent_block = marker->ContainingBlock();
offset = line_box_parent_block->FirstLineBoxBaseline();
}
@@ -369,11 +375,11 @@ void LayoutListItem::AlignMarkerInBlockDirection() {
// instead. BaselinePosition is workable when marker is an image.
// However, when marker is text, BaselinePosition contains lineheight
// information. So use marker_font_metrics.Ascent when marker is text.
- if (marker_->IsImage()) {
+ if (marker->IsImage()) {
offset -= marker_inline_box->BaselinePosition(marker_root.BaselineType());
} else {
const SimpleFontData* marker_font_data =
- marker_->Style(true)->GetFont().PrimaryFont();
+ marker->Style(true)->GetFont().PrimaryFont();
if (marker_font_data) {
const FontMetrics& marker_font_metrics =
marker_font_data->GetFontMetrics();
@@ -382,7 +388,7 @@ void LayoutListItem::AlignMarkerInBlockDirection() {
}
offset -= marker_inline_box->LogicalTop();
- for (LayoutBox* o = marker_->ParentBox(); o != this; o = o->ParentBox()) {
+ for (LayoutBox* o = marker->ParentBox(); o != this; o = o->ParentBox()) {
offset -= o->LogicalTop();
}
@@ -392,24 +398,25 @@ void LayoutListItem::AlignMarkerInBlockDirection() {
}
void LayoutListItem::UpdateOverflow() {
- if (!marker_ || !marker_->Parent() || !marker_->Parent()->IsBox() ||
- marker_->IsInside() || !marker_->InlineBoxWrapper())
+ LayoutListMarker* marker = Marker();
+ if (!marker || !marker->Parent() || !marker->Parent()->IsBox() ||
+ marker->IsInsideListMarker() || !marker->InlineBoxWrapper())
return;
if (need_block_direction_align_)
AlignMarkerInBlockDirection();
- LayoutUnit marker_old_logical_left = marker_->LogicalLeft();
+ LayoutUnit marker_old_logical_left = marker->LogicalLeft();
LayoutUnit block_offset;
LayoutUnit line_offset;
- for (LayoutBox* o = marker_->ParentBox(); o != this; o = o->ParentBox()) {
+ for (LayoutBox* o = marker->ParentBox(); o != this; o = o->ParentBox()) {
block_offset += o->LogicalTop();
line_offset += o->LogicalLeft();
}
bool adjust_overflow = false;
LayoutUnit marker_logical_left;
- InlineBox* marker_inline_box = marker_->InlineBoxWrapper();
+ InlineBox* marker_inline_box = marker->InlineBoxWrapper();
RootInlineBox& root = marker_inline_box->Root();
bool hit_self_painting_layer = false;
@@ -427,11 +434,11 @@ void LayoutListItem::UpdateOverflow() {
// FIXME: Need to account for relative positioning in the layout overflow.
if (StyleRef().IsLeftToRightDirection()) {
LayoutUnit marker_line_offset =
- std::min(marker_->LineOffset(),
- LogicalLeftOffsetForLine(marker_->LogicalTop(),
+ std::min(marker->LineOffset(),
+ LogicalLeftOffsetForLine(marker->LogicalTop(),
kDoNotIndentText, LayoutUnit()));
marker_logical_left = marker_line_offset - line_offset - PaddingStart() -
- BorderStart() + marker_->MarginStart();
+ BorderStart() + marker->MarginStart();
marker_inline_box->MoveInInlineDirection(marker_logical_left -
marker_old_logical_left);
@@ -468,11 +475,11 @@ void LayoutListItem::UpdateOverflow() {
}
} else {
LayoutUnit marker_line_offset =
- std::max(marker_->LineOffset(),
- LogicalRightOffsetForLine(marker_->LogicalTop(),
+ std::max(marker->LineOffset(),
+ LogicalRightOffsetForLine(marker->LogicalTop(),
kDoNotIndentText, LayoutUnit()));
marker_logical_left = marker_line_offset - line_offset + PaddingStart() +
- BorderStart() + marker_->MarginEnd();
+ BorderStart() + marker->MarginEnd();
marker_inline_box->MoveInInlineDirection(marker_logical_left -
marker_old_logical_left);
@@ -482,11 +489,11 @@ void LayoutListItem::UpdateOverflow() {
box->AddReplacedChildrenVisualOverflow(line_top, line_bottom);
LayoutRect new_logical_visual_overflow_rect =
box->LogicalVisualOverflowRect(line_top, line_bottom);
- if (marker_logical_left + marker_->LogicalWidth() >
+ if (marker_logical_left + marker->LogicalWidth() >
new_logical_visual_overflow_rect.MaxX() &&
!hit_self_painting_layer) {
new_logical_visual_overflow_rect.SetWidth(
- marker_logical_left + marker_->LogicalWidth() -
+ marker_logical_left + marker->LogicalWidth() -
new_logical_visual_overflow_rect.X());
if (box == root)
adjust_overflow = true;
@@ -498,10 +505,10 @@ void LayoutListItem::UpdateOverflow() {
hit_self_painting_layer = true;
LayoutRect new_logical_layout_overflow_rect =
box->LogicalLayoutOverflowRect(line_top, line_bottom);
- if (marker_logical_left + marker_->LogicalWidth() >
+ if (marker_logical_left + marker->LogicalWidth() >
new_logical_layout_overflow_rect.MaxX()) {
new_logical_layout_overflow_rect.SetWidth(
- marker_logical_left + marker_->LogicalWidth() -
+ marker_logical_left + marker->LogicalWidth() -
new_logical_layout_overflow_rect.X());
if (box == root)
adjust_overflow = true;
@@ -518,10 +525,10 @@ void LayoutListItem::UpdateOverflow() {
LayoutRect marker_rect(
LayoutPoint(marker_logical_left + line_offset,
block_offset + marker_inline_box->LogicalTop()),
- marker_->Size());
+ marker->Size());
if (!StyleRef().IsHorizontalWritingMode())
marker_rect = marker_rect.TransposedRect();
- LayoutBox* object = marker_;
+ LayoutBox* object = marker;
bool found_self_painting_layer = false;
do {
@@ -549,16 +556,16 @@ void LayoutListItem::Paint(const PaintInfo& paint_info) const {
}
const String& LayoutListItem::MarkerText() const {
- if (marker_)
- return marker_->GetText();
+ if (LayoutListMarker* marker = Marker())
+ return marker->GetText();
return g_null_atom.GetString();
}
void LayoutListItem::OrdinalValueChanged() {
- if (!marker_)
- return;
- marker_->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
- layout_invalidation_reason::kListValueChange);
+ if (LayoutListMarker* marker = Marker()) {
+ marker->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
+ layout_invalidation_reason::kListValueChange);
+ }
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_item.h b/chromium/third_party/blink/renderer/core/layout/layout_list_item.h
index 3984e8ddabc..b324ba8020a 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_item.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_item.h
@@ -26,11 +26,10 @@
#include "third_party/blink/renderer/core/html/list_item_ordinal.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/layout_list_marker.h"
namespace blink {
-class LayoutListMarker;
-
class LayoutListItem final : public LayoutBlockFlow {
public:
explicit LayoutListItem(Element*);
@@ -41,7 +40,16 @@ class LayoutListItem final : public LayoutBlockFlow {
bool IsEmpty() const;
- LayoutListMarker* Marker() const { return marker_; }
+ LayoutListMarker* Marker() const {
+ Element* list_item = To<Element>(GetNode());
+ if (LayoutObject* marker =
+ list_item->PseudoElementLayoutObject(kPseudoIdMarker)) {
+ if (marker->IsListMarker())
+ return ToLayoutListMarker(marker);
+ NOTREACHED();
+ }
+ return nullptr;
+ }
ListItemOrdinal& Ordinal() { return ordinal_; }
void OrdinalValueChanged();
@@ -80,7 +88,6 @@ class LayoutListItem final : public LayoutBlockFlow {
bool PrepareForBlockDirectionAlign(const LayoutObject*);
ListItemOrdinal ordinal_;
- LayoutListMarker* marker_;
bool need_block_direction_align_;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc
index 7af899cd5b2..0425425e887 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc
@@ -41,8 +41,8 @@ const int kCMarkerPaddingPx = 7;
// Recommended UA margin for list markers.
const int kCUAMarkerMarginEm = 1;
-LayoutListMarker::LayoutListMarker(LayoutListItem* item)
- : LayoutBox(nullptr), list_item_(item), line_offset_() {
+LayoutListMarker::LayoutListMarker(Element* element) : LayoutBox(element) {
+ DCHECK(ListItem());
SetInline(true);
SetIsAtomicInlineLevel(true);
}
@@ -55,11 +55,11 @@ void LayoutListMarker::WillBeDestroyed() {
LayoutBox::WillBeDestroyed();
}
-LayoutListMarker* LayoutListMarker::CreateAnonymous(LayoutListItem* item) {
- Document& document = item->GetDocument();
- LayoutListMarker* layout_object = new LayoutListMarker(item);
- layout_object->SetDocumentForAnonymous(&document);
- return layout_object;
+const LayoutListItem* LayoutListMarker::ListItem() const {
+ LayoutObject* list_item = GetNode()->parentNode()->GetLayoutObject();
+ DCHECK(list_item);
+ DCHECK(list_item->IsListItem());
+ return ToLayoutListItem(list_item);
}
LayoutSize LayoutListMarker::ImageBulletSize() const {
@@ -77,7 +77,8 @@ LayoutSize LayoutListMarker::ImageBulletSize() const {
font_data->GetFontMetrics().Ascent() / LayoutUnit(2);
return RoundedLayoutSize(
image_->ImageSize(GetDocument(), StyleRef().EffectiveZoom(),
- LayoutSize(bullet_width, bullet_width)));
+ LayoutSize(bullet_width, bullet_width),
+ LayoutObject::ShouldRespectImageOrientation(this)));
}
void LayoutListMarker::StyleWillChange(StyleDifference diff,
@@ -88,7 +89,7 @@ void LayoutListMarker::StyleWillChange(StyleDifference diff,
(new_style.ListStyleType() == EListStyleType::kString &&
new_style.ListStyleStringValue() !=
StyleRef().ListStyleStringValue()))) {
- SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kStyleChange);
}
@@ -127,14 +128,15 @@ void LayoutListMarker::UpdateLayout() {
LayoutAnalyzer::Scope analyzer(*this);
LayoutUnit block_offset = LogicalTop();
- for (LayoutBox* o = ParentBox(); o && o != ListItem(); o = o->ParentBox()) {
+ const LayoutListItem* list_item = ListItem();
+ for (LayoutBox* o = ParentBox(); o && o != list_item; o = o->ParentBox()) {
block_offset += o->LogicalTop();
}
- if (ListItem()->StyleRef().IsLeftToRightDirection()) {
- line_offset_ = ListItem()->LogicalLeftOffsetForLine(
+ if (list_item->StyleRef().IsLeftToRightDirection()) {
+ line_offset_ = list_item->LogicalLeftOffsetForLine(
block_offset, kDoNotIndentText, LayoutUnit());
} else {
- line_offset_ = ListItem()->LogicalRightOffsetForLine(
+ line_offset_ = list_item->LogicalRightOffsetForLine(
block_offset, kDoNotIndentText, LayoutUnit());
}
if (IsImage()) {
@@ -145,21 +147,11 @@ void LayoutListMarker::UpdateLayout() {
} else {
const SimpleFontData* font_data = StyleRef().GetFont().PrimaryFont();
DCHECK(font_data);
- SetLogicalWidth(MinPreferredLogicalWidth());
+ SetLogicalWidth(PreferredLogicalWidths().min_size);
SetLogicalHeight(
LayoutUnit(font_data ? font_data->GetFontMetrics().Height() : 0));
}
- SetMarginStart(LayoutUnit());
- SetMarginEnd(LayoutUnit());
-
- const Length& start_margin = StyleRef().MarginStart();
- const Length& end_margin = StyleRef().MarginEnd();
- if (start_margin.IsFixed())
- SetMarginStart(LayoutUnit(start_margin.Value()));
- if (end_margin.IsFixed())
- SetMarginEnd(LayoutUnit(end_margin.Value()));
-
ClearNeedsLayout();
}
@@ -171,7 +163,7 @@ void LayoutListMarker::ImageChanged(WrappedImagePtr o, CanDeferInvalidation) {
LayoutSize image_size = IsImage() ? ImageBulletSize() : LayoutSize();
if (Size() != image_size || image_->ErrorOccurred()) {
- SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kImageChanged);
} else {
SetShouldDoFullPaintInvalidation();
@@ -179,14 +171,11 @@ void LayoutListMarker::ImageChanged(WrappedImagePtr o, CanDeferInvalidation) {
}
void LayoutListMarker::UpdateMarginsAndContent() {
- if (PreferredLogicalWidthsDirty())
- ComputePreferredLogicalWidths();
- else
- UpdateMargins();
+ UpdateMargins(PreferredLogicalWidths().min_size);
}
void LayoutListMarker::UpdateContent() {
- DCHECK(PreferredLogicalWidthsDirty());
+ DCHECK(IntrinsicLogicalWidthsDirty());
text_ = "";
@@ -202,7 +191,7 @@ void LayoutListMarker::UpdateContent() {
break;
case ListStyleCategory::kLanguage:
text_ = list_marker_text::GetText(StyleRef().ListStyleType(),
- list_item_->Value());
+ ListItem()->Value());
break;
case ListStyleCategory::kStaticString:
text_ = StyleRef().ListStyleStringValue();
@@ -214,7 +203,7 @@ String LayoutListMarker::TextAlternative() const {
if (GetListStyleCategory() == ListStyleCategory::kStaticString)
return text_;
UChar suffix =
- list_marker_text::Suffix(StyleRef().ListStyleType(), list_item_->Value());
+ list_marker_text::Suffix(StyleRef().ListStyleType(), ListItem()->Value());
// Return suffix after the marker text, even in RTL, reflecting speech order.
return text_ + suffix + ' ';
}
@@ -232,7 +221,7 @@ LayoutUnit LayoutListMarker::GetWidthOfText(ListStyleCategory category) const {
// TODO(wkorman): Look into constructing a text run for both text and suffix
// and painting them together.
UChar suffix[2] = {
- list_marker_text::Suffix(StyleRef().ListStyleType(), list_item_->Value()),
+ list_marker_text::Suffix(StyleRef().ListStyleType(), ListItem()->Value()),
' '};
TextRun run =
ConstructTextRun(font, suffix, 2, StyleRef(), StyleRef().Direction());
@@ -240,40 +229,36 @@ LayoutUnit LayoutListMarker::GetWidthOfText(ListStyleCategory category) const {
return item_width + suffix_space_width;
}
-void LayoutListMarker::ComputePreferredLogicalWidths() {
- DCHECK(PreferredLogicalWidthsDirty());
- UpdateContent();
+MinMaxSizes LayoutListMarker::ComputeIntrinsicLogicalWidths() const {
+ DCHECK(IntrinsicLogicalWidthsDirty());
+ const_cast<LayoutListMarker*>(this)->UpdateContent();
+ MinMaxSizes sizes;
if (IsImage()) {
LayoutSize image_size(ImageBulletSize());
- min_preferred_logical_width_ = max_preferred_logical_width_ =
- StyleRef().IsHorizontalWritingMode() ? image_size.Width()
- : image_size.Height();
- ClearPreferredLogicalWidthsDirty();
- UpdateMargins();
- return;
- }
-
- LayoutUnit logical_width;
- ListStyleCategory category = GetListStyleCategory();
- switch (category) {
- case ListStyleCategory::kNone:
- break;
- case ListStyleCategory::kSymbol:
- logical_width = WidthOfSymbol(StyleRef());
- break;
- case ListStyleCategory::kLanguage:
- case ListStyleCategory::kStaticString:
- logical_width = GetWidthOfText(category);
- break;
+ sizes = StyleRef().IsHorizontalWritingMode() ? image_size.Width()
+ : image_size.Height();
+ } else {
+ ListStyleCategory category = GetListStyleCategory();
+ switch (category) {
+ case ListStyleCategory::kNone:
+ break;
+ case ListStyleCategory::kSymbol:
+ sizes = WidthOfSymbol(StyleRef());
+ break;
+ case ListStyleCategory::kLanguage:
+ case ListStyleCategory::kStaticString:
+ sizes = GetWidthOfText(category);
+ break;
+ }
}
- min_preferred_logical_width_ = logical_width;
- max_preferred_logical_width_ = logical_width;
-
- ClearPreferredLogicalWidthsDirty();
+ const_cast<LayoutListMarker*>(this)->UpdateMargins(sizes.min_size);
+ return sizes;
+}
- UpdateMargins();
+MinMaxSizes LayoutListMarker::PreferredLogicalWidths() const {
+ return IntrinsicLogicalWidths();
}
LayoutUnit LayoutListMarker::WidthOfSymbol(const ComputedStyle& style) {
@@ -285,32 +270,27 @@ LayoutUnit LayoutListMarker::WidthOfSymbol(const ComputedStyle& style) {
return LayoutUnit((font_data->GetFontMetrics().Ascent() * 2 / 3 + 1) / 2 + 2);
}
-void LayoutListMarker::UpdateMargins() {
+void LayoutListMarker::UpdateMargins(LayoutUnit marker_inline_size) {
LayoutUnit margin_start;
LayoutUnit margin_end;
const ComputedStyle& style = StyleRef();
- if (IsInside()) {
+ if (IsInsideListMarker()) {
std::tie(margin_start, margin_end) =
InlineMarginsForInside(style, IsImage());
} else {
std::tie(margin_start, margin_end) =
- InlineMarginsForOutside(style, IsImage(), MinPreferredLogicalWidth());
+ InlineMarginsForOutside(style, IsImage(), marker_inline_size);
}
- Length start_length = Length::Fixed(margin_start);
- Length end_length = Length::Fixed(margin_end);
-
- if (start_length != style.MarginStart() || end_length != style.MarginEnd()) {
- scoped_refptr<ComputedStyle> new_style = ComputedStyle::Clone(style);
- new_style->SetMarginStart(start_length);
- new_style->SetMarginEnd(end_length);
- SetStyleInternal(std::move(new_style));
- }
+ SetMarginStart(margin_start);
+ SetMarginEnd(margin_end);
}
std::pair<LayoutUnit, LayoutUnit> LayoutListMarker::InlineMarginsForInside(
const ComputedStyle& style,
bool is_image) {
+ if (!style.ContentBehavesAsNormal())
+ return {};
if (is_image)
return {LayoutUnit(), LayoutUnit(kCMarkerPaddingPx)};
switch (GetListStyleCategory(style.ListStyleType())) {
@@ -329,51 +309,31 @@ std::pair<LayoutUnit, LayoutUnit> LayoutListMarker::InlineMarginsForOutside(
LayoutUnit marker_inline_size) {
LayoutUnit margin_start;
LayoutUnit margin_end;
- if (style.IsLeftToRightDirection()) {
- if (is_image) {
- margin_start = -marker_inline_size - kCMarkerPaddingPx;
- } else {
- switch (GetListStyleCategory(style.ListStyleType())) {
- case ListStyleCategory::kNone:
- break;
- case ListStyleCategory::kSymbol: {
- const SimpleFontData* font_data = style.GetFont().PrimaryFont();
- DCHECK(font_data);
- if (!font_data)
- return {};
- const FontMetrics& font_metrics = font_data->GetFontMetrics();
- int offset = font_metrics.Ascent() * 2 / 3;
- margin_start = LayoutUnit(-offset - kCMarkerPaddingPx - 1);
- break;
- }
- default:
- margin_start = -marker_inline_size;
- }
- }
- margin_end = -margin_start - marker_inline_size;
+ if (!style.ContentBehavesAsNormal()) {
+ margin_start = -marker_inline_size;
+ } else if (is_image) {
+ margin_start = -marker_inline_size - kCMarkerPaddingPx;
+ margin_end = LayoutUnit(kCMarkerPaddingPx);
} else {
- if (is_image) {
- margin_end = LayoutUnit(kCMarkerPaddingPx);
- } else {
- switch (GetListStyleCategory(style.ListStyleType())) {
- case ListStyleCategory::kNone:
- break;
- case ListStyleCategory::kSymbol: {
- const SimpleFontData* font_data = style.GetFont().PrimaryFont();
- DCHECK(font_data);
- if (!font_data)
- return {};
- const FontMetrics& font_metrics = font_data->GetFontMetrics();
- int offset = font_metrics.Ascent() * 2 / 3;
- margin_end = offset + kCMarkerPaddingPx + 1 - marker_inline_size;
- break;
- }
- default:
- margin_end = LayoutUnit();
+ switch (GetListStyleCategory(style.ListStyleType())) {
+ case ListStyleCategory::kNone:
+ break;
+ case ListStyleCategory::kSymbol: {
+ const SimpleFontData* font_data = style.GetFont().PrimaryFont();
+ DCHECK(font_data);
+ if (!font_data)
+ return {};
+ const FontMetrics& font_metrics = font_data->GetFontMetrics();
+ int offset = font_metrics.Ascent() * 2 / 3;
+ margin_start = LayoutUnit(-offset - kCMarkerPaddingPx - 1);
+ margin_end = offset + kCMarkerPaddingPx + 1 - marker_inline_size;
+ break;
}
+ default:
+ margin_start = -marker_inline_size;
}
- margin_start = -margin_end - marker_inline_size;
}
+ DCHECK_EQ(margin_start + margin_end, -marker_inline_size);
return {margin_start, margin_end};
}
@@ -382,7 +342,7 @@ LayoutUnit LayoutListMarker::LineHeight(
LineDirectionMode direction,
LinePositionMode line_position_mode) const {
if (!IsImage())
- return list_item_->LineHeight(first_line, direction,
+ return ListItem()->LineHeight(first_line, direction,
kPositionOfInteriorLineBoxes);
return LayoutBox::LineHeight(first_line, direction, line_position_mode);
}
@@ -394,7 +354,7 @@ LayoutUnit LayoutListMarker::BaselinePosition(
LinePositionMode line_position_mode) const {
DCHECK_EQ(line_position_mode, kPositionOnContainingLine);
if (!IsImage())
- return list_item_->BaselinePosition(baseline_type, first_line, direction,
+ return ListItem()->BaselinePosition(baseline_type, first_line, direction,
kPositionOfInteriorLineBoxes);
return LayoutBox::BaselinePosition(baseline_type, first_line, direction,
line_position_mode);
@@ -475,11 +435,6 @@ LayoutListMarker::ListStyleCategory LayoutListMarker::GetListStyleCategory(
}
}
-bool LayoutListMarker::IsInside() const {
- return list_item_->Ordinal().NotInList() ||
- StyleRef().ListStylePosition() == EListStylePosition::kInside;
-}
-
LayoutRect LayoutListMarker::GetRelativeMarkerRect() const {
if (IsImage())
return LayoutRect(LayoutPoint(), ImageBulletSize());
@@ -535,31 +490,4 @@ LayoutRect LayoutListMarker::RelativeSymbolMarkerRect(
return relative_rect;
}
-void LayoutListMarker::ListItemStyleDidChange() {
- Node* list_item = list_item_->GetNode();
- const ComputedStyle* cached_marker_style =
- list_item->IsPseudoElement()
- ? nullptr
- : ToElement(list_item)->CachedStyleForPseudoElement(kPseudoIdMarker);
- scoped_refptr<ComputedStyle> new_style;
- if (cached_marker_style) {
- new_style = ComputedStyle::Clone(*cached_marker_style);
- } else {
- // The marker always inherits from the list item, regardless of where it
- // might end up (e.g., in some deeply nested line box). See CSS3 spec.
- new_style = ComputedStyle::Create();
- new_style->InheritFrom(list_item_->StyleRef());
- new_style->SetStyleType(kPseudoIdMarker);
- new_style->SetUnicodeBidi(UnicodeBidi::kIsolate);
- new_style->SetFontVariantNumericSpacing(FontVariantNumeric::kTabularNums);
- }
- if (Style()) {
- // Reuse the current margins. Otherwise resetting the margins to initial
- // values would trigger unnecessary layout.
- new_style->SetMarginStart(StyleRef().MarginStart());
- new_style->SetMarginEnd(StyleRef().MarginRight());
- }
- SetStyle(std::move(new_style));
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_list_marker.h b/chromium/third_party/blink/renderer/core/layout/layout_list_marker.h
index 68d1a290b0f..1fee564ee6e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_list_marker.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_list_marker.h
@@ -31,11 +31,10 @@ namespace blink {
class LayoutListItem;
-// Used to layout the list item's marker.
-// The LayoutListMarker always has to be a child of a LayoutListItem.
-class CORE_EXPORT LayoutListMarker final : public LayoutBox {
+// This class holds code shared among legacy classes for list markers.
+class CORE_EXPORT LayoutListMarker : public LayoutBox {
public:
- static LayoutListMarker* CreateAnonymous(LayoutListItem*);
+ explicit LayoutListMarker(Element*);
~LayoutListMarker() override;
// Marker text without suffix, e.g. "1".
@@ -53,8 +52,6 @@ class CORE_EXPORT LayoutListMarker final : public LayoutBox {
ListStyleCategory GetListStyleCategory() const;
static ListStyleCategory GetListStyleCategory(EListStyleType);
- bool IsInside() const;
-
void UpdateMarginsAndContent();
// Compute inline margins for 'list-style-position: inside' and 'outside'.
@@ -72,26 +69,17 @@ class CORE_EXPORT LayoutListMarker final : public LayoutBox {
bool IsImage() const override;
const StyleImage* GetImage() const { return image_.Get(); }
- const LayoutListItem* ListItem() const { return list_item_; }
+ const LayoutListItem* ListItem() const;
LayoutSize ImageBulletSize() const;
- void ListItemStyleDidChange();
-
- const char* GetName() const override { return "LayoutListMarker"; }
-
LayoutUnit LineOffset() const { return line_offset_; }
protected:
void WillBeDestroyed() override;
private:
- LayoutListMarker(LayoutListItem*);
-
- void ComputePreferredLogicalWidths() override;
-
- bool IsOfType(LayoutObjectType type) const override {
- return type == kLayoutObjectListMarker || LayoutBox::IsOfType(type);
- }
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const override;
+ MinMaxSizes PreferredLogicalWidths() const override;
void Paint(const PaintInfo&) const override;
@@ -114,21 +102,15 @@ class CORE_EXPORT LayoutListMarker final : public LayoutBox {
bool IsText() const { return !IsImage(); }
LayoutUnit GetWidthOfText(ListStyleCategory) const;
- void UpdateMargins();
+ void UpdateMargins(LayoutUnit marker_inline_size);
void UpdateContent();
void StyleWillChange(StyleDifference,
const ComputedStyle& new_style) override;
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
- bool AnonymousHasStylePropagationOverride() override { return true; }
-
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override {
- return false;
- }
String text_;
Persistent<StyleImage> image_;
- LayoutListItem* list_item_;
LayoutUnit line_offset_;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_media.cc b/chromium/third_party/blink/renderer/core/layout/layout_media.cc
index 2764e0b773f..359dc680f00 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_media.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_media.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/core/layout/layout_media.h"
+#include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/html/media/html_media_element.h"
@@ -41,7 +42,7 @@ LayoutMedia::LayoutMedia(HTMLMediaElement* video) : LayoutImage(video) {
LayoutMedia::~LayoutMedia() = default;
HTMLMediaElement* LayoutMedia::MediaElement() const {
- return ToHTMLMediaElement(GetNode());
+ return To<HTMLMediaElement>(GetNode());
}
void LayoutMedia::UpdateLayout() {
@@ -154,9 +155,9 @@ LayoutUnit LayoutMedia::ComputePanelWidth(const LayoutRect& media_rect) const {
// TODO(crbug.com/771379): Once we no longer assume that the video is in the
// main frame for the visibility calculation below, we will only care about
// the video's frame's scrollbar check below.
- ScrollbarMode h_mode, v_mode;
+ mojom::blink::ScrollbarMode h_mode, v_mode;
page_view->GetLayoutView()->CalculateScrollbarModes(h_mode, v_mode);
- if (h_mode != ScrollbarMode::kAlwaysOff)
+ if (h_mode != mojom::blink::ScrollbarMode::kAlwaysOff)
return media_rect.Width();
// If the video's frame (can be different from main frame if video is in an
@@ -165,7 +166,7 @@ LayoutUnit LayoutMedia::ComputePanelWidth(const LayoutRect& media_rect) const {
LocalFrameView* media_page_view = media_frame ? media_frame->View() : nullptr;
if (media_page_view && media_page_view->GetLayoutView()) {
media_page_view->GetLayoutView()->CalculateScrollbarModes(h_mode, v_mode);
- if (h_mode != ScrollbarMode::kAlwaysOff)
+ if (h_mode != mojom::blink::ScrollbarMode::kAlwaysOff)
return media_rect.Width();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_media.h b/chromium/third_party/blink/renderer/core/layout/layout_media.h
index 98d8a954ffb..d3032678339 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_media.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_media.h
@@ -89,8 +89,6 @@ class LayoutMedia : public LayoutImage {
LayoutObjectChildList children_;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutMedia, IsMedia());
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_MEDIA_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_menu_list.cc b/chromium/third_party/blink/renderer/core/layout/layout_menu_list.cc
deleted file mode 100644
index d10d4e199cd..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/layout_menu_list.cc
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * This file is part of the select element layoutObject in WebCore.
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
- * All rights reserved.
- * (C) 2009 Torch Mobile Inc. All rights reserved.
- * (http://www.torchmobile.com/)
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "third_party/blink/renderer/core/layout/layout_menu_list.h"
-
-#include <math.h>
-#include "third_party/blink/public/strings/grit/blink_strings.h"
-#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
-#include "third_party/blink/renderer/core/dom/node_computed_style.h"
-#include "third_party/blink/renderer/core/frame/local_frame_view.h"
-#include "third_party/blink/renderer/core/html/forms/html_option_element.h"
-#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
-#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
-#include "third_party/blink/renderer/core/layout/layout_text.h"
-#include "third_party/blink/renderer/core/layout/layout_theme.h"
-#include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/platform/text/platform_locale.h"
-
-namespace blink {
-
-LayoutMenuList::LayoutMenuList(Element* element)
- : LayoutFlexibleBox(element),
- button_text_(nullptr),
- inner_block_(nullptr),
- is_empty_(false),
- has_updated_active_option_(false),
- inner_block_height_(LayoutUnit()),
- options_width_(0),
- last_active_index_(-1) {
- DCHECK(IsA<HTMLSelectElement>(element));
-}
-
-LayoutMenuList::~LayoutMenuList() = default;
-
-bool LayoutMenuList::IsChildAllowed(LayoutObject* object,
- const ComputedStyle&) const {
- // For a size=1 <select>, we only render the active option through the
- // anonymous inner_block_ plus button_text_. We do not allow adding layout
- // objects for options or optgroups.
- return object->IsAnonymous();
-}
-
-scoped_refptr<ComputedStyle> LayoutMenuList::CreateInnerStyle() {
- scoped_refptr<ComputedStyle> inner_style =
- ComputedStyle::CreateAnonymousStyleWithDisplay(StyleRef(),
- EDisplay::kBlock);
-
- AdjustInnerStyle(*inner_style);
- return inner_style;
-}
-
-void LayoutMenuList::UpdateInnerStyle() {
- DCHECK(inner_block_);
- scoped_refptr<ComputedStyle> inner_style =
- ComputedStyle::Clone(inner_block_->StyleRef());
- AdjustInnerStyle(*inner_style);
- inner_block_->SetModifiedStyleOutsideStyleRecalc(std::move(inner_style),
- ApplyStyleChanges::kNo);
- // LayoutMenuList::ControlClipRect() depends on inner_block_->ContentsSize().
- SetNeedsPaintPropertyUpdate();
- if (Layer())
- Layer()->SetNeedsCompositingInputsUpdate();
-}
-
-void LayoutMenuList::CreateInnerBlock() {
- if (inner_block_) {
- DCHECK_EQ(FirstChild(), inner_block_);
- DCHECK(!inner_block_->NextSibling());
- return;
- }
-
- // Create an anonymous block.
- LegacyLayout legacy =
- ForceLegacyLayout() ? LegacyLayout::kForce : LegacyLayout::kAuto;
- DCHECK(!FirstChild());
- inner_block_ = LayoutBlockFlow::CreateAnonymous(&GetDocument(),
- CreateInnerStyle(), legacy);
-
- button_text_ =
- LayoutText::CreateEmptyAnonymous(GetDocument(), Style(), legacy);
- // We need to set the text explicitly though it was specified in the
- // constructor because LayoutText doesn't refer to the text
- // specified in the constructor in a case of re-transforming.
- inner_block_->AddChild(button_text_);
- LayoutFlexibleBox::AddChild(inner_block_);
-
- // LayoutMenuList::ControlClipRect() depends on inner_block_->ContentsSize().
- SetNeedsPaintPropertyUpdate();
- if (Layer())
- Layer()->SetNeedsCompositingInputsUpdate();
-}
-
-bool LayoutMenuList::HasOptionStyleChanged(
- const ComputedStyle& inner_style) const {
- return option_style_ &&
- ((option_style_->Direction() != inner_style.Direction() ||
- option_style_->GetUnicodeBidi() != inner_style.GetUnicodeBidi()));
-}
-
-void LayoutMenuList::AdjustInnerStyle(ComputedStyle& inner_style) const {
- inner_style.SetFlexGrow(1);
- inner_style.SetFlexShrink(1);
- // min-width: 0; is needed for correct shrinking.
- inner_style.SetMinWidth(Length::Fixed(0));
-
- // Use margin:auto instead of align-items:center to get safe centering, i.e.
- // when the content overflows, treat it the same as align-items: flex-start.
- // But we only do that for the cases where html.css would otherwise use
- // center.
- if (StyleRef().AlignItemsPosition() == ItemPosition::kCenter) {
- inner_style.SetMarginTop(Length());
- inner_style.SetMarginBottom(Length());
- inner_style.SetAlignSelfPosition(ItemPosition::kFlexStart);
- }
-
- Length padding_start = Length::Fixed(
- LayoutTheme::GetTheme().PopupInternalPaddingStart(StyleRef()));
- Length padding_end = Length::Fixed(
- LayoutTheme::GetTheme().PopupInternalPaddingEnd(GetFrame(), StyleRef()));
- inner_style.SetPaddingLeft(StyleRef().Direction() == TextDirection::kLtr
- ? padding_start
- : padding_end);
- inner_style.SetPaddingRight(StyleRef().Direction() == TextDirection::kLtr
- ? padding_end
- : padding_start);
- inner_style.SetPaddingTop(Length::Fixed(
- LayoutTheme::GetTheme().PopupInternalPaddingTop(StyleRef())));
- inner_style.SetPaddingBottom(Length::Fixed(
- LayoutTheme::GetTheme().PopupInternalPaddingBottom(StyleRef())));
- inner_style.SetTextAlign(StyleRef().IsLeftToRightDirection()
- ? ETextAlign::kLeft
- : ETextAlign::kRight);
-
- if (HasOptionStyleChanged(inner_style)) {
- inner_block_->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
- layout_invalidation_reason::kStyleChange);
- inner_style.SetDirection(option_style_->Direction());
- inner_style.SetUnicodeBidi(option_style_->GetUnicodeBidi());
- }
-}
-
-HTMLSelectElement* LayoutMenuList::SelectElement() const {
- return To<HTMLSelectElement>(GetNode());
-}
-
-void LayoutMenuList::AddChild(LayoutObject* new_child,
- LayoutObject* before_child) {
- inner_block_->AddChild(new_child, before_child);
- DCHECK_EQ(inner_block_, FirstChild());
-
- if (AXObjectCache* cache = GetDocument().ExistingAXObjectCache())
- cache->ChildrenChanged(this);
-
- // LayoutMenuList::ControlClipRect() depends on inner_block_->ContentsSize().
- SetNeedsPaintPropertyUpdate();
- if (Layer())
- Layer()->SetNeedsCompositingInputsUpdate();
-}
-
-void LayoutMenuList::RemoveChild(LayoutObject* old_child) {
- if (old_child == inner_block_ || !inner_block_) {
- LayoutFlexibleBox::RemoveChild(old_child);
- inner_block_ = nullptr;
- } else {
- inner_block_->RemoveChild(old_child);
- }
-}
-
-void LayoutMenuList::StyleDidChange(StyleDifference diff,
- const ComputedStyle* old_style) {
- LayoutBlock::StyleDidChange(diff, old_style);
-
- if (!inner_block_)
- CreateInnerBlock();
-
- button_text_->SetStyle(Style());
- UpdateInnerStyle();
- UpdateInnerBlockHeight();
-}
-
-void LayoutMenuList::UpdateInnerBlockHeight() {
- const SimpleFontData* font_data = StyleRef().GetFont().PrimaryFont();
- DCHECK(font_data);
- inner_block_height_ = (font_data ? font_data->GetFontMetrics().Height() : 0) +
- inner_block_->BorderAndPaddingHeight();
-}
-
-void LayoutMenuList::UpdateOptionsWidth() const {
- if (ShouldApplySizeContainment()) {
- options_width_ = 0;
- return;
- }
-
- float max_option_width = 0;
-
- for (auto* const option : SelectElement()->GetOptionList()) {
- String text = option->TextIndentedToRespectGroupLabel();
- const ComputedStyle* item_style =
- option->GetComputedStyle() ? option->GetComputedStyle() : Style();
- item_style->ApplyTextTransform(&text);
- // We apply SELECT's style, not OPTION's style because m_optionsWidth is
- // used to determine intrinsic width of the menulist box.
- TextRun text_run = ConstructTextRun(StyleRef().GetFont(), text, *Style());
- max_option_width =
- std::max(max_option_width, StyleRef().GetFont().Width(text_run));
- }
- options_width_ = static_cast<int>(ceilf(max_option_width));
-}
-
-void LayoutMenuList::UpdateFromElement() {
- HTMLSelectElement* select = SelectElement();
- HTMLOptionElement* option = select->OptionToBeShown();
- String text = g_empty_string;
- option_style_ = nullptr;
-
- if (select->IsMultiple()) {
- unsigned selected_count = 0;
- HTMLOptionElement* selected_option_element = nullptr;
- for (auto* const option : select->GetOptionList()) {
- if (option->Selected()) {
- if (++selected_count == 1)
- selected_option_element = option;
- }
- }
-
- if (selected_count == 1) {
- text = selected_option_element->TextIndentedToRespectGroupLabel();
- option_style_ = selected_option_element->GetComputedStyle();
- } else {
- Locale& locale = select->GetLocale();
- String localized_number_string =
- locale.ConvertToLocalizedNumber(String::Number(selected_count));
- text = locale.QueryString(IDS_FORM_SELECT_MENU_LIST_TEXT,
- localized_number_string);
- DCHECK(!option_style_);
- }
- } else {
- if (option) {
- text = option->TextIndentedToRespectGroupLabel();
- option_style_ = option->GetComputedStyle();
- }
- }
-
- SetText(text.StripWhiteSpace());
-
- DidUpdateActiveOption(option);
-
- DCHECK(inner_block_);
- if (HasOptionStyleChanged(inner_block_->StyleRef()))
- UpdateInnerStyle();
-}
-
-void LayoutMenuList::SetText(const String& s) {
- if (s.IsEmpty()) {
- // FIXME: This is a hack. We need the select to have the same baseline
- // positioning as any surrounding text. Wihtout any content, we align the
- // bottom of the select to the bottom of the text. With content (In this
- // case the faked " ") we correctly align the middle of the select to the
- // middle of the text. It should be possible to remove this, just set
- // s.impl() into the text and have things align correctly...
- // crbug.com/485982
- is_empty_ = true;
- button_text_->ForceSetText(StringImpl::Create(" ", 1));
- } else {
- is_empty_ = false;
- button_text_->ForceSetText(s.Impl());
- }
- // LayoutMenuList::ControlClipRect() depends on inner_block_->ContentsSize().
- SetNeedsPaintPropertyUpdate();
- if (Layer())
- Layer()->SetNeedsCompositingInputsUpdate();
-}
-
-String LayoutMenuList::GetText() const {
- return button_text_ && !is_empty_ ? button_text_->GetText() : String();
-}
-
-PhysicalRect LayoutMenuList::ControlClipRect(
- const PhysicalOffset& additional_offset) const {
- // Clip to the intersection of the content box and the content box for the
- // inner box. This will leave room for the arrows which sit in the inner box
- // padding, and if the inner box ever spills out of the outer box, that will
- // get clipped too.
- PhysicalRect outer_box = PhysicalContentBoxRect();
- outer_box.offset += additional_offset;
-
- PhysicalRect inner_box(additional_offset + inner_block_->PhysicalLocation() +
- PhysicalOffset(inner_block_->PaddingLeft(),
- inner_block_->PaddingTop()),
- inner_block_->ContentSize());
-
- return Intersection(outer_box, inner_box);
-}
-
-void LayoutMenuList::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
- UpdateOptionsWidth();
-
- max_logical_width =
- std::max(options_width_,
- LayoutTheme::GetTheme().MinimumMenuListSize(StyleRef())) +
- inner_block_->PaddingLeft() + inner_block_->PaddingRight();
- if (!StyleRef().Width().IsPercentOrCalc())
- min_logical_width = max_logical_width;
- else
- min_logical_width = LayoutUnit();
-}
-
-void LayoutMenuList::ComputeLogicalHeight(
- LayoutUnit logical_height,
- LayoutUnit logical_top,
- LogicalExtentComputedValues& computed_values) const {
- if (StyleRef().HasEffectiveAppearance())
- logical_height = inner_block_height_ + BorderAndPaddingHeight();
- LayoutBox::ComputeLogicalHeight(logical_height, logical_top, computed_values);
-}
-
-void LayoutMenuList::DidSelectOption(HTMLOptionElement* option) {
- DidUpdateActiveOption(option);
-}
-
-void LayoutMenuList::DidUpdateActiveOption(HTMLOptionElement* option) {
- if (!GetDocument().ExistingAXObjectCache())
- return;
-
- int option_index = option ? option->index() : -1;
- if (last_active_index_ == option_index)
- return;
- last_active_index_ = option_index;
-
- // We skip sending accessiblity notifications for the very first option,
- // otherwise we get extra focus and select events that are undesired.
- if (!has_updated_active_option_) {
- has_updated_active_option_ = true;
- return;
- }
-
- GetDocument().ExistingAXObjectCache()->HandleUpdateActiveMenuOption(
- this, option_index);
-}
-
-LayoutUnit LayoutMenuList::ClientPaddingLeft() const {
- return PaddingLeft() + inner_block_->PaddingLeft();
-}
-
-LayoutUnit LayoutMenuList::ClientPaddingRight() const {
- return PaddingRight() + inner_block_->PaddingRight();
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_menu_list.h b/chromium/third_party/blink/renderer/core/layout/layout_menu_list.h
deleted file mode 100644
index ba3a7d5a62d..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/layout_menu_list.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * This file is part of the select element layoutObject in WebCore.
- *
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
- * All rights reserved.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_MENU_LIST_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_MENU_LIST_H_
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
-#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
-
-namespace blink {
-
-class HTMLOptionElement;
-class HTMLSelectElement;
-class LayoutText;
-
-class CORE_EXPORT LayoutMenuList final : public LayoutFlexibleBox {
- public:
- explicit LayoutMenuList(Element*);
- ~LayoutMenuList() override;
-
- HTMLSelectElement* SelectElement() const;
- void DidSelectOption(HTMLOptionElement*);
- String GetText() const;
-
- const char* GetName() const override { return "LayoutMenuList"; }
-
- LayoutUnit ClientPaddingLeft() const;
- LayoutUnit ClientPaddingRight() const;
-
- private:
- bool IsOfType(LayoutObjectType type) const override {
- return type == kLayoutObjectMenuList || LayoutFlexibleBox::IsOfType(type);
- }
- bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override;
-
- void AddChild(LayoutObject* new_child,
- LayoutObject* before_child = nullptr) override;
- void RemoveChild(LayoutObject*) override;
- bool CreatesAnonymousWrapper() const override { return true; }
-
- void UpdateFromElement() override;
-
- PhysicalRect ControlClipRect(const PhysicalOffset&) const override;
- bool HasControlClip() const override { return true; }
-
- void ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const override;
- void ComputeLogicalHeight(LayoutUnit logical_height,
- LayoutUnit logical_top,
- LogicalExtentComputedValues&) const override;
-
- void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
-
- bool HasLineIfEmpty() const override { return true; }
-
- // Flexbox defines baselines differently than regular blocks.
- // For backwards compatibility, menulists need to do the regular block
- // behavior.
- LayoutUnit BaselinePosition(FontBaseline baseline,
- bool first_line,
- LineDirectionMode direction,
- LinePositionMode position) const override {
- return LayoutBlock::BaselinePosition(baseline, first_line, direction,
- position);
- }
- LayoutUnit FirstLineBoxBaseline() const override {
- return LayoutBlock::FirstLineBoxBaseline();
- }
- LayoutUnit InlineBlockBaseline(LineDirectionMode direction) const override {
- return LayoutBlock::InlineBlockBaseline(direction);
- }
-
- void CreateInnerBlock();
- scoped_refptr<ComputedStyle> CreateInnerStyle();
- void UpdateInnerStyle();
- void AdjustInnerStyle(ComputedStyle&) const;
- bool HasOptionStyleChanged(const ComputedStyle& inner_style) const;
- void SetText(const String&);
- void UpdateInnerBlockHeight();
- void UpdateOptionsWidth() const;
- void SetIndexToSelectOnCancel(int list_index);
-
- void DidUpdateActiveOption(HTMLOptionElement*);
-
- LayoutText* button_text_;
- LayoutBlock* inner_block_;
-
- bool is_empty_ : 1;
- bool has_updated_active_option_ : 1;
- LayoutUnit inner_block_height_;
- // m_optionsWidth is calculated and cached on demand.
- // updateOptionsWidth() should be called before reading them.
- mutable int options_width_;
-
- int last_active_index_;
-
- scoped_refptr<const ComputedStyle> option_style_;
-};
-
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutMenuList, IsMenuList());
-
-} // namespace blink
-
-#endif
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
index 9b7976066aa..2c6e4fc788e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc
@@ -332,7 +332,7 @@ LayoutUnit LayoutMultiColumnFlowThread::MaxColumnLogicalHeight() const {
const LayoutBlockFlow* multicol_block = MultiColumnBlockFlow();
const Length& logical_max_height =
multicol_block->StyleRef().LogicalMaxHeight();
- if (!logical_max_height.IsMaxSizeNone()) {
+ if (!logical_max_height.IsNone()) {
LayoutUnit resolved_logical_max_height =
multicol_block->ComputeContentLogicalHeight(
kMaxSize, logical_max_height, LayoutUnit(-1));
@@ -611,7 +611,7 @@ bool LayoutMultiColumnFlowThread::RemoveSpannerPlaceholderIfNoLongerValid(
// We may have a new containing block, since we're no longer a spanner. Mark
// it for relayout.
spanner_object_in_flow_thread->ContainingBlock()
- ->SetNeedsLayoutAndPrefWidthsRecalc(
+ ->SetNeedsLayoutAndIntrinsicWidthsRecalc(
layout_invalidation_reason::kColumnsChanged);
// Now generate a column set for this ex-spanner, if needed and none is there
@@ -729,7 +729,7 @@ void LayoutMultiColumnFlowThread::CalculateColumnHeightAvailable() {
// have a definite height when they in fact don't.
LayoutBlockFlow* container = MultiColumnBlockFlow();
LayoutUnit column_height;
- if (container->HasDefiniteLogicalHeight() || container->IsLayoutView()) {
+ if (container->HasDefiniteLogicalHeight() || IsA<LayoutView>(container)) {
LogicalExtentComputedValues computed_values;
container->ComputeLogicalHeight(LayoutUnit(), container->LogicalTop(),
computed_values);
@@ -1332,7 +1332,7 @@ void LayoutMultiColumnFlowThread::ToggleSpannersInSubtree(
}
}
-void LayoutMultiColumnFlowThread::ComputePreferredLogicalWidths() {
+MinMaxSizes LayoutMultiColumnFlowThread::PreferredLogicalWidths() const {
// The min/max intrinsic widths calculated really tell how much space elements
// need when laid out inside the columns. In order to eventually end up with
// the desired column width, we need to convert them to values pertaining to
@@ -1343,28 +1343,22 @@ void LayoutMultiColumnFlowThread::ComputePreferredLogicalWidths() {
multicol_style->HasAutoColumnCount() ? 1 : multicol_style->ColumnCount());
LayoutUnit gap_extra((column_count - 1) *
ColumnGap(*multicol_style, LayoutUnit()));
+ MinMaxSizes sizes;
if (flow->HasOverrideIntrinsicContentLogicalWidth()) {
- min_preferred_logical_width_ = max_preferred_logical_width_ =
- flow->OverrideIntrinsicContentLogicalWidth();
- ClearPreferredLogicalWidthsDirty();
+ sizes = flow->OverrideIntrinsicContentLogicalWidth();
} else if (flow->ShouldApplySizeContainment()) {
- min_preferred_logical_width_ = max_preferred_logical_width_ = LayoutUnit();
- ClearPreferredLogicalWidthsDirty();
+ sizes = LayoutUnit();
} else {
- // Calculate and set new min_preferred_logical_width_ and
- // max_preferred_logical_width_.
- LayoutFlowThread::ComputePreferredLogicalWidths();
+ sizes = LayoutFlowThread::PreferredLogicalWidths();
}
LayoutUnit column_width;
if (multicol_style->HasAutoColumnWidth()) {
- min_preferred_logical_width_ =
- min_preferred_logical_width_ * column_count + gap_extra;
+ sizes.min_size = sizes.min_size * column_count + gap_extra;
} else {
column_width = LayoutUnit(multicol_style->ColumnWidth());
- min_preferred_logical_width_ =
- std::min(min_preferred_logical_width_, column_width);
+ sizes.min_size = std::min(sizes.min_size, column_width);
}
// Note that if column-count is auto here, we should resolve it to calculate
// the maximum intrinsic width, instead of pretending that it's 1. The only
@@ -1372,9 +1366,9 @@ void LayoutMultiColumnFlowThread::ComputePreferredLogicalWidths() {
// appropriate time or place for layout. The good news is that if height is
// unconstrained and there are no explicit breaks, the resolved column-count
// really should be 1.
- max_preferred_logical_width_ =
- std::max(max_preferred_logical_width_, column_width) * column_count +
- gap_extra;
+ sizes.max_size =
+ std::max(sizes.max_size, column_width) * column_count + gap_extra;
+ return sizes;
}
void LayoutMultiColumnFlowThread::ComputeLogicalHeight(
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h
index e0518872994..e09739b2a21 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h
@@ -317,7 +317,7 @@ class CORE_EXPORT LayoutMultiColumnFlowThread final
StyleDifference,
const ComputedStyle& old_style) override;
void ToggleSpannersInSubtree(LayoutBox*);
- void ComputePreferredLogicalWidths() override;
+ MinMaxSizes PreferredLogicalWidths() const override;
void ComputeLogicalHeight(LayoutUnit logical_height,
LayoutUnit logical_top,
LogicalExtentComputedValues&) const final;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
index 924dd0ea1db..05575c71fc9 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.cc
@@ -449,11 +449,8 @@ void LayoutMultiColumnSet::UpdateLayout() {
}
}
-void LayoutMultiColumnSet::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
- min_logical_width = flow_thread_->MinPreferredLogicalWidth();
- max_logical_width = flow_thread_->MaxPreferredLogicalWidth();
+MinMaxSizes LayoutMultiColumnSet::ComputeIntrinsicLogicalWidths() const {
+ return MinMaxSizes();
}
void LayoutMultiColumnSet::ComputeLogicalHeight(
@@ -534,6 +531,7 @@ void LayoutMultiColumnSet::ComputeVisualOverflow(
AddVisualOverflowFromFloats();
if (VisualOverflowRect() != previous_visual_overflow_rect) {
+ InvalidateIntersectionObserverCachedRects();
SetShouldCheckForPaintInvalidation();
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.h b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.h
index ed5ed54a877..6fdae46ff0c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_set.h
@@ -207,8 +207,7 @@ class CORE_EXPORT LayoutMultiColumnSet final : public LayoutBlockFlow {
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
void UpdateLayout() override;
- void ComputeIntrinsicLogicalWidths(LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const final;
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const final;
void AttachToFlowThread();
void DetachFromFlowThread();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
index d08cd063337..10b19d72df8 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.cc
@@ -72,7 +72,7 @@ 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(
+ layout_object_in_flow_thread_->SetNeedsLayoutAndIntrinsicWidthsRecalc(
layout_invalidation_reason::kColumnsChanged);
}
@@ -83,7 +83,7 @@ void LayoutMultiColumnSpannerPlaceholder::WillBeRemovedFromTree() {
// 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(
+ ex_spanner->SetNeedsLayoutAndIntrinsicWidthsRecalc(
layout_invalidation_reason::kColumnsChanged);
}
LayoutBox::WillBeRemovedFromTree();
@@ -101,7 +101,7 @@ void LayoutMultiColumnSpannerPlaceholder::RecalcVisualOverflow() {
layout_object_in_flow_thread_->VisualOverflowRect());
}
-LayoutUnit LayoutMultiColumnSpannerPlaceholder::MinPreferredLogicalWidth()
+MinMaxSizes LayoutMultiColumnSpannerPlaceholder::PreferredLogicalWidths()
const {
// There should be no contribution from a spanner if the multicol container is
// size-contained. Normally we'd stop at the object that has contain:size
@@ -111,17 +111,8 @@ LayoutUnit LayoutMultiColumnSpannerPlaceholder::MinPreferredLogicalWidth()
// siblings of the flow thread, we need this check.
// TODO(crbug.com/953919): What should we return for display-locked content?
if (MultiColumnBlockFlow()->ShouldApplySizeContainment())
- return LayoutUnit();
- return layout_object_in_flow_thread_->MinPreferredLogicalWidth();
-}
-
-LayoutUnit LayoutMultiColumnSpannerPlaceholder::MaxPreferredLogicalWidth()
- const {
- // See above.
- // TODO(crbug.com/953919): What should we return for display-locked content?
- if (MultiColumnBlockFlow()->ShouldApplySizeContainment())
- return LayoutUnit();
- return layout_object_in_flow_thread_->MaxPreferredLogicalWidth();
+ return MinMaxSizes();
+ return layout_object_in_flow_thread_->PreferredLogicalWidths();
}
void LayoutMultiColumnSpannerPlaceholder::UpdateLayout() {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
index c4018fbc0ae..a2575a39b8c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h
@@ -60,8 +60,7 @@ class LayoutMultiColumnSpannerPlaceholder final : public LayoutBox {
void WillBeRemovedFromTree() override;
bool NeedsPreferredWidthsRecalculation() const override;
void RecalcVisualOverflow() override;
- LayoutUnit MinPreferredLogicalWidth() const override;
- LayoutUnit MaxPreferredLogicalWidth() const override;
+ MinMaxSizes PreferredLogicalWidths() const override;
void UpdateLayout() override;
void ComputeLogicalHeight(LayoutUnit logical_height,
LayoutUnit logical_top,
@@ -75,6 +74,11 @@ class LayoutMultiColumnSpannerPlaceholder final : public LayoutBox {
private:
LayoutMultiColumnSpannerPlaceholder(LayoutBox*);
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const final {
+ NOTREACHED();
+ return MinMaxSizes();
+ }
+
// The actual column-span:all layoutObject inside the flow thread.
LayoutBox* layout_object_in_flow_thread_;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object.cc b/chromium/third_party/blink/renderer/core/layout/layout_object.cc
index a8574b15657..9d6d6f718aa 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object.cc
@@ -33,7 +33,7 @@
#include <utility>
#include "base/allocator/partition_allocator/partition_alloc.h"
-#include "third_party/blink/public/platform/web_scroll_into_view_params.h"
+#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/animation/element_animations.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
@@ -55,11 +55,14 @@
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
+#include "third_party/blink/renderer/core/html/forms/html_select_element.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html/html_html_element.h"
#include "third_party/blink/renderer/core/html/html_table_cell_element.h"
#include "third_party/blink/renderer/core/html/html_table_element.h"
+#include "third_party/blink/renderer/core/html/image_document.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
+#include "third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h"
#include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/layout_counter.h"
@@ -74,6 +77,7 @@
#include "third_party/blink/renderer/core/layout/layout_image_resource_style_image.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_list_item.h"
+#include "third_party/blink/renderer/core/layout/layout_list_marker.h"
#include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h"
#include "third_party/blink/renderer/core/layout/layout_object_factory.h"
#include "third_party/blink/renderer/core/layout/layout_table_caption.h"
@@ -237,11 +241,10 @@ LayoutObject* LayoutObject::CreateObject(Element* element,
case EDisplay::kBlock:
case EDisplay::kFlowRoot:
case EDisplay::kInlineBlock:
+ case EDisplay::kListItem:
case EDisplay::kMath:
case EDisplay::kInlineMath:
return LayoutObjectFactory::CreateBlockFlow(*element, style, legacy);
- case EDisplay::kListItem:
- return LayoutObjectFactory::CreateListItem(*element, style, legacy);
case EDisplay::kTable:
case EDisplay::kInlineTable:
return new LayoutTable(element);
@@ -260,9 +263,14 @@ LayoutObject* LayoutObject::CreateObject(Element* element,
return LayoutObjectFactory::CreateTableCaption(*element, style, legacy);
case EDisplay::kWebkitBox:
case EDisplay::kWebkitInlineBox:
+ if (style.IsDeprecatedWebkitBoxWithVerticalLineClamp() &&
+ RuntimeEnabledFeatures::BlockFlowHandlesWebkitLineClampEnabled()) {
+ return LayoutObjectFactory::CreateBlockForLineClamp(*element, style,
+ legacy);
+ }
if (style.IsDeprecatedFlexboxUsingFlexLayout())
return new LayoutFlexibleBox(element);
- return new LayoutDeprecatedFlexibleBox(*element);
+ return new LayoutDeprecatedFlexibleBox(element);
case EDisplay::kFlex:
case EDisplay::kInlineFlex:
UseCounter::Count(element->GetDocument(), WebFeature::kCSSFlexibleBox);
@@ -307,6 +315,7 @@ LayoutObject::LayoutObject(Node* node)
LayoutObject::~LayoutObject() {
#if DCHECK_IS_ON()
DCHECK(!has_ax_object_);
+ DCHECK(BeingDestroyed());
#endif
InstanceCounters::DecrementCounter(InstanceCounters::kLayoutObjectCounter);
}
@@ -361,6 +370,22 @@ bool LayoutObject::RequiresAnonymousTableWrappers(
return false;
}
+#if DCHECK_IS_ON()
+
+void LayoutObject::AssertClearedPaintInvalidationFlags() const {
+ if (!PaintInvalidationStateIsDirty() ||
+ PrePaintBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren))
+ return;
+ // NG text objects are exempt, as pre-paint walking doesn't visit those with
+ // no paint effects (only white-space, for instance).
+ if (IsText() && IsLayoutNGObject())
+ return;
+ ShowLayoutTreeForThis();
+ NOTREACHED();
+}
+
+#endif // DCHECK_IS_ON()
+
DISABLE_CFI_PERF
void LayoutObject::AddChild(LayoutObject* new_child,
LayoutObject* before_child) {
@@ -467,20 +492,26 @@ LayoutObject* LayoutObject::NextInPreOrder() const {
}
bool LayoutObject::HasClipRelatedProperty() const {
- // TODO(trchen): Refactor / remove this function.
// This function detects a bunch of properties that can potentially affect
- // clip inheritance chain. However such generalization is practially useless
+ // clip inheritance chain. However such generalization is practically useless
// because these properties change clip inheritance in different way that
// needs to be handled explicitly.
// CSS clip applies clip to the current element and all descendants.
- // CSS overflow clip applies only to containg-block descendants.
+ // CSS overflow clip applies only to containing-block descendants.
// CSS contain:paint applies to all descendants by making itself a containing
// block for all descendants.
// CSS clip-path/mask/filter induces a stacking context and applies inherited
// clip to that stacking context, while resetting clip for descendants. This
// special behavior is already handled elsewhere.
- if (HasClip() || HasOverflowClip() || ShouldApplyPaintContainment())
+ if (HasClip() || HasOverflowClip())
+ return true;
+ // Paint containment establishes isolation which creates clip isolation nodes.
+ // Style & Layout containment also establish isolation (see
+ // |NeedsIsolationNodes| in PaintPropertyTreeBuilder).
+ if (ShouldApplyPaintContainment() ||
+ (ShouldApplyStyleContainment() && ShouldApplyLayoutContainment())) {
return true;
+ }
if (IsBox() && ToLayoutBox(this)->HasControlClip())
return true;
return false;
@@ -744,19 +775,18 @@ bool LayoutObject::IsFixedPositionObjectInPagedMedia() const {
PhysicalRect LayoutObject::ScrollRectToVisible(
const PhysicalRect& rect,
- const WebScrollIntoViewParams& params) {
+ mojom::blink::ScrollIntoViewParamsPtr params) {
LayoutBox* enclosing_box = EnclosingBox();
if (!enclosing_box)
return rect;
GetDocument().GetFrame()->GetSmoothScrollSequencer().AbortAnimations();
GetDocument().GetFrame()->GetSmoothScrollSequencer().SetScrollType(
- params.GetScrollType());
- WebScrollIntoViewParams new_params(params);
- new_params.is_for_scroll_sequence |=
- params.GetScrollType() == kProgrammaticScroll;
+ params->type);
+ params->is_for_scroll_sequence |=
+ params->type == mojom::blink::ScrollType::kProgrammatic;
PhysicalRect new_location =
- enclosing_box->ScrollRectToVisibleRecursive(rect, new_params);
+ enclosing_box->ScrollRectToVisibleRecursive(rect, std::move(params));
GetDocument().GetFrame()->GetSmoothScrollSequencer().RunQueuedAnimations();
return new_location;
@@ -855,6 +885,12 @@ static inline bool ObjectIsRelayoutBoundary(const LayoutObject* object) {
// FIXME: In future it may be possible to broaden these conditions in order to
// improve performance.
+ // Positioned objects always have self-painting layers and are safe to use as
+ // relayout boundaries.
+ bool is_svg_root = object->IsSVGRoot();
+ if (!object->IsPositioned() && !is_svg_root)
+ return false;
+
// LayoutInline can't be relayout roots since LayoutBlockFlow is responsible
// for layouting them.
if (object->IsLayoutInline())
@@ -872,6 +908,17 @@ static inline bool ObjectIsRelayoutBoundary(const LayoutObject* object) {
(style->HasAutoLeftAndRight() || style->HasAutoTopAndBottom()))
return false;
+ if (UNLIKELY(RuntimeEnabledFeatures::LayoutNGFragmentTraversalEnabled() &&
+ object->IsLayoutNGObject())) {
+ // We need to rebuild the entire NG fragment spine all the way from the root
+ // (or at least the nearest self-painting paint layer), since we traverse
+ // the fragments, and not objects. Fragment painting is initiated at
+ // self-painting layers, but we cannot check if it's a self-painting layer
+ // now, because it may cease to be one during layout (an object with clipped
+ // overflow that no longer has content that requires it to clip).
+ return false;
+ }
+
if (object->ShouldApplyLayoutContainment() &&
object->ShouldApplySizeContainment())
return true;
@@ -887,7 +934,7 @@ static inline bool ObjectIsRelayoutBoundary(const LayoutObject* object) {
if (object->IsTextControl())
return true;
- if (object->IsSVGRoot())
+ if (is_svg_root)
return true;
if (!object->HasOverflowClip())
@@ -1016,7 +1063,7 @@ void LayoutObject::MarkContainerChainForLayout(bool schedule_relayout,
// Don't mark the outermost object of an unrooted subtree. That object will
// be marked when the subtree is added to the document.
LayoutObject* container = object->Container();
- if (!container && !object->IsLayoutView())
+ if (!container && !IsA<LayoutView>(object))
return;
if (!last->IsTextOrSVGChild() && last->StyleRef().HasOutOfFlowPosition()) {
object = last->ContainingBlock();
@@ -1112,16 +1159,33 @@ void LayoutObject::CheckBlockPositionedObjectsNeedLayout() {
}
#endif
-void LayoutObject::SetPreferredLogicalWidthsDirty(
+void LayoutObject::SetIntrinsicLogicalWidthsDirty(
MarkingBehavior mark_parents) {
- bitfields_.SetPreferredLogicalWidthsDirty(true);
+ bitfields_.SetIntrinsicLogicalWidthsDirty(true);
if (mark_parents == kMarkContainerChain &&
(IsText() || !StyleRef().HasOutOfFlowPosition()))
- InvalidateContainerPreferredLogicalWidths();
+ InvalidateContainerIntrinsicLogicalWidths();
}
-void LayoutObject::ClearPreferredLogicalWidthsDirty() {
- bitfields_.SetPreferredLogicalWidthsDirty(false);
+void LayoutObject::ClearIntrinsicLogicalWidthsDirty() {
+ bitfields_.SetIntrinsicLogicalWidthsDirty(false);
+}
+
+void LayoutObject::InvalidateSubtreeLayoutForFontUpdates() {
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
+ layout_invalidation_reason::kFontsChanged);
+ for (LayoutObject* child = SlowFirstChild(); child;
+ child = child->NextSibling()) {
+ child->InvalidateSubtreeLayoutForFontUpdates();
+ }
+}
+
+void LayoutObject::InvalidateIntersectionObserverCachedRects() {
+ if (GetNode() && GetNode()->IsElementNode()) {
+ if (auto* data = To<Element>(GetNode())->IntersectionObserverData()) {
+ data->InvalidateCachedRects();
+ }
+ }
}
static inline bool NGKeepInvalidatingBeyond(LayoutObject* o) {
@@ -1131,28 +1195,30 @@ static inline bool NGKeepInvalidatingBeyond(LayoutObject* o) {
// next block container.
// Atomic inlines do not have this problem as they are treated like blocks
// in this context.
+ // There's a similar issue for flow thread objects, as they are invisible to
+ // LayoutNG.
if (!RuntimeEnabledFeatures::LayoutNGEnabled())
return false;
- if (o->IsLayoutInline() || o->IsText())
+ if (o->IsLayoutInline() || o->IsText() || o->IsLayoutFlowThread())
return true;
return false;
}
-inline void LayoutObject::InvalidateContainerPreferredLogicalWidths() {
+inline void LayoutObject::InvalidateContainerIntrinsicLogicalWidths() {
// In order to avoid pathological behavior when inlines are deeply nested, we
// do include them in the chain that we mark dirty (even though they're kind
// of irrelevant).
LayoutObject* o = IsTableCell() ? ContainingBlock() : Container();
while (o &&
- (!o->PreferredLogicalWidthsDirty() || NGKeepInvalidatingBeyond(o))) {
+ (!o->IntrinsicLogicalWidthsDirty() || NGKeepInvalidatingBeyond(o))) {
// Don't invalidate the outermost object of an unrooted subtree. That object
// will be invalidated when the subtree is added to the document.
LayoutObject* container =
o->IsTableCell() ? o->ContainingBlock() : o->Container();
- if (!container && !o->IsLayoutView())
+ if (!container && !IsA<LayoutView>(o))
break;
- o->bitfields_.SetPreferredLogicalWidthsDirty(true);
+ o->bitfields_.SetIntrinsicLogicalWidthsDirty(true);
// A positioned object has no effect on the min/max width of its containing
// block ever. We can optimize this case and not go up any further.
if (o->StyleRef().HasOutOfFlowPosition())
@@ -1187,24 +1253,6 @@ LayoutObject* LayoutObject::ContainerForFixedPosition(
});
}
-LayoutBlock* LayoutObject::FindNonAnonymousContainingBlock(
- LayoutObject* container,
- AncestorSkipInfo* skip_info) {
- // For inlines, we return the nearest non-anonymous enclosing
- // block. We don't try to return the inline itself. This allows us to avoid
- // having a positioned objects list in all LayoutInlines and lets us return a
- // strongly-typed LayoutBlock* result from this method. The
- // LayoutObject::Container() method can actually be used to obtain the inline
- // directly.
- if (container && !container->IsLayoutBlock())
- container = container->ContainingBlock(skip_info);
-
- while (container && container->IsAnonymousBlock())
- container = container->ContainingBlock(skip_info);
-
- return DynamicTo<LayoutBlock>(container);
-}
-
LayoutBlock* LayoutObject::ContainingBlockForAbsolutePosition(
AncestorSkipInfo* skip_info) const {
auto* container = ContainerForAbsolutePosition(skip_info);
@@ -1250,6 +1298,24 @@ LayoutBlock* LayoutObject::ContainingBlock(AncestorSkipInfo* skip_info) const {
return DynamicTo<LayoutBlock>(object);
}
+LayoutBlock* LayoutObject::FindNonAnonymousContainingBlock(
+ LayoutObject* container,
+ AncestorSkipInfo* skip_info) {
+ // For inlines, we return the nearest non-anonymous enclosing
+ // block. We don't try to return the inline itself. This allows us to avoid
+ // having a positioned objects list in all LayoutInlines and lets us return a
+ // strongly-typed LayoutBlock* result from this method. The
+ // LayoutObject::Container() method can actually be used to obtain the inline
+ // directly.
+ if (container && !container->IsLayoutBlock())
+ container = container->ContainingBlock(skip_info);
+
+ while (container && container->IsAnonymousBlock())
+ container = container->ContainingBlock(skip_info);
+
+ return DynamicTo<LayoutBlock>(container);
+}
+
bool LayoutObject::ComputeIsFixedContainer(const ComputedStyle* style) const {
if (!style)
return false;
@@ -1267,7 +1333,7 @@ bool LayoutObject::ComputeIsFixedContainer(const ComputedStyle* style) const {
// select elements inside that are created by user agent shadow DOM, and we
// have (C++) code that assumes that the elements are indeed contained by the
// text control. So just make sure this is the case.
- if (IsLayoutView() || IsSVGForeignObject() || IsTextControl())
+ if (IsA<LayoutView>(this) || IsSVGForeignObject() || IsTextControl())
return true;
// https://www.w3.org/TR/css-transforms-1/#containing-block-for-all-descendants
if (style->HasTransformRelatedProperty()) {
@@ -1334,16 +1400,6 @@ PhysicalRect LayoutObject::AbsoluteBoundingBoxRectForScrollIntoView() const {
return rect;
}
-FloatRect LayoutObject::AbsoluteBoundingBoxRectForRange(
- const EphemeralRange& range) {
- if (range.IsNull() || !range.StartPosition().ComputeContainerNode())
- return FloatRect();
-
- range.GetDocument().UpdateStyleAndLayout();
-
- return ComputeTextFloatRect(range);
-}
-
void LayoutObject::AddAbsoluteRectForLayer(IntRect& result) {
if (HasLayer())
result.Unite(AbsoluteBoundingBoxRect());
@@ -1412,6 +1468,7 @@ void LayoutObject::RecalcNormalFlowChildVisualOverflowIfNeeded() {
}
const LayoutBoxModelObject* LayoutObject::EnclosingCompositedContainer() const {
+ DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
LayoutBoxModelObject* container = nullptr;
// FIXME: CompositingState is not necessarily up to date for many callers of
// this function.
@@ -1495,7 +1552,7 @@ String LayoutObject::DecoratedName() const {
name.Append(" (anonymous)");
// FIXME: Remove the special case for LayoutView here (requires rebaseline of
// all tests).
- if (IsOutOfFlowPositioned() && !IsLayoutView())
+ if (IsOutOfFlowPositioned() && !IsA<LayoutView>(this))
name.Append(" (positioned)");
if (IsRelPositioned())
name.Append(" (relative positioned)");
@@ -1626,14 +1683,12 @@ bool LayoutObject::MapToVisualRectInAncestorSpaceInternalFastPath(
if (ancestor == this)
return true;
- const auto* property_container = this;
AncestorSkipInfo skip_info(ancestor);
- while (!property_container->FirstFragment().HasLocalBorderBoxProperties()) {
- property_container = property_container->Container(&skip_info);
- if (!property_container || skip_info.AncestorSkipped() ||
- property_container->FirstFragment().NextFragment())
- return false;
- }
+ PropertyTreeState container_properties = PropertyTreeState::Uninitialized();
+ const LayoutObject* property_container =
+ GetPropertyContainer(&skip_info, &container_properties);
+ if (!property_container)
+ return false;
// This works because it's not possible to have any intervening clips,
// effects, transforms between |this| and |property_container|, and therefore
@@ -1643,13 +1698,9 @@ bool LayoutObject::MapToVisualRectInAncestorSpaceInternalFastPath(
rect.Move(FirstFragment().PaintOffset());
if (property_container != ancestor) {
FloatClipRect clip_rect((FloatRect(rect)));
- const auto& local_state =
- property_container == this
- ? FirstFragment().LocalBorderBoxProperties()
- : property_container->FirstFragment().ContentsProperties();
intersects = GeometryMapper::LocalToAncestorVisualRect(
- local_state, ancestor->FirstFragment().ContentsProperties(), clip_rect,
- kIgnorePlatformOverlayScrollbarSize,
+ container_properties, ancestor->FirstFragment().ContentsProperties(),
+ clip_rect, kIgnorePlatformOverlayScrollbarSize,
(visual_rect_flags & kEdgeInclusive) ? kInclusiveIntersect
: kNonInclusiveIntersect);
rect = PhysicalRect::EnclosingRect(clip_rect.Rect());
@@ -1707,6 +1758,27 @@ bool LayoutObject::MapToVisualRectInAncestorSpaceInternal(
return true;
}
+const LayoutObject* LayoutObject::GetPropertyContainer(
+ AncestorSkipInfo* skip_info,
+ PropertyTreeState* container_properties) const {
+ const LayoutObject* property_container = this;
+ while (!property_container->FirstFragment().HasLocalBorderBoxProperties()) {
+ property_container = property_container->Container(skip_info);
+ if (!property_container || (skip_info && skip_info->AncestorSkipped()) ||
+ property_container->FirstFragment().NextFragment())
+ return nullptr;
+ }
+ if (container_properties) {
+ if (property_container == this) {
+ *container_properties = FirstFragment().LocalBorderBoxProperties();
+ } else {
+ *container_properties =
+ property_container->FirstFragment().ContentsProperties();
+ }
+ }
+ return property_container;
+}
+
HitTestResult LayoutObject::HitTestForOcclusion(
const PhysicalRect& hit_rect) const {
LocalFrame* frame = GetDocument().GetFrame();
@@ -1893,26 +1965,20 @@ StyleDifference LayoutObject::AdjustStyleDifference(
diff.SetNeedsFullLayout();
}
- // TODO(wangxianzhu): We may avoid subtree paint invalidation on CSS clip
- // change for CAP.
- if (diff.CssClipChanged())
- diff.SetNeedsPaintInvalidationSubtree();
-
// Optimization: for decoration/color property changes, invalidation is only
// needed if we have style or text affected by these properties.
- if (diff.TextDecorationOrColorChanged() &&
- !diff.NeedsFullPaintInvalidation()) {
+ if (diff.TextDecorationOrColorChanged() && !diff.NeedsPaintInvalidation()) {
if (StyleRef().HasBorderColorReferencingCurrentColor() ||
StyleRef().HasOutlineWithCurrentColor() ||
StyleRef().HasBackgroundRelatedColorReferencingCurrentColor() ||
// Skip any text nodes that do not contain text boxes. Whitespace cannot
// be skipped or we will miss invalidating decorations (e.g.,
// underlines).
- (IsText() && !IsBR() && ToLayoutText(this)->HasTextBoxes()) ||
+ (IsText() && !IsBR() && ToLayoutText(this)->HasInlineFragments()) ||
(IsSVG() && StyleRef().SvgStyle().IsFillColorCurrentColor()) ||
(IsSVG() && StyleRef().SvgStyle().IsStrokeColorCurrentColor()) ||
IsListMarker() || IsDetailsMarker())
- diff.SetNeedsPaintInvalidationObject();
+ diff.SetNeedsPaintInvalidation();
}
// The answer to layerTypeRequired() for plugins, iframes, and canvas can
@@ -1956,7 +2022,8 @@ void LayoutObject::SetPseudoElementStyle(
SetStyle(std::move(pseudo_style));
}
-void LayoutObject::MarkContainerChainForOverflowRecalcIfNeeded() {
+void LayoutObject::MarkContainerChainForOverflowRecalcIfNeeded(
+ bool mark_container_chain_layout_overflow_recalc) {
LayoutObject* object = this;
do {
// Cell and row need to propagate the flag to their containing section and
@@ -1966,25 +2033,53 @@ void LayoutObject::MarkContainerChainForOverflowRecalcIfNeeded() {
? object->Parent()
: object->Container();
if (object) {
- object->SetChildNeedsLayoutOverflowRecalc();
- object->MarkSelfPaintingLayerForVisualOverflowRecalc();
+ bool already_needs_layout_overflow_recalc = false;
+ if (mark_container_chain_layout_overflow_recalc) {
+ already_needs_layout_overflow_recalc =
+ object->ChildNeedsLayoutOverflowRecalc();
+ if (!already_needs_layout_overflow_recalc)
+ object->SetChildNeedsLayoutOverflowRecalc();
+ }
+
+ if (object->HasLayer()) {
+ auto* box_model_object = ToLayoutBoxModelObject(object);
+ if (box_model_object->HasSelfPaintingLayer()) {
+ auto* layer = box_model_object->Layer();
+ if (layer->NeedsVisualOverflowRecalc()) {
+ if (already_needs_layout_overflow_recalc)
+ return;
+ } else {
+ layer->SetNeedsVisualOverflowRecalc();
+ }
+ }
+ }
}
} while (object);
}
-void LayoutObject::SetNeedsVisualOverflowAndPaintInvalidation() {
+void LayoutObject::SetNeedsOverflowRecalc(
+ OverflowRecalcType overflow_recalc_type) {
+ bool mark_container_chain_layout_overflow_recalc =
+ !SelfNeedsLayoutOverflowRecalc();
+
+ if (overflow_recalc_type ==
+ OverflowRecalcType::kLayoutAndVisualOverflowRecalc) {
+ SetSelfNeedsLayoutOverflowRecalc();
+ }
+
+ DCHECK(overflow_recalc_type ==
+ OverflowRecalcType::kOnlyVisualOverflowRecalc ||
+ overflow_recalc_type ==
+ OverflowRecalcType::kLayoutAndVisualOverflowRecalc);
SetShouldCheckForPaintInvalidation();
MarkSelfPaintingLayerForVisualOverflowRecalc();
-}
-
-void LayoutObject::SetNeedsOverflowRecalc() {
- bool needed_recalc = SelfNeedsLayoutOverflowRecalc();
- SetSelfNeedsLayoutOverflowRecalc();
- SetNeedsVisualOverflowAndPaintInvalidation();
- if (!needed_recalc)
- MarkContainerChainForOverflowRecalcIfNeeded();
+ if (mark_container_chain_layout_overflow_recalc) {
+ MarkContainerChainForOverflowRecalcIfNeeded(
+ overflow_recalc_type ==
+ OverflowRecalcType::kLayoutAndVisualOverflowRecalc);
+ }
}
DISABLE_CFI_PERF
@@ -2046,7 +2141,7 @@ void LayoutObject::SetStyle(scoped_refptr<const ComputedStyle> style,
if (!diff.NeedsFullLayout()) {
if (updated_diff.NeedsFullLayout()) {
- SetNeedsLayoutAndPrefWidthsRecalc(
+ SetNeedsLayoutAndIntrinsicWidthsRecalc(
layout_invalidation_reason::kStyleChange);
} else if (updated_diff.NeedsPositionedMovementLayout()) {
SetNeedsPositionedMovementLayout();
@@ -2060,32 +2155,34 @@ void LayoutObject::SetStyle(scoped_refptr<const ComputedStyle> style,
container->SetNeedsOverflowRecalc();
}
- if (diff.NeedsRecomputeOverflow() && !NeedsLayout()) {
- // TODO(rhogan): Make inlines capable of recomputing overflow too.
- if (IsLayoutBlock()) {
- SetNeedsOverflowRecalc();
- } else {
- SetNeedsLayoutAndPrefWidthsRecalc(
+ if (diff.NeedsRecomputeVisualOverflow()) {
+ if (!IsLayoutNGObject() && !IsLayoutBlock() && !NeedsLayout()) {
+ // TODO(rego): This is still needed because RecalcVisualOverflow() does
+ // not actually compute the visual overflow for inline elements (legacy
+ // layout). However in LayoutNG RecalcInlineChildrenInkOverflow() is
+ // called and visual overflow is recomputed properly so we don't need this
+ // (see crbug.com/1043927).
+ SetNeedsLayoutAndIntrinsicWidthsRecalc(
layout_invalidation_reason::kStyleChange);
+ } else {
+ PaintingLayer()->SetNeedsVisualOverflowRecalc();
+ SetShouldCheckForPaintInvalidation();
}
}
- if (diff.NeedsPaintInvalidationSubtree() ||
- updated_diff.NeedsPaintInvalidationSubtree()) {
- SetSubtreeShouldDoFullPaintInvalidation();
- } else if (diff.NeedsPaintInvalidationObject() ||
- updated_diff.NeedsPaintInvalidationObject()) {
- // TODO(wangxianzhu): For now LayoutSVGRoot::localVisualRect() depends on
- // several styles. Refactor to avoid this special case.
- if (IsSVGRoot())
+ if (diff.NeedsPaintInvalidation() || updated_diff.NeedsPaintInvalidation()) {
+ if (IsSVGRoot()) {
+ // LayoutSVGRoot::LocalVisualRect() depends on some styles.
SetShouldDoFullPaintInvalidation();
- else
+ } else {
+ // We'll set needing geometry change later if the style change does cause
+ // possible layout change or visual overflow change.
SetShouldDoFullPaintInvalidationWithoutGeometryChange();
+ }
}
- if ((diff.NeedsPaintInvalidationObject() ||
- diff.NeedsPaintInvalidationSubtree()) &&
- old_style && !old_style->ClipPathDataEquivalent(*style_)) {
+ if (diff.NeedsPaintInvalidation() && old_style &&
+ !old_style->ClipPathDataEquivalent(*style_)) {
InvalidateClipPathCache();
PaintingLayer()->SetNeedsCompositingInputsUpdate();
}
@@ -2280,7 +2377,7 @@ void LayoutObject::StyleWillChange(StyleDifference diff,
// Elements may inherit touch action from parent frame, so we need to report
// touchstart handler if the root layout object has non-auto effective touch
// action.
- TouchAction old_touch_action = TouchAction::kTouchActionAuto;
+ TouchAction old_touch_action = TouchAction::kAuto;
bool is_document_element = GetNode() && IsDocumentElement();
if (style_) {
old_touch_action = is_document_element ? style_->GetEffectiveTouchAction()
@@ -2290,11 +2387,11 @@ void LayoutObject::StyleWillChange(StyleDifference diff,
? new_style.GetEffectiveTouchAction()
: new_style.GetTouchAction();
if (GetNode() && !GetNode()->IsTextNode() &&
- (old_touch_action == TouchAction::kTouchActionAuto) !=
- (new_touch_action == TouchAction::kTouchActionAuto)) {
+ (old_touch_action == TouchAction::kAuto) !=
+ (new_touch_action == TouchAction::kAuto)) {
EventHandlerRegistry& registry =
GetDocument().GetFrame()->GetEventHandlerRegistry();
- if (new_touch_action != TouchAction::kTouchActionAuto) {
+ if (new_touch_action != TouchAction::kAuto) {
registry.DidAddEventHandler(*GetNode(),
EventHandlerRegistry::kTouchAction);
} else {
@@ -2342,6 +2439,22 @@ void LayoutObject::SetScrollAnchorDisablingStyleChangedOnAncestor() {
}
}
+static void ClearAncestorScrollAnchors(LayoutObject* layout_object) {
+ PaintLayer* layer = nullptr;
+ if (LayoutObject* parent = layout_object->Parent())
+ layer = parent->EnclosingLayer();
+
+ while (layer) {
+ if (PaintLayerScrollableArea* scrollable_area =
+ layer->GetScrollableArea()) {
+ ScrollAnchor* anchor = scrollable_area->GetScrollAnchor();
+ DCHECK(anchor);
+ anchor->Clear();
+ }
+ layer = layer->Parent();
+ }
+}
+
void LayoutObject::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) {
// First assume the outline will be affected. It may be updated when we know
@@ -2372,7 +2485,8 @@ void LayoutObject::StyleDidChange(StyleDifference diff,
MarkContainerChainForLayout();
}
- SetNeedsLayoutAndPrefWidthsRecalc(layout_invalidation_reason::kStyleChange);
+ SetNeedsLayoutAndIntrinsicWidthsRecalc(
+ layout_invalidation_reason::kStyleChange);
} else if (diff.NeedsPositionedMovementLayout()) {
SetNeedsPositionedMovementLayout();
}
@@ -2394,7 +2508,7 @@ void LayoutObject::StyleDidChange(StyleDifference diff,
}
}
- if (diff.NeedsFullPaintInvalidation() && old_style) {
+ if (diff.NeedsPaintInvalidation() && old_style) {
if (ResolveColor(*old_style, GetCSSPropertyBackgroundColor()) !=
ResolveColor(GetCSSPropertyBackgroundColor()) ||
old_style->BackgroundLayers() != StyleRef().BackgroundLayers())
@@ -2409,6 +2523,10 @@ void LayoutObject::StyleDidChange(StyleDifference diff,
AddSubtreePaintPropertyUpdateReason(
SubtreePaintPropertyUpdateReason::kTransformStyleChanged);
}
+
+ if (old_style && old_style->OverflowAnchor() != StyleRef().OverflowAnchor()) {
+ ClearAncestorScrollAnchors(this);
+ }
}
void LayoutObject::ApplyPseudoElementStyleChanges(
@@ -2441,12 +2559,12 @@ void LayoutObject::ApplyFirstLineChanges(const ComputedStyle* old_style) {
}
}
if (!has_diff) {
- diff.SetNeedsPaintInvalidationObject();
+ diff.SetNeedsPaintInvalidation();
diff.SetNeedsFullLayout();
}
- if (BehavesLikeBlockContainer() && (diff.NeedsFullPaintInvalidation() ||
- diff.TextDecorationOrColorChanged())) {
+ if (BehavesLikeBlockContainer() &&
+ (diff.NeedsPaintInvalidation() || diff.TextDecorationOrColorChanged())) {
if (auto* first_line_container =
To<LayoutBlock>(this)->NearestInnerBlockWithFirstLine())
first_line_container->SetShouldDoFullPaintInvalidationForFirstLine();
@@ -2455,7 +2573,8 @@ void LayoutObject::ApplyFirstLineChanges(const ComputedStyle* old_style) {
if (diff.NeedsLayout()) {
if (diff.NeedsFullLayout())
SetNeedsCollectInlines();
- SetNeedsLayoutAndPrefWidthsRecalc(layout_invalidation_reason::kStyleChange);
+ SetNeedsLayoutAndIntrinsicWidthsRecalc(
+ layout_invalidation_reason::kStyleChange);
}
}
@@ -2481,15 +2600,18 @@ void LayoutObject::PropagateStyleToAnonymousChildren() {
child_block_flow->IsAnonymousBlockContinuation())
new_style->SetPosition(child->StyleRef().GetPosition());
- if (child->IsLayoutNGListMarker())
- new_style->SetWhiteSpace(child->StyleRef().WhiteSpace());
-
UpdateAnonymousChildStyle(child, *new_style);
child->SetStyle(std::move(new_style));
}
- if (StyleRef().StyleType() == kPseudoIdNone)
+ PseudoId pseudo_id = StyleRef().StyleType();
+ if (pseudo_id == kPseudoIdNone)
+ return;
+
+ // Don't propagate style from markers with 'content: normal' because it's not
+ // needed and it would be slow.
+ if (pseudo_id == kPseudoIdMarker && StyleRef().ContentBehavesAsNormal())
return;
// Propagate style from pseudo elements to generated content. We skip children
@@ -2681,10 +2803,10 @@ void LayoutObject::MapLocalToAncestor(const LayoutBoxModelObject* ancestor,
: TransformState::kFlattenTransform);
// If the ancestor is fixed, then the rect is already in its coordinates so
// doesn't need viewport-adjusting.
+ auto* layout_view = DynamicTo<LayoutView>(container);
if (ancestor->StyleRef().GetPosition() != EPosition::kFixed &&
- container->IsLayoutView() &&
- StyleRef().GetPosition() == EPosition::kFixed) {
- transform_state.Move(ToLayoutView(container)->OffsetForFixedPosition());
+ layout_view && StyleRef().GetPosition() == EPosition::kFixed) {
+ transform_state.Move(layout_view->OffsetForFixedPosition());
}
return;
}
@@ -2745,10 +2867,10 @@ void LayoutObject::MapAncestorToLocal(const LayoutBoxModelObject* ancestor,
transform_state.Move(-container_offset);
// If the ancestor is fixed, then the rect is already in its coordinates so
// doesn't need viewport-adjusting.
+ auto* layout_view = DynamicTo<LayoutView>(container);
if (ancestor->StyleRef().GetPosition() != EPosition::kFixed &&
- container->IsLayoutView() &&
- StyleRef().GetPosition() == EPosition::kFixed) {
- transform_state.Move(ToLayoutView(container)->OffsetForFixedPosition());
+ layout_view && StyleRef().GetPosition() == EPosition::kFixed) {
+ transform_state.Move(layout_view->OffsetForFixedPosition());
}
}
}
@@ -2931,30 +3053,12 @@ bool LayoutObject::IsRooted() const {
RespectImageOrientationEnum LayoutObject::ShouldRespectImageOrientation(
const LayoutObject* layout_object) {
- if (!layout_object)
- return kDoNotRespectImageOrientation;
-
- // Respect the image's orientation if it's being used as a full-page image or
- // it's an <img> and the setting to respect it everywhere is set or the <img>
- // has image-orientation: from-image style. FIXME: crbug.com/498233
- if (layout_object->GetDocument().IsImageDocument())
- return kRespectImageOrientation;
-
- if (!IsA<HTMLImageElement>(layout_object->GetNode()))
- return kDoNotRespectImageOrientation;
-
- if (layout_object->GetDocument().GetSettings() &&
- layout_object->GetDocument()
- .GetSettings()
- ->GetShouldRespectImageOrientation())
- return kRespectImageOrientation;
-
- if (layout_object->Style() &&
- layout_object->StyleRef().RespectImageOrientation() ==
+ if (layout_object && layout_object->Style() &&
+ layout_object->StyleRef().RespectImageOrientation() !=
kRespectImageOrientation)
- return kRespectImageOrientation;
+ return kDoNotRespectImageOrientation;
- return kDoNotRespectImageOrientation;
+ return kRespectImageOrientation;
}
LayoutObject* LayoutObject::Container(AncestorSkipInfo* skip_info) const {
@@ -2993,7 +3097,7 @@ LayoutObject* LayoutObject::Container(AncestorSkipInfo* skip_info) const {
}
inline LayoutObject* LayoutObject::ParentCrossingFrames() const {
- if (IsLayoutView())
+ if (IsA<LayoutView>(this))
return GetFrame()->OwnerLayoutObject();
return Parent();
}
@@ -3044,7 +3148,7 @@ void LayoutObject::WillBeDestroyed() {
// m_style is null in cases of partial construction. Any handler we added
// previously may have already been removed by the Document independently.
if (GetNode() && !GetNode()->IsTextNode() && style_ &&
- style_->GetTouchAction() != TouchAction::kTouchActionAuto) {
+ style_->GetTouchAction() != TouchAction::kAuto) {
EventHandlerRegistry& registry =
GetDocument().GetFrame()->GetEventHandlerRegistry();
if (registry.EventHandlerTargets(EventHandlerRegistry::kTouchAction)
@@ -3178,6 +3282,11 @@ void LayoutObject::WillBeRemovedFromTree() {
}
void LayoutObject::SetNeedsPaintPropertyUpdate() {
+ SetNeedsPaintPropertyUpdatePreservingCachedRects();
+ InvalidateIntersectionObserverCachedRects();
+}
+
+void LayoutObject::SetNeedsPaintPropertyUpdatePreservingCachedRects() {
if (bitfields_.NeedsPaintPropertyUpdate())
return;
@@ -3287,7 +3396,14 @@ void LayoutObject::DestroyAndCleanupAnonymousWrappers() {
}
void LayoutObject::Destroy() {
+ // Mark as being destroyed to avoid trouble with merges in |RemoveChild()| and
+ // other house keepings.
+ bitfields_.SetBeingDestroyed(true);
WillBeDestroyed();
+ DeleteThis();
+}
+
+void LayoutObject::DeleteThis() {
delete this;
}
@@ -3302,6 +3418,10 @@ CompositingState LayoutObject::GetCompositingState() const {
: kNotComposited;
}
+bool LayoutObject::CanHaveAdditionalCompositingReasons() const {
+ return false;
+}
+
CompositingReasons LayoutObject::AdditionalCompositingReasons() const {
return CompositingReason::kNone;
}
@@ -3343,17 +3463,12 @@ Node* LayoutObject::NodeForHitTest() const {
// If we hit the anonymous layoutObjects inside generated content we should
// actually hit the generated content so walk up to the PseudoElement.
if (const LayoutObject* parent = Parent()) {
- if (parent->IsBeforeOrAfterContent() ||
+ if (parent->IsBeforeOrAfterContent() || parent->IsMarkerContent() ||
parent->StyleRef().StyleType() == kPseudoIdFirstLetter) {
for (; parent; parent = parent->Parent()) {
if (Node* node = parent->GetNode())
return node;
}
- } else if (const LayoutNGListItem* list_item =
- LayoutNGListItem::FromMarkerOrMarkerContent(*this)) {
- // If this is a list marker, or is inside of a list marker, return the
- // list item.
- return list_item->GetNode();
}
}
@@ -3377,9 +3492,8 @@ bool LayoutObject::NodeAtPoint(HitTestResult&,
}
void LayoutObject::ScheduleRelayout() {
- if (IsLayoutView()) {
- LocalFrameView* view = ToLayoutView(this)->GetFrameView();
- if (view)
+ if (auto* layout_view = DynamicTo<LayoutView>(this)) {
+ if (LocalFrameView* view = layout_view->GetFrameView())
view->ScheduleRelayout();
} else {
if (IsRooted()) {
@@ -3605,7 +3719,7 @@ Element* LayoutObject::OffsetParent(const Element* base) const {
break;
if (!IsPositioned() &&
- (IsA<HTMLTableElement>(*node) || IsHTMLTableCellElement(*node)))
+ (IsA<HTMLTableElement>(*node) || IsA<HTMLTableCellElement>(*node)))
break;
// Webkit specific extension where offsetParent stops at zoom level changes.
@@ -3696,11 +3810,12 @@ PositionWithAffinity LayoutObject::CreatePositionWithAffinity(
if (position.IsNotNull())
return PositionWithAffinity(position);
- DCHECK(!GetNode());
+ DCHECK(!NonPseudoNode());
return CreatePositionWithAffinity(0);
}
-CursorDirective LayoutObject::GetCursor(const PhysicalOffset&, Cursor&) const {
+CursorDirective LayoutObject::GetCursor(const PhysicalOffset&,
+ ui::Cursor&) const {
return kSetCursorBasedOnStyle;
}
@@ -4089,6 +4204,15 @@ LayoutUnit LayoutObject::FlipForWritingModeInternal(
->FlipForWritingMode(position, width);
}
+bool LayoutObject::SelfPaintingLayerNeedsVisualOverflowRecalc() const {
+ if (HasLayer()) {
+ auto* box_model_object = ToLayoutBoxModelObject(this);
+ if (box_model_object->HasSelfPaintingLayer())
+ return box_model_object->Layer()->NeedsVisualOverflowRecalc();
+ }
+ return false;
+}
+
void LayoutObject::MarkSelfPaintingLayerForVisualOverflowRecalc() {
if (HasLayer()) {
auto* box_model_object = ToLayoutBoxModelObject(this);
@@ -4097,6 +4221,20 @@ void LayoutObject::MarkSelfPaintingLayerForVisualOverflowRecalc() {
}
}
+bool IsMenuList(const LayoutObject* object) {
+ if (!object)
+ return false;
+ auto* select = DynamicTo<HTMLSelectElement>(object->GetNode());
+ return select && select->UsesMenuList();
+}
+
+bool IsListBox(const LayoutObject* object) {
+ if (!object)
+ return false;
+ auto* select = DynamicTo<HTMLSelectElement>(object->GetNode());
+ return select && !select->UsesMenuList();
+}
+
} // namespace blink
#if DCHECK_IS_ON()
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object.h b/chromium/third_party/blink/renderer/core/layout/layout_object.h
index 28e6a2fec09..714d1246169 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object.h
@@ -31,6 +31,7 @@
#include "base/auto_reset.h"
#include "base/macros.h"
+#include "third_party/blink/public/mojom/scroll/scroll_into_view_params.mojom-blink-forward.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
#include "third_party/blink/renderer/core/dom/document.h"
@@ -45,6 +46,7 @@
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/layout_object_child_list.h"
#include "third_party/blink/renderer/core/layout/map_coordinates_flags.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "third_party/blink/renderer/core/layout/ng/ng_outline_type.h"
#include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
#include "third_party/blink/renderer/core/layout/subtree_layout_scope.h"
@@ -64,10 +66,12 @@
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-namespace blink {
+namespace ui {
+class Cursor;
+}
+namespace blink {
class AffineTransform;
-class Cursor;
class HitTestLocation;
class HitTestRequest;
class InlineBox;
@@ -89,13 +93,15 @@ class PaintLayer;
class PseudoElementStyleRequest;
struct PaintInfo;
struct PaintInvalidatorContext;
-struct WebScrollIntoViewParams;
enum VisualRectFlags {
kDefaultVisualRectFlags = 0,
kEdgeInclusive = 1 << 0,
// Use the GeometryMapper fast-path, if possible.
kUseGeometryMapper = 1 << 1,
+ // When mapping to absolute coordinates and the main frame is remote, don't
+ // apply the main frame root scroller's overflow clip.
+ kDontApplyMainFrameOverflowClip = 1 << 2,
};
enum CursorDirective { kSetCursorBasedOnStyle, kSetCursor, kDoNotSetCursor };
@@ -209,8 +215,8 @@ const int kShowTreeCharacterOffset = 39;
// Those widths are used to determine the final layout logical width, which
// depends on the layout algorithm used and the available logical width.
//
-// LayoutObject only has getters for the widths (MinPreferredLogicalWidth and
-// MaxPreferredLogicalWidth). However the storage for them is in LayoutBox (see
+// LayoutObject only has a getter for the widths (PreferredLogicalWidths).
+// However the storage for them is in LayoutBox (see
// min_preferred_logical_width_ and max_preferred_logical_width_). This is
// because only boxes implementing the full box model have a need for them.
// Because LayoutBlockFlow's intrinsic widths rely on the underlying text
@@ -219,7 +225,7 @@ const int kShowTreeCharacterOffset = 39;
// The 2 widths are computed lazily during layout when the getters are called.
// The computation is done by calling ComputePreferredLogicalWidths() behind the
// scene. The boolean used to control the lazy recomputation is
-// PreferredLogicalWidthsDirty.
+// IntrinsicLogicalWidthsDirty.
//
// See the individual getters below for more details about what each width is.
class CORE_EXPORT LayoutObject : public ImageResourceObserver,
@@ -374,7 +380,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// TODO(nburris): The returned rect is actually in document coordinates, not
// root frame coordinates.
PhysicalRect ScrollRectToVisible(const PhysicalRect&,
- const WebScrollIntoViewParams&);
+ mojom::blink::ScrollIntoViewParamsPtr);
// Convenience function for getting to the nearest enclosing box of a
// LayoutObject.
@@ -439,13 +445,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
}
}
- void AssertClearedPaintInvalidationFlags() const {
- if (PaintInvalidationStateIsDirty() &&
- !PrePaintBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren)) {
- ShowLayoutTreeForThis();
- NOTREACHED();
- }
- }
+ void AssertClearedPaintInvalidationFlags() const;
void AssertSubtreeClearedPaintInvalidationFlags() const {
for (const LayoutObject* layout_object = this; layout_object;
@@ -644,6 +644,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
}
bool IsFrame() const { return IsOfType(kLayoutObjectFrame); }
bool IsFrameSet() const { return IsOfType(kLayoutObjectFrameSet); }
+ bool IsInsideListMarker() const {
+ return IsOfType(kLayoutObjectInsideListMarker);
+ }
bool IsLayoutNGBlockFlow() const {
return IsOfType(kLayoutObjectNGBlockFlow);
}
@@ -652,25 +655,27 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
}
bool IsLayoutNGMixin() const { return IsOfType(kLayoutObjectNGMixin); }
bool IsLayoutNGListItem() const { return IsOfType(kLayoutObjectNGListItem); }
- bool IsLayoutNGListMarker() const {
- return IsOfType(kLayoutObjectNGListMarker);
- }
bool IsLayoutNGInsideListMarker() const {
return IsOfType(kLayoutObjectNGInsideListMarker);
}
bool IsLayoutNGListMarkerImage() const {
return IsOfType(kLayoutObjectNGListMarkerImage);
}
+ bool IsLayoutNGOutsideListMarker() const {
+ return IsOfType(kLayoutObjectNGOutsideListMarker);
+ }
bool IsLayoutNGProgress() const { return IsOfType(kLayoutObjectNGProgress); }
bool IsLayoutNGText() const { return IsOfType(kLayoutObjectNGText); }
bool IsLayoutTableCol() const {
return IsOfType(kLayoutObjectLayoutTableCol);
}
- bool IsListBox() const { return IsOfType(kLayoutObjectListBox); }
bool IsListItem() const { return IsOfType(kLayoutObjectListItem); }
- bool IsListMarker() const { return IsOfType(kLayoutObjectListMarker); }
+ bool IsMathML() const { return IsOfType(kLayoutObjectMathML); }
+ bool IsMathMLRoot() const { return IsOfType(kLayoutObjectMathMLRoot); }
bool IsMedia() const { return IsOfType(kLayoutObjectMedia); }
- bool IsMenuList() const { return IsOfType(kLayoutObjectMenuList); }
+ bool IsOutsideListMarker() const {
+ return IsOfType(kLayoutObjectOutsideListMarker);
+ }
bool IsProgress() const { return IsOfType(kLayoutObjectProgress); }
bool IsQuote() const { return IsOfType(kLayoutObjectQuote); }
bool IsLayoutButton() const { return IsOfType(kLayoutObjectLayoutButton); }
@@ -832,11 +837,8 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bool IsSVGResourceContainer() const {
return IsOfType(kLayoutObjectSVGResourceContainer);
}
- bool IsSVGResourceFilter() const {
- return IsOfType(kLayoutObjectSVGResourceFilter);
- }
- bool IsSVGResourceFilterPrimitive() const {
- return IsOfType(kLayoutObjectSVGResourceFilterPrimitive);
+ bool IsSVGFilterPrimitive() const {
+ return IsOfType(kLayoutObjectSVGFilterPrimitive);
}
// FIXME: Those belong into a SVG specific base-class for all layoutObjects
@@ -1072,14 +1074,14 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
}
bool NeedsCollectInlines() const { return bitfields_.NeedsCollectInlines(); }
- // Return true if the min/max preferred logical widths aren't up-to-date. Note
- // that for objects that *don't* need to calculate preferred logical widths
- // (e.g. if inline-size is a fixed value, and no other inline lengths are
- // intrinsic, and the object isn't a descendant of something that needs
+ // Return true if the min/max intrinsic logical widths aren't up-to-date.
+ // Note that for objects that *don't* need to calculate intrinsic logical
+ // widths (e.g. if inline-size is a fixed value, and no other inline lengths
+ // are intrinsic, and the object isn't a descendant of something that needs
// min/max), this flag will never be cleared (since the values will never be
// calculated).
- bool PreferredLogicalWidthsDirty() const {
- return bitfields_.PreferredLogicalWidthsDirty();
+ bool IntrinsicLogicalWidthsDirty() const {
+ return bitfields_.IntrinsicLogicalWidthsDirty();
}
bool NeedsLayoutOverflowRecalc() const {
@@ -1343,20 +1345,27 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
void SetChildNeedsLayout(MarkingBehavior = kMarkContainerChain,
SubtreeLayoutScope* = nullptr);
void SetNeedsPositionedMovementLayout();
- void SetPreferredLogicalWidthsDirty(MarkingBehavior = kMarkContainerChain);
- void ClearPreferredLogicalWidthsDirty();
+ void SetIntrinsicLogicalWidthsDirty(MarkingBehavior = kMarkContainerChain);
+ void ClearIntrinsicLogicalWidthsDirty();
- void SetNeedsLayoutAndPrefWidthsRecalc(
+ void SetNeedsLayoutAndIntrinsicWidthsRecalc(
LayoutInvalidationReasonForTracing reason) {
SetNeedsLayout(reason);
- SetPreferredLogicalWidthsDirty();
+ SetIntrinsicLogicalWidthsDirty();
}
- void SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ void SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
LayoutInvalidationReasonForTracing reason) {
SetNeedsLayoutAndFullPaintInvalidation(reason);
- SetPreferredLogicalWidthsDirty();
+ SetIntrinsicLogicalWidthsDirty();
}
+ // Traverses subtree, and marks all layout objects as need relayout, repaint
+ // and preferred width recalc. Also invalidates shaping on all text nodes.
+ // TODO(crbug.com/441925): Try to partially invalidate layout on font updates.
+ virtual void InvalidateSubtreeLayoutForFontUpdates();
+
+ void InvalidateIntersectionObserverCachedRects();
+
void SetPositionState(EPosition position) {
DCHECK(
(position != EPosition::kAbsolute && position != EPosition::kFixed) ||
@@ -1368,10 +1377,24 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
void SetFloating(bool is_floating) { bitfields_.SetFloating(is_floating); }
void SetInline(bool is_inline) { bitfields_.SetIsInline(is_inline); }
+ // Return whether we can directly traverse fragments generated for this layout
+ // object, when it comes to painting, hit-testing and other layout read
+ // operations. If false is returned, we need to traverse the layout object
+ // tree instead.
+ //
+ // It is not allowed to call this method on a non-LayoutBox object, unless its
+ // containing block is an NG object (e.g. not allowed to call it on a
+ // LayoutInline that's contained by a legacy LayoutBlockFlow).
+ inline bool CanTraversePhysicalFragments() const;
+
// Returns the associated |NGPaintFragment|. When this is not a |nullptr|,
// this is the root of an inline formatting context, laid out by LayoutNG.
virtual const NGPaintFragment* PaintFragment() const { return nullptr; }
+ // Return true if |this| produces one or more inline fragments, including
+ // whitespace-only text fragments.
+ virtual bool HasInlineFragments() const { return false; }
+
// Paint/Physical fragments are not in sync with LayoutObject tree until it is
// laid out. For inline, it needs to check if the containing block is
// layout-clean. crbug.com/963103
@@ -1479,6 +1502,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
virtual void AddAnnotatedRegions(Vector<AnnotatedRegionValue>&);
CompositingState GetCompositingState() const;
+
+ // True for object types which override |AdditionalCompositingReasons|.
+ virtual bool CanHaveAdditionalCompositingReasons() const;
virtual CompositingReasons AdditionalCompositingReasons() const;
// |accumulated_offset| is accumulated physical offset of this object from
@@ -1563,6 +1589,11 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// See LayoutBlock.h for some extra explanations on containing blocks.
LayoutBlock* ContainingBlock(AncestorSkipInfo* = nullptr) const;
+ // Returns |container|'s containing block.
+ static LayoutBlock* FindNonAnonymousContainingBlock(
+ LayoutObject* container,
+ AncestorSkipInfo* = nullptr);
+
const LayoutBlock* InclusiveContainingBlock() const;
bool CanContainAbsolutePositionObjects() const {
@@ -1725,8 +1756,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
virtual void AbsoluteQuads(Vector<FloatQuad>&,
MapCoordinatesFlags mode = 0) const {}
- static FloatRect AbsoluteBoundingBoxRectForRange(const EphemeralRange&);
-
// The bounding box (see: absoluteBoundingBoxRect) including all descendant
// bounding boxes.
IntRect AbsoluteBoundingBoxRectIncludingDescendants() const;
@@ -1736,28 +1765,20 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// to any ancestor using, e.g., localToAncestorTransform.
virtual FloatRect LocalBoundingBoxRectForAccessibility() const = 0;
- // This function returns the minimal logical width this object can have
- // without overflowing. This means that all the opportunities for wrapping
- // have been taken.
+ // This function returns the:
+ // - Minimal logical width this object can have without overflowing. This
+ // means that all the opportunities for wrapping have been taken.
+ // - Maximal logical width.
//
// See INTRINSIC SIZES / PREFERRED LOGICAL WIDTHS above.
//
- // CSS 2.1 calls this width the "preferred minimum width" (thus this name)
- // and "minimum content width" (for table).
- // However CSS 3 calls it the "min-content inline size".
+ // CSS 2.1 calls this width the "preferred minimum width"/"preferred width"
+ // (thus this name) and "minimum content width" (for table).
+ // However CSS 3 calls it the "min/max-content inline size".
// https://drafts.csswg.org/css-sizing-3/#min-content-inline-size
- // TODO(jchaffraix): We will probably want to rename it to match CSS 3.
- virtual LayoutUnit MinPreferredLogicalWidth() const { return LayoutUnit(); }
-
- // This function returns the maximum logical width this object can have.
- //
- // See INTRINSIC SIZES / PREFERRED LOGICAL WIDTHS above.
- //
- // CSS 2.1 calls this width the "preferred width". However CSS 3 calls it
- // the "max-content inline size".
// https://drafts.csswg.org/css-sizing-3/#max-content-inline-size
// TODO(jchaffraix): We will probably want to rename it to match CSS 3.
- virtual LayoutUnit MaxPreferredLogicalWidth() const { return LayoutUnit(); }
+ virtual MinMaxSizes PreferredLogicalWidths() const { return MinMaxSizes(); }
const ComputedStyle* Style() const { return style_.get(); }
@@ -1791,7 +1812,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
return StyleRef().VisitedDependentColor(color_property);
}
- virtual CursorDirective GetCursor(const PhysicalOffset&, Cursor&) const;
+ virtual CursorDirective GetCursor(const PhysicalOffset&, ui::Cursor&) const;
// Return the LayoutBoxModelObject in the container chain which is responsible
// for painting this object. The function crosses frames boundaries so the
@@ -1860,6 +1881,14 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
TransformState&,
VisualRectFlags = kDefaultVisualRectFlags) const;
+ // Returns the nearest ancestor in the containing block chain that
+ // HasLocalBorderBoxProperties. If AncestorSkipInfo* is non-null and the
+ // ancestor was skipped, returns nullptr. If PropertyTreeState* is non-null,
+ // it will be populated with paint property nodes suitable for mapping upward
+ // from the coordinate system of the property container.
+ const LayoutObject* GetPropertyContainer(AncestorSkipInfo*,
+ PropertyTreeState* = nullptr) const;
+
// Do a rect-based hit test with this object as the stop node.
HitTestResult HitTestForOcclusion(const PhysicalRect&) const;
HitTestResult HitTestForOcclusion() const {
@@ -1879,6 +1908,15 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
return (IsFloating() || IsOutOfFlowPositioned());
}
+ // Outside list markers are in-flow but behave kind of out-of-flowish.
+ // We include them here to prevent code like '<li> <ol></ol></li>' from
+ // generating an anonymous block box for the whitespace between the marker
+ // and the <ol>.
+ bool AffectsWhitespaceSiblings() const {
+ return !IsFloatingOrOutOfFlowPositioned() &&
+ !IsLayoutNGOutsideListMarker() && !IsOutsideListMarker();
+ }
+
bool HasReflection() const { return bitfields_.HasReflection(); }
// The current selection state for an object. For blocks, the state refers to
@@ -1932,12 +1970,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
void DestroyAndCleanupAnonymousWrappers();
- // While the destroy() method is virtual, this should only be overriden in
- // very rare circumstances.
- // You want to override willBeDestroyed() instead unless you explicitly need
- // to stop this object from being destroyed (for example,
- // LayoutEmbeddedContent overrides destroy() for this purpose).
- virtual void Destroy();
+ void Destroy();
// Virtual function helpers for the deprecated Flexible Box Layout (display:
// -webkit-box).
@@ -1958,14 +1991,14 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// There are 3 types of list marker. LayoutNG creates different types for
// inside and outside; outside is derived from LayoutBlockFlow, and inside
// from LayoutInline. Legacy is derived from LayoutBox.
- bool IsListMarkerIncludingNG() const {
- return IsListMarker() || IsLayoutNGListMarker();
+ bool IsListMarker() const {
+ return IsOutsideListMarker() || IsInsideListMarker();
}
- bool IsLayoutNGListMarkerIncludingInside() const {
- return IsLayoutNGListMarker() || IsLayoutNGInsideListMarker();
+ bool IsListMarkerIncludingNGOutside() const {
+ return IsListMarker() || IsLayoutNGOutsideListMarker();
}
- bool IsListMarkerIncludingNGInside() const {
- return IsListMarker() || IsLayoutNGListMarkerIncludingInside();
+ bool IsListMarkerIncludingNGOutsideAndInside() const {
+ return IsListMarkerIncludingNGOutside() || IsLayoutNGInsideListMarker();
}
virtual bool IsCombineText() const { return false; }
@@ -2176,8 +2209,12 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// Returns the bounding box of the visual rects of all fragments.
IntRect FragmentsVisualRectBoundingBox() const;
- void SetNeedsOverflowRecalc();
- void SetNeedsVisualOverflowAndPaintInvalidation();
+ enum OverflowRecalcType {
+ kOnlyVisualOverflowRecalc,
+ kLayoutAndVisualOverflowRecalc,
+ };
+ void SetNeedsOverflowRecalc(
+ OverflowRecalcType = OverflowRecalcType::kLayoutAndVisualOverflowRecalc);
void InvalidateClipPathCache();
@@ -2189,11 +2226,11 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// (from style) and blocking touch event handlers.
TouchAction EffectiveAllowedTouchAction() const {
if (InsideBlockingTouchEventHandler())
- return TouchAction::kTouchActionNone;
+ return TouchAction::kNone;
return StyleRef().GetEffectiveTouchAction();
}
bool HasEffectiveAllowedTouchAction() const {
- return EffectiveAllowedTouchAction() != TouchAction::kTouchActionAuto;
+ return EffectiveAllowedTouchAction() != TouchAction::kAuto;
}
// Whether this object's Node has a blocking touch event handler on itself
@@ -2239,7 +2276,13 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
}
}
void SetShouldCheckForPaintInvalidation() {
- layout_object_.SetShouldCheckForPaintInvalidation();
+ // This method is only intended to be called when visiting this object
+ // during pre-paint, and as such it should only mark itself, and not the
+ // entire containing block chain.
+ DCHECK_EQ(layout_object_.GetDocument().Lifecycle().GetState(),
+ DocumentLifecycle::kInPrePaint);
+ layout_object_.bitfields_.SetNeedsPaintOffsetAndVisualRectUpdate(true);
+ layout_object_.bitfields_.SetShouldCheckForPaintInvalidation(true);
}
void SetShouldDoFullPaintInvalidation(PaintInvalidationReason reason) {
layout_object_.SetShouldDoFullPaintInvalidation(reason);
@@ -2272,9 +2315,10 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
layout_object_.fragment_.SetSelectionVisualRect(r);
}
- void SetPreviousBackgroundPaintLocation(BackgroundPaintLocation location) {
- layout_object_.bitfields_.SetPreviousBackgroundPaintLocation(location);
+ void SetBackgroundPaintLocation(BackgroundPaintLocation location) {
+ layout_object_.SetBackgroundPaintLocation(location);
}
+
void UpdatePreviousOutlineMayBeAffectedByDescendants() {
layout_object_.SetPreviousOutlineMayBeAffectedByDescendants(
layout_object_.OutlineMayBeAffectedByDescendants());
@@ -2303,6 +2347,10 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
layout_object_.UpdateInsideBlockingTouchEventHandler(inside);
}
+ void InvalidateIntersectionObserverCachedRects() {
+ layout_object_.InvalidateIntersectionObserverCachedRects();
+ }
+
#if DCHECK_IS_ON()
// Same as setNeedsPaintPropertyUpdate() but does not mark ancestors as
// having a descendant needing a paint property update.
@@ -2352,6 +2400,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// updated, SetNeedsPaintPropertyUpdate marks all ancestors as having a
// descendant needing a paint property update too.
void SetNeedsPaintPropertyUpdate();
+ void SetNeedsPaintPropertyUpdatePreservingCachedRects();
bool NeedsPaintPropertyUpdate() const {
return bitfields_.NeedsPaintPropertyUpdate();
}
@@ -2387,8 +2436,14 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bool CompositedScrollsWithRespectTo(
const LayoutBoxModelObject& paint_invalidation_container) const;
- BackgroundPaintLocation PreviousBackgroundPaintLocation() const {
- return bitfields_.PreviousBackgroundPaintLocation();
+ BackgroundPaintLocation GetBackgroundPaintLocation() const {
+ return bitfields_.GetBackgroundPaintLocation();
+ }
+ void SetBackgroundPaintLocation(BackgroundPaintLocation location) {
+ if (GetBackgroundPaintLocation() != location) {
+ SetBackgroundNeedsFullPaintInvalidation();
+ bitfields_.SetBackgroundPaintLocation(location);
+ }
}
bool IsBackgroundAttachmentFixedObject() const {
@@ -2467,8 +2522,10 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bitfields_.SetHasNonCollapsedBorderDecoration(b);
}
+ bool BeingDestroyed() const { return bitfields_.BeingDestroyed(); }
+
DisplayLockContext* GetDisplayLockContext() const {
- if (!RuntimeEnabledFeatures::DisplayLockingEnabled(&GetDocument()))
+ if (!RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled())
return nullptr;
auto* element = DynamicTo<Element>(GetNode());
if (!element)
@@ -2487,22 +2544,23 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
kLayoutObjectFileUploadControl,
kLayoutObjectFrame,
kLayoutObjectFrameSet,
+ kLayoutObjectInsideListMarker,
kLayoutObjectLayoutTableCol,
- kLayoutObjectListBox,
kLayoutObjectListItem,
- kLayoutObjectListMarker,
+ kLayoutObjectMathML,
+ kLayoutObjectMathMLRoot,
kLayoutObjectMedia,
- kLayoutObjectMenuList,
kLayoutObjectNGBlockFlow,
kLayoutObjectNGFieldset,
kLayoutObjectNGFlexibleBox,
kLayoutObjectNGMixin,
kLayoutObjectNGListItem,
- kLayoutObjectNGListMarker,
kLayoutObjectNGInsideListMarker,
+ kLayoutObjectNGOutsideListMarker,
kLayoutObjectNGListMarkerImage,
kLayoutObjectNGProgress,
kLayoutObjectNGText,
+ kLayoutObjectOutsideListMarker,
kLayoutObjectProgress,
kLayoutObjectQuote,
kLayoutObjectLayoutButton,
@@ -2549,11 +2607,19 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
kLayoutObjectSVGImage,
kLayoutObjectSVGForeignObject,
kLayoutObjectSVGResourceContainer,
- kLayoutObjectSVGResourceFilter,
- kLayoutObjectSVGResourceFilterPrimitive,
+ kLayoutObjectSVGFilterPrimitive,
};
virtual bool IsOfType(LayoutObjectType type) const { return false; }
+ // While the |DeleteThis()| method is virtual, this should only be overridden
+ // in very rare circumstances.
+ // You want to override |WillBeDestroyed()| instead unless you explicitly need
+ // to stop this object from being destroyed (for example,
+ // |LayoutEmbeddedContent| overrides |DeleteThis()| for this purpose).
+ virtual void DeleteThis();
+
+ void SetBeingDestroyedForTesting() { bitfields_.SetBeingDestroyed(true); }
+
const ComputedStyle& SlowEffectiveStyle(NGStyleVariant style_variant) const;
// Updates only the local style ptr of the object. Does not update the state
@@ -2661,10 +2727,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bitfields_.SetBackgroundIsKnownToBeObscured(b);
}
- // Returns |container|'s containing block.
- static LayoutBlock* FindNonAnonymousContainingBlock(
- LayoutObject* container,
- AncestorSkipInfo* = nullptr);
// Returns ContainerForAbsolutePosition() if it's a LayoutBlock, or the
// containing LayoutBlock of it.
LayoutBlock* ContainingBlockForAbsolutePosition(
@@ -2709,11 +2771,13 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// scroll anchoring on.
void SetScrollAnchorDisablingStyleChangedOnAncestor();
- inline void MarkContainerChainForOverflowRecalcIfNeeded();
+ bool SelfPaintingLayerNeedsVisualOverflowRecalc() const;
+ inline void MarkContainerChainForOverflowRecalcIfNeeded(
+ bool mark_container_chain_layout_overflow_recalc);
inline void SetNeedsPaintOffsetAndVisualRectUpdate();
- inline void InvalidateContainerPreferredLogicalWidths();
+ inline void InvalidateContainerIntrinsicLogicalWidths();
const LayoutBoxModelObject* EnclosingCompositedContainer() const;
@@ -2810,7 +2874,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
needs_simplified_normal_flow_layout_(false),
self_needs_layout_overflow_recalc_(false),
child_needs_layout_overflow_recalc_(false),
- preferred_logical_widths_dirty_(false),
+ intrinsic_logical_widths_dirty_(false),
needs_collect_inlines_(false),
should_check_for_paint_invalidation_(true),
subtree_should_check_for_paint_invalidation_(false),
@@ -2864,11 +2928,12 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
registered_as_first_line_image_observer_(false),
is_html_legend_element_(false),
has_non_collapsed_border_decoration_(false),
+ being_destroyed_(false),
positioned_state_(kIsStaticallyPositioned),
selection_state_(static_cast<unsigned>(SelectionState::kNone)),
subtree_paint_property_update_reasons_(
static_cast<unsigned>(SubtreePaintPropertyUpdateReason::kNone)),
- previous_background_paint_location_(0) {}
+ background_paint_location_(kBackgroundPaintInGraphicsLayer) {}
// Self needs layout for style means that this layout object is marked for a
// full layout. This is the default layout but it is expensive as it
@@ -2918,12 +2983,12 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
ADD_BOOLEAN_BITFIELD(child_needs_layout_overflow_recalc_,
ChildNeedsLayoutOverflowRecalc);
- // This boolean marks preferred logical widths for lazy recomputation.
+ // This boolean marks the intrinsic logical widths for lazy recomputation.
//
// See INTRINSIC SIZES / PREFERRED LOGICAL WIDTHS above about those
// widths.
- ADD_BOOLEAN_BITFIELD(preferred_logical_widths_dirty_,
- PreferredLogicalWidthsDirty);
+ ADD_BOOLEAN_BITFIELD(intrinsic_logical_widths_dirty_,
+ IntrinsicLogicalWidthsDirty);
// This flag is set on inline container boxes that need to run the
// Pre-layout phase in LayoutNG. See NGInlineNode::CollectInlines().
@@ -3124,6 +3189,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
ADD_BOOLEAN_BITFIELD(has_non_collapsed_border_decoration_,
HasNonCollapsedBorderDecoration);
+ // True at start of |Destroy()| before calling |WillBeDestroyed()|.
+ ADD_BOOLEAN_BITFIELD(being_destroyed_, BeingDestroyed);
+
private:
// This is the cached 'position' value of this object
// (see ComputedStyle::position).
@@ -3134,8 +3202,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
unsigned subtree_paint_property_update_reasons_
: kSubtreePaintPropertyUpdateReasonsBitfieldWidth;
- // BackgroundPaintLocation of previous paint invalidation.
- unsigned previous_background_paint_location_ : 2;
+ // Updated during CompositingUpdate in pre-CompositeAfterPaint, or PrePaint
+ // in CompositeAfterPaint.
+ unsigned background_paint_location_ : 2; // BackgroundPaintLocation.
public:
bool IsOutOfFlowPositioned() const {
@@ -3202,15 +3271,13 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
static_cast<unsigned>(SubtreePaintPropertyUpdateReason::kNone);
}
- ALWAYS_INLINE BackgroundPaintLocation
- PreviousBackgroundPaintLocation() const {
- return static_cast<BackgroundPaintLocation>(
- previous_background_paint_location_);
+ ALWAYS_INLINE BackgroundPaintLocation GetBackgroundPaintLocation() const {
+ return static_cast<BackgroundPaintLocation>(background_paint_location_);
}
- ALWAYS_INLINE void SetPreviousBackgroundPaintLocation(
+ ALWAYS_INLINE void SetBackgroundPaintLocation(
BackgroundPaintLocation location) {
- previous_background_paint_location_ = static_cast<unsigned>(location);
- DCHECK_EQ(location, PreviousBackgroundPaintLocation());
+ background_paint_location_ = static_cast<unsigned>(location);
+ DCHECK_EQ(location, GetBackgroundPaintLocation());
}
};
@@ -3290,6 +3357,33 @@ inline bool LayoutObject::IsBeforeOrAfterContent() const {
return IsBeforeContent() || IsAfterContent();
}
+inline bool LayoutObject::CanTraversePhysicalFragments() const {
+ if (LIKELY(!RuntimeEnabledFeatures::LayoutNGFragmentTraversalEnabled()))
+ return false;
+ // Non-NG objects should be painted by legacy.
+ if (!IsLayoutNGObject()) {
+ if (IsBox())
+ return false;
+ // Non-LayoutBox objects (such as LayoutInline) don't necessarily create NG
+ // LayoutObjects. If they are laid out by an NG container, though, we may be
+ // allowed to traverse their fragments. Otherwise, bail now.
+ if (!IsInLayoutNGInlineFormattingContext())
+ return false;
+ }
+ // Bail if we have an NGPaintFragment. NGPaintFragment will be removed, and we
+ // will not attempt to add support for them here.
+ if (PaintFragment())
+ return false;
+ // We don't support fragmentation traversal inside block fragmentation just
+ // yet.
+ if (IsInsideFlowThread())
+ return false;
+ // The NG paint system currently doesn't support table-cells.
+ if (IsTableCell())
+ return false;
+ return true;
+}
+
// setNeedsLayout() won't cause full paint invalidations as
// setNeedsLayoutAndFullPaintInvalidation() does. Otherwise the two methods are
// identical.
@@ -3428,6 +3522,9 @@ CORE_EXPORT std::ostream& operator<<(std::ostream&, const LayoutObject&);
DEFINE_TYPE_CASTS(thisType, LayoutObject, object, object->predicate, \
object.predicate)
+bool IsMenuList(const LayoutObject* object);
+CORE_EXPORT bool IsListBox(const LayoutObject* object);
+
} // namespace blink
#if DCHECK_IS_ON()
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc b/chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc
index fb9db0a519e..8a71bc3a13b 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc
@@ -58,7 +58,11 @@ void InvalidateInlineItems(LayoutObject* object) {
}
}
- if (NGPaintFragment* fragment = object->FirstInlineFragment()) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ // TODO(yosin): Tells |NGFragmentItem| about they become not to associate
+ // to layout object.
+ object->ClearFirstInlineFragmentItemIndex();
+ } else if (NGPaintFragment* fragment = object->FirstInlineFragment()) {
// This LayoutObject is not technically destroyed, but further access should
// be prohibited when moved to different parent as if it were destroyed.
fragment->LayoutObjectWillBeDestroyed();
@@ -70,20 +74,13 @@ void InvalidateInlineItems(LayoutObject* object) {
} // namespace
void LayoutObjectChildList::DestroyLeftoverChildren() {
- while (FirstChild()) {
- // List markers are owned by their enclosing list and so don't get destroyed
- // by this container.
- if (FirstChild()->IsListMarkerIncludingNG()) {
- FirstChild()->Remove();
- continue;
- }
-
- // Destroy any anonymous children remaining in the layout tree, as well as
- // implicit (shadow) DOM elements like those used in the engine-based text
- // fields.
- if (FirstChild()->GetNode())
- FirstChild()->GetNode()->SetLayoutObject(nullptr);
- FirstChild()->Destroy();
+ // Destroy any anonymous children remaining in the layout tree, as well as
+ // implicit (shadow) DOM elements like those used in the engine-based text
+ // fields.
+ while (LayoutObject* child = FirstChild()) {
+ if (Node* child_node = child->GetNode())
+ child_node->SetLayoutObject(nullptr);
+ child->Destroy();
}
}
@@ -103,7 +100,7 @@ LayoutObject* LayoutObjectChildList::RemoveChildNode(
// issue paint invalidations, so that the area exposed when the child
// disappears gets paint invalidated properly.
if (notify_layout_object && old_child->EverHadLayout()) {
- old_child->SetNeedsLayoutAndPrefWidthsRecalc(
+ old_child->SetNeedsLayoutAndIntrinsicWidthsRecalc(
layout_invalidation_reason::kRemovedFromLayout);
if (old_child->IsOutOfFlowPositioned() &&
RuntimeEnabledFeatures::LayoutNGEnabled())
@@ -129,6 +126,8 @@ LayoutObject* LayoutObjectChildList::RemoveChildNode(
if (old_child->IsInLayoutNGInlineFormattingContext()) {
owner->SetChildNeedsCollectInlines();
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ InvalidateInlineItems(old_child);
}
}
@@ -184,6 +183,12 @@ void LayoutObjectChildList::InsertChildNode(LayoutObject* owner,
return;
}
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled() &&
+ !owner->DocumentBeingDestroyed() &&
+ new_child->IsInLayoutNGInlineFormattingContext()) {
+ InvalidateInlineItems(new_child);
+ }
+
new_child->SetParent(owner);
if (FirstChild() == before_child)
@@ -239,7 +244,7 @@ void LayoutObjectChildList::InsertChildNode(LayoutObject* owner,
// actually happens.
}
- new_child->SetNeedsLayoutAndPrefWidthsRecalc(
+ new_child->SetNeedsLayoutAndIntrinsicWidthsRecalc(
layout_invalidation_reason::kAddedToLayout);
if (new_child->IsOutOfFlowPositioned() &&
RuntimeEnabledFeatures::LayoutNGEnabled())
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object_factory.cc b/chromium/third_party/blink/renderer/core/layout/layout_object_factory.cc
index 00524e1719a..5ec6031ef59 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object_factory.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object_factory.cc
@@ -5,10 +5,15 @@
#include "third_party/blink/renderer/core/layout/layout_object_factory.h"
#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.h"
#include "third_party/blink/renderer/core/layout/layout_fieldset.h"
+#include "third_party/blink/renderer/core/layout/layout_file_upload_control.h"
#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
+#include "third_party/blink/renderer/core/layout/layout_inside_list_marker.h"
#include "third_party/blink/renderer/core/layout/layout_list_item.h"
+#include "third_party/blink/renderer/core/layout/layout_outside_list_marker.h"
#include "third_party/blink/renderer/core/layout/layout_table_caption.h"
#include "third_party/blink/renderer/core/layout/layout_table_cell.h"
#include "third_party/blink/renderer/core/layout/layout_text.h"
@@ -24,7 +29,7 @@
#include "third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -74,9 +79,26 @@ LayoutBlockFlow* LayoutObjectFactory::CreateBlockFlow(
Node& node,
const ComputedStyle& style,
LegacyLayout legacy) {
+ if (style.Display() == EDisplay::kListItem) {
+ // Create a LayoutBlockFlow with a list marker
+ return CreateObject<LayoutBlockFlow, LayoutNGListItem, LayoutListItem>(
+ node, style, legacy);
+ }
+
+ // Create a plain LayoutBlockFlow
return CreateObject<LayoutBlockFlow, LayoutNGBlockFlow>(node, style, legacy);
}
+// static
+LayoutBlock* LayoutObjectFactory::CreateBlockForLineClamp(
+ Node& node,
+ const ComputedStyle& style,
+ LegacyLayout legacy) {
+ DCHECK(RuntimeEnabledFeatures::BlockFlowHandlesWebkitLineClampEnabled());
+ return CreateObject<LayoutBlock, LayoutNGBlockFlow,
+ LayoutDeprecatedFlexibleBox>(node, style, legacy);
+}
+
LayoutBlock* LayoutObjectFactory::CreateFlexibleBox(Node& node,
const ComputedStyle& style,
LegacyLayout legacy) {
@@ -85,28 +107,20 @@ LayoutBlock* LayoutObjectFactory::CreateFlexibleBox(Node& node,
node, style, legacy, disable_ng_for_type);
}
-LayoutBlockFlow* LayoutObjectFactory::CreateListItem(Node& node,
- const ComputedStyle& style,
- LegacyLayout legacy) {
- return CreateObject<LayoutBlockFlow, LayoutNGListItem, LayoutListItem>(
- node, style, legacy);
-}
-
LayoutObject* LayoutObjectFactory::CreateListMarker(Node& node,
const ComputedStyle& style,
LegacyLayout legacy) {
- // TODO(obrufau): allow ::marker pseudo-elements to generate legacy layout.
- if (!RuntimeEnabledFeatures::LayoutNGEnabled() ||
- legacy == LegacyLayout::kForce)
- return nullptr;
- // TODO(obrufau): markers may be forced to be inside despite having
- // `list-style-position: outside`.
- if (style.ListStylePosition() == EListStylePosition::kInside) {
+ const Node* parent = node.parentNode();
+ const ComputedStyle* parent_style = parent->GetComputedStyle();
+ bool is_inside =
+ parent_style->ListStylePosition() == EListStylePosition::kInside ||
+ (IsA<HTMLLIElement>(parent) && !parent_style->IsInsideListElement());
+ if (is_inside) {
return CreateObject<LayoutObject, LayoutNGInsideListMarker,
- LayoutNGInsideListMarker>(node, style, legacy);
+ LayoutInsideListMarker>(node, style, legacy);
}
- return CreateObject<LayoutObject, LayoutNGListMarker, LayoutNGListMarker>(
- node, style, legacy);
+ return CreateObject<LayoutObject, LayoutNGOutsideListMarker,
+ LayoutOutsideListMarker>(node, style, legacy);
}
LayoutTableCaption* LayoutObjectFactory::CreateTableCaption(
@@ -132,6 +146,14 @@ LayoutBlock* LayoutObjectFactory::CreateFieldset(Node& node,
node, style, legacy, disable_ng_for_type);
}
+LayoutBlockFlow* LayoutObjectFactory::CreateFileUploadControl(
+ Node& node,
+ const ComputedStyle& style,
+ LegacyLayout legacy) {
+ return CreateObject<LayoutBlockFlow, LayoutNGBlockFlow,
+ LayoutFileUploadControl>(node, style, legacy);
+}
+
LayoutText* LayoutObjectFactory::CreateText(Node* node,
scoped_refptr<StringImpl> str,
LegacyLayout legacy) {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object_factory.h b/chromium/third_party/blink/renderer/core/layout/layout_object_factory.h
index 4fc7ac0f5af..37428424c92 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object_factory.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object_factory.h
@@ -38,12 +38,12 @@ class LayoutObjectFactory {
static LayoutBlockFlow* CreateBlockFlow(Node&,
const ComputedStyle&,
LegacyLayout);
+ static LayoutBlock* CreateBlockForLineClamp(Node& node,
+ const ComputedStyle& style,
+ LegacyLayout legacy);
static LayoutBlock* CreateFlexibleBox(Node&,
const ComputedStyle&,
LegacyLayout);
- static LayoutBlockFlow* CreateListItem(Node&,
- const ComputedStyle&,
- LegacyLayout);
static LayoutObject* CreateListMarker(Node&,
const ComputedStyle&,
LegacyLayout);
@@ -54,6 +54,9 @@ class LayoutObjectFactory {
const ComputedStyle&,
LegacyLayout);
static LayoutBlock* CreateFieldset(Node&, const ComputedStyle&, LegacyLayout);
+ static LayoutBlockFlow* CreateFileUploadControl(Node& node,
+ const ComputedStyle& style,
+ LegacyLayout legacy);
static LayoutText* CreateText(Node*, scoped_refptr<StringImpl>, LegacyLayout);
static LayoutTextFragment* CreateTextFragment(Node*,
StringImpl*,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_object_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_object_test.cc
index bc06001fd8a..d1d45474fa0 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object_test.cc
@@ -530,6 +530,7 @@ TEST_F(LayoutObjectTest, VisualRect) {
class MockLayoutObject : public LayoutObject {
public:
MockLayoutObject() : LayoutObject(nullptr) {}
+ ~MockLayoutObject() override { SetBeingDestroyedForTesting(); }
MOCK_CONST_METHOD0(VisualRectRespectsVisibility, bool());
private:
@@ -856,8 +857,7 @@ TEST_F(LayoutObjectTest, UpdateVisualRectAfterAncestorLayout) {
class LayoutObjectSimTest : public SimTest {
public:
bool DocumentHasTouchActionRegion(const EventHandlerRegistry& registry) {
- GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetDocument().View()->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
return registry.HasEventHandlers(
EventHandlerRegistry::EventHandlerClass::kTouchAction);
}
@@ -930,8 +930,7 @@ TEST_F(LayoutObjectSimTest, HitTestForOcclusionInIframe) {
<div id='target'>target</div>
)HTML");
- GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetDocument().View()->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
Element* iframe_element = GetDocument().QuerySelector("iframe");
auto* frame_owner_element = To<HTMLFrameOwnerElement>(iframe_element);
Document* iframe_doc = frame_owner_element->contentDocument();
@@ -941,8 +940,7 @@ TEST_F(LayoutObjectSimTest, HitTestForOcclusionInIframe) {
Element* occluder = GetDocument().getElementById("occluder");
occluder->SetInlineStyleProperty(CSSPropertyID::kMarginTop, "-150px");
- GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetDocument().View()->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
result = target->GetLayoutObject()->HitTestForOcclusion();
EXPECT_EQ(result.InnerNode(), occluder);
}
@@ -965,8 +963,7 @@ TEST_F(LayoutObjectSimTest, FirstLineBackgroundImage) {
<div>To keep the image alive when target is set display: none</div>
)HTML");
- GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetDocument().View()->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
auto* target = GetDocument().getElementById("target");
auto* target_object = target->GetLayoutObject();
@@ -998,8 +995,7 @@ TEST_F(LayoutObjectSimTest, FirstLineBackgroundImage) {
EXPECT_FALSE(second_line->SlowFirstChild()->ShouldDoFullPaintInvalidation());
target->setAttribute(html_names::kStyleAttr, "display: none");
- GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetDocument().View()->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
target_object = target->GetLayoutObject();
EXPECT_EQ(nullptr, target_object);
// The image is still alive because the other div's first line style still
@@ -1064,8 +1060,7 @@ TEST_F(LayoutObjectTest, FirstLineBackgroundImageChangeStyleCrash) {
UpdateAllLifecyclePhasesForTest();
}
-// TODO(rego): Test is failing until we can fix https://crbug.com/941180.
-TEST_F(LayoutObjectTest, DISABLED_NeedsLayoutOverflowRecalc) {
+TEST_F(LayoutObjectTest, NeedsLayoutOverflowRecalc) {
if (!RuntimeEnabledFeatures::LayoutNGEnabled())
return;
@@ -1089,7 +1084,7 @@ TEST_F(LayoutObjectTest, DISABLED_NeedsLayoutOverflowRecalc) {
EXPECT_FALSE(other->NeedsLayoutOverflowRecalc());
auto* target_element = GetDocument().getElementById("target");
- target_element->SetInnerHTMLFromString("baz");
+ target_element->setInnerHTML("baz");
UpdateAllLifecyclePhasesForTest();
EXPECT_FALSE(wrapper->NeedsLayoutOverflowRecalc());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.cc
new file mode 100644
index 00000000000..41956979cb9
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.cc
@@ -0,0 +1,14 @@
+// Copyright 2020 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_outside_list_marker.h"
+
+namespace blink {
+
+LayoutOutsideListMarker::LayoutOutsideListMarker(Element* element)
+ : LayoutListMarker(element) {}
+
+LayoutOutsideListMarker::~LayoutOutsideListMarker() = default;
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.h b/chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.h
new file mode 100644
index 00000000000..20ff17c14a8
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/layout_outside_list_marker.h
@@ -0,0 +1,33 @@
+// Copyright 2020 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_OUTSIDE_LIST_MARKER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_OUTSIDE_LIST_MARKER_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/layout_list_marker.h"
+
+namespace blink {
+
+// Used to layout the list item's outside marker.
+// The LayoutOutsideListMarker always has to be a child of a LayoutListItem.
+class CORE_EXPORT LayoutOutsideListMarker final : public LayoutListMarker {
+ public:
+ explicit LayoutOutsideListMarker(Element*);
+ ~LayoutOutsideListMarker() override;
+
+ const char* GetName() const override { return "LayoutOutsideListMarker"; }
+
+ private:
+ bool IsOfType(LayoutObjectType type) const override {
+ return type == kLayoutObjectOutsideListMarker ||
+ LayoutListMarker::IsOfType(type);
+ }
+};
+
+DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutOutsideListMarker, IsOutsideListMarker());
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_OUTSIDE_LIST_MARKER_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc b/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc
index b74dbbaca8b..e5b86b519aa 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc
@@ -117,7 +117,7 @@ void LayoutReplaced::IntrinsicSizeChanged() {
int scaled_height =
static_cast<int>(kDefaultHeight * StyleRef().EffectiveZoom());
intrinsic_size_ = LayoutSize(scaled_width, scaled_height);
- SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kSizeChanged);
}
@@ -152,7 +152,7 @@ static inline bool LayoutObjectHasAspectRatio(
const LayoutObject* layout_object) {
DCHECK(layout_object);
return layout_object->IsImage() || layout_object->IsCanvas() ||
- layout_object->IsVideo();
+ IsA<LayoutVideo>(layout_object);
}
void LayoutReplaced::RecalcVisualOverflow() {
@@ -724,12 +724,14 @@ void LayoutReplaced::ComputeIntrinsicSizingInfo(
static inline LayoutUnit ResolveWidthForRatio(LayoutUnit height,
const FloatSize& aspect_ratio) {
- return LayoutUnit(height * aspect_ratio.Width() / aspect_ratio.Height());
+ return LayoutUnit(height.ToDouble() * aspect_ratio.Width() /
+ aspect_ratio.Height());
}
static inline LayoutUnit ResolveHeightForRatio(LayoutUnit width,
const FloatSize& aspect_ratio) {
- return LayoutUnit(width * aspect_ratio.Height() / aspect_ratio.Width());
+ return LayoutUnit(width.ToDouble() * aspect_ratio.Height() /
+ aspect_ratio.Width());
}
LayoutUnit LayoutReplaced::ComputeConstrainedLogicalWidth(
@@ -893,60 +895,45 @@ LayoutUnit LayoutReplaced::ComputeReplacedLogicalHeight(
IntrinsicLogicalHeight());
}
-void LayoutReplaced::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
- min_logical_width = max_logical_width = IntrinsicLogicalWidth();
+MinMaxSizes LayoutReplaced::ComputeIntrinsicLogicalWidths() const {
+ MinMaxSizes sizes;
+ sizes += BorderAndPaddingLogicalWidth() + IntrinsicLogicalWidth();
+ return sizes;
}
-void LayoutReplaced::ComputePreferredLogicalWidths() {
- DCHECK(PreferredLogicalWidthsDirty());
+MinMaxSizes LayoutReplaced::PreferredLogicalWidths() const {
+ MinMaxSizes sizes;
// We cannot resolve some logical width here (i.e. percent, fill-available or
// fit-content) as the available logical width may not be set on our
// containing block.
const Length& logical_width = StyleRef().LogicalWidth();
if (logical_width.IsPercentOrCalc() || logical_width.IsFillAvailable() ||
- logical_width.IsFitContent())
- ComputeIntrinsicLogicalWidths(min_preferred_logical_width_,
- max_preferred_logical_width_);
- else
- min_preferred_logical_width_ = max_preferred_logical_width_ =
- ComputeReplacedLogicalWidth(kComputePreferred);
+ logical_width.IsFitContent()) {
+ sizes = IntrinsicLogicalWidths();
+ sizes -= BorderAndPaddingLogicalWidth();
+ } else {
+ sizes = ComputeReplacedLogicalWidth(kComputePreferred);
+ }
const ComputedStyle& style_to_use = StyleRef();
if (style_to_use.LogicalWidth().IsPercentOrCalc() ||
style_to_use.LogicalMaxWidth().IsPercentOrCalc())
- min_preferred_logical_width_ = LayoutUnit();
+ sizes.min_size = LayoutUnit();
if (style_to_use.LogicalMinWidth().IsFixed() &&
style_to_use.LogicalMinWidth().Value() > 0) {
- max_preferred_logical_width_ =
- std::max(max_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- style_to_use.LogicalMinWidth().Value()));
- min_preferred_logical_width_ =
- std::max(min_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- style_to_use.LogicalMinWidth().Value()));
+ sizes.Encompass(AdjustContentBoxLogicalWidthForBoxSizing(
+ style_to_use.LogicalMinWidth().Value()));
}
if (style_to_use.LogicalMaxWidth().IsFixed()) {
- max_preferred_logical_width_ =
- std::min(max_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- style_to_use.LogicalMaxWidth().Value()));
- min_preferred_logical_width_ =
- std::min(min_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- style_to_use.LogicalMaxWidth().Value()));
+ sizes.Constrain(AdjustContentBoxLogicalWidthForBoxSizing(
+ style_to_use.LogicalMaxWidth().Value()));
}
- LayoutUnit border_and_padding = BorderAndPaddingLogicalWidth();
- min_preferred_logical_width_ += border_and_padding;
- max_preferred_logical_width_ += border_and_padding;
-
- ClearPreferredLogicalWidthsDirty();
+ sizes += BorderAndPaddingLogicalWidth();
+ return sizes;
}
static std::pair<LayoutUnit, LayoutUnit> SelectionTopAndBottom(
@@ -975,14 +962,15 @@ static std::pair<LayoutUnit, LayoutUnit> SelectionTopAndBottom(
// Step 2: Return the logical top and bottom of the line box.
// TODO(layout-dev): Use selection top & bottom instead of line's, or decide
// if we still want to distinguish line and selection heights in NG.
- const ComputedStyle& line_style = line_box.CurrentStyle();
+ const ComputedStyle& line_style = line_box.Current().Style();
const WritingMode writing_mode = line_style.GetWritingMode();
const TextDirection text_direction = line_style.Direction();
- const PhysicalOffset line_box_offset = line_box.CurrentOffset();
- const PhysicalSize line_box_size = line_box.CurrentSize();
+ const PhysicalOffset line_box_offset =
+ line_box.Current().OffsetInContainerBlock();
+ const PhysicalSize line_box_size = line_box.Current().Size();
const LogicalOffset logical_offset = line_box_offset.ConvertToLogical(
writing_mode, text_direction, fragmentainer->Size(),
- line_box.CurrentSize());
+ line_box.Current().Size());
const LogicalSize logical_size =
line_box_size.ConvertToLogical(writing_mode);
return {logical_offset.block_offset,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_replaced.h b/chromium/third_party/blink/renderer/core/layout/layout_replaced.h
index dfb6906f5d1..d501a40eef6 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_replaced.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_replaced.h
@@ -90,11 +90,6 @@ class CORE_EXPORT LayoutReplaced : public LayoutBox {
void Paint(const PaintInfo&) const override;
- // Replaced objects often have contents to paint.
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override {
- return false;
- }
-
// This function is public only so we can call it when computing
// intrinsic size in LayoutNG.
virtual void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const;
@@ -136,8 +131,7 @@ class CORE_EXPORT LayoutReplaced : public LayoutBox {
void ComputePositionedLogicalHeight(
LogicalExtentComputedValues&) const override;
- void ComputeIntrinsicLogicalWidths(LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const final;
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const final;
// This function calculates the placement of the replaced contents. It takes
// intrinsic size of the replaced contents, stretch to fit CSS content box
@@ -164,7 +158,7 @@ class CORE_EXPORT LayoutReplaced : public LayoutBox {
}
private:
- void ComputePreferredLogicalWidths() final;
+ MinMaxSizes PreferredLogicalWidths() const final;
void ComputeIntrinsicSizingInfoForReplacedContent(IntrinsicSizingInfo&) const;
FloatSize ConstrainIntrinsicSizeToMinMax(const IntrinsicSizingInfo&) const;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_replaced_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_replaced_test.cc
index 5b157b6a6c8..138bee7164b 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_replaced_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_replaced_test.cc
@@ -26,7 +26,8 @@ TEST_F(LayoutReplacedTest, InvalidateAfterAddingBorderRadius) {
target_element->setAttribute(html_names::kStyleAttr, "border-radius: 10px");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(layout_object->NeedsPaintPropertyUpdate());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_ruby_base.cc b/chromium/third_party/blink/renderer/core/layout/layout_ruby_base.cc
index 9b21b0bf71f..1bb9a9e2685 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_ruby_base.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_ruby_base.cc
@@ -65,9 +65,9 @@ void LayoutRubyBase::MoveChildren(LayoutRubyBase* to_base,
else
MoveBlockChildren(to_base, before_child);
- SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kUnknown);
- to_base->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ to_base->SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kUnknown);
}
@@ -152,7 +152,7 @@ void LayoutRubyBase::AdjustInlineDirectionLineBounds(
unsigned expansion_opportunity_count,
LayoutUnit& logical_left,
LayoutUnit& logical_width) const {
- int max_preferred_logical_width = MaxPreferredLogicalWidth().ToInt();
+ int max_preferred_logical_width = PreferredLogicalWidths().max_size.ToInt();
if (max_preferred_logical_width >= logical_width)
return;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_ruby_text.cc b/chromium/third_party/blink/renderer/core/layout/layout_ruby_text.cc
index 5990208b8f8..730b2a35e1c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_ruby_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_ruby_text.cc
@@ -64,7 +64,7 @@ void LayoutRubyText::AdjustInlineDirectionLineBounds(
return LayoutBlockFlow::AdjustInlineDirectionLineBounds(
expansion_opportunity_count, logical_left, logical_width);
- int max_preferred_logical_width = MaxPreferredLogicalWidth().ToInt();
+ int max_preferred_logical_width = PreferredLogicalWidths().max_size.ToInt();
if (max_preferred_logical_width >= logical_width)
return;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_search_field.cc b/chromium/third_party/blink/renderer/core/layout/layout_search_field.cc
deleted file mode 100644
index 54159e3348f..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/layout_search_field.cc
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * Copyright (C) 2006, 2007, 2010 Apple Inc. All rights reserved.
- * (C) 2008 Torch Mobile Inc. All rights reserved.
- * (http://www.torchmobile.com/)
- * Copyright (C) 2010 Google Inc. All rights reserved.
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#include "third_party/blink/renderer/core/layout/layout_search_field.h"
-
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
-#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
-#include "third_party/blink/renderer/core/input_type_names.h"
-
-namespace blink {
-
-LayoutSearchField::LayoutSearchField(HTMLInputElement* element)
- : LayoutTextControlSingleLine(element) {
- DCHECK_EQ(element->type(), input_type_names::kSearch);
-}
-
-LayoutSearchField::~LayoutSearchField() = default;
-
-inline Element* LayoutSearchField::SearchDecorationElement() const {
- return InputElement()->UserAgentShadowRoot()->getElementById(
- shadow_element_names::SearchDecoration());
-}
-
-inline Element* LayoutSearchField::CancelButtonElement() const {
- return InputElement()->UserAgentShadowRoot()->getElementById(
- shadow_element_names::ClearButton());
-}
-
-LayoutUnit LayoutSearchField::ComputeControlLogicalHeight(
- LayoutUnit line_height,
- LayoutUnit non_content_height) const {
- Element* search_decoration = SearchDecorationElement();
- if (LayoutBox* decoration_layout_object =
- search_decoration ? search_decoration->GetLayoutBox() : nullptr) {
- decoration_layout_object->UpdateLogicalHeight();
- non_content_height =
- max(non_content_height,
- decoration_layout_object->BorderAndPaddingLogicalHeight() +
- decoration_layout_object->MarginLogicalHeight());
- line_height = max(line_height, decoration_layout_object->LogicalHeight());
- }
- Element* cancel_button = CancelButtonElement();
- if (LayoutBox* cancel_layout_object =
- cancel_button ? cancel_button->GetLayoutBox() : nullptr) {
- cancel_layout_object->UpdateLogicalHeight();
- non_content_height =
- max(non_content_height,
- cancel_layout_object->BorderAndPaddingLogicalHeight() +
- cancel_layout_object->MarginLogicalHeight());
- line_height = max(line_height, cancel_layout_object->LogicalHeight());
- }
-
- return line_height + non_content_height;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_search_field.h b/chromium/third_party/blink/renderer/core/layout/layout_search_field.h
deleted file mode 100644
index f9146cab43b..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/layout_search_field.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2008 Torch Mobile Inc. All rights reserved.
- * (http://www.torchmobile.com/)
- * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public License
- * along with this library; see the file COPYING.LIB. If not, write to
- * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- */
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_SEARCH_FIELD_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_SEARCH_FIELD_H_
-
-#include "third_party/blink/renderer/core/layout/layout_text_control_single_line.h"
-
-namespace blink {
-
-class HTMLInputElement;
-
-class LayoutSearchField final : public LayoutTextControlSingleLine {
- public:
- LayoutSearchField(HTMLInputElement*);
- ~LayoutSearchField() override;
-
- private:
- LayoutUnit ComputeControlLogicalHeight(
- LayoutUnit line_height,
- LayoutUnit non_content_height) const override;
-
- Element* SearchDecorationElement() const;
- Element* CancelButtonElement() const;
-};
-
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutSearchField, IsTextField());
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_SEARCH_FIELD_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.cc b/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
index 3ff579f8fe0..20ab99f71b4 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.cc
@@ -6,7 +6,9 @@
#include "cc/layers/heads_up_display_layer.h"
#include "cc/layers/picture_layer.h"
-#include "third_party/blink/public/platform/web_pointer_event.h"
+#include "cc/trees/layer_tree_host.h"
+#include "third_party/blink/public/common/input/web_pointer_event.h"
+#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
@@ -26,12 +28,20 @@
namespace blink {
-static constexpr base::TimeDelta kTimerDelay =
- base::TimeDelta::FromMilliseconds(500);
-static const float kMovementThreshold = 3.0; // CSS pixels.
+using ReattachHook = LayoutShiftTracker::ReattachHook;
-static FloatPoint LogicalStart(const FloatRect& rect,
- const LayoutObject& object) {
+namespace {
+
+ReattachHook& GetReattachHook() {
+ DEFINE_STATIC_LOCAL(Persistent<ReattachHook>, hook,
+ (MakeGarbageCollected<ReattachHook>()));
+ return *hook;
+}
+
+constexpr base::TimeDelta kTimerDelay = base::TimeDelta::FromMilliseconds(500);
+const float kMovementThreshold = 3.0; // CSS pixels.
+
+FloatPoint LogicalStart(const FloatRect& rect, const LayoutObject& object) {
const ComputedStyle* style = object.Style();
DCHECK(style);
auto logical =
@@ -40,59 +50,67 @@ static FloatPoint LogicalStart(const FloatRect& rect,
return FloatPoint(logical.InlineStart(), logical.BlockStart());
}
-static float GetMoveDistance(const FloatRect& old_rect,
- const FloatRect& new_rect,
- const LayoutObject& object) {
+float GetMoveDistance(const FloatRect& old_rect,
+ const FloatRect& new_rect,
+ const LayoutObject& object) {
FloatSize location_delta =
LogicalStart(new_rect, object) - LogicalStart(old_rect, object);
return std::max(fabs(location_delta.Width()), fabs(location_delta.Height()));
}
-static bool EqualWithinMovementThreshold(const FloatPoint& a,
- const FloatPoint& b,
- const LayoutObject& object) {
+bool EqualWithinMovementThreshold(const FloatPoint& a,
+ const FloatPoint& b,
+ const LayoutObject& object) {
float threshold_physical_px =
kMovementThreshold * object.StyleRef().EffectiveZoom();
return fabs(a.X() - b.X()) < threshold_physical_px &&
fabs(a.Y() - b.Y()) < threshold_physical_px;
}
-static bool SmallerThanRegionGranularity(const FloatRect& rect) {
+bool SmallerThanRegionGranularity(const FloatRect& rect) {
// The region uses integer coordinates, so the rects are snapped to
// pixel boundaries. Ignore rects smaller than half a pixel.
return rect.Width() < 0.5 || rect.Height() < 0.5;
}
-static const PropertyTreeState PropertyTreeStateFor(
- const LayoutObject& object) {
+const PropertyTreeState PropertyTreeStateFor(const LayoutObject& object) {
return object.FirstFragment().LocalBorderBoxProperties();
}
-static void RegionToTracedValue(const LayoutShiftRegion& region,
- TracedValue& value) {
+void RectToTracedValue(const IntRect& rect,
+ TracedValue& value,
+ const char* key = nullptr) {
+ if (key)
+ value.BeginArray(key);
+ else
+ value.BeginArray();
+ value.PushInteger(rect.X());
+ value.PushInteger(rect.Y());
+ value.PushInteger(rect.Width());
+ value.PushInteger(rect.Height());
+ value.EndArray();
+}
+
+void RegionToTracedValue(const LayoutShiftRegion& region, TracedValue& value) {
Region blink_region;
for (IntRect rect : region.GetRects())
blink_region.Unite(Region(rect));
value.BeginArray("region_rects");
- for (const IntRect& rect : blink_region.Rects()) {
- value.BeginArray();
- value.PushInteger(rect.X());
- value.PushInteger(rect.Y());
- value.PushInteger(rect.Width());
- value.PushInteger(rect.Height());
- value.EndArray();
- }
+ for (const IntRect& rect : blink_region.Rects())
+ RectToTracedValue(rect, value);
value.EndArray();
}
#if DCHECK_IS_ON()
-static bool ShouldLog(const LocalFrame& frame) {
+bool ShouldLog(const LocalFrame& frame) {
const String& url = frame.GetDocument()->Url().GetString();
- return !url.StartsWith("chrome-devtools:") && !url.StartsWith("devtools:");
+ return !url.StartsWith("devtools:");
}
#endif
+} // namespace
+
LayoutShiftTracker::LayoutShiftTracker(LocalFrameView* frame_view)
: frame_view_(frame_view),
score_(0.0),
@@ -200,6 +218,60 @@ void LayoutShiftTracker::ObjectShifted(
region_.AddRect(visible_old_rect);
region_.AddRect(visible_new_rect);
+
+ if (Node* node = source.GetNode()) {
+ MaybeRecordAttribution(
+ {DOMNodeIds::IdForNode(node), visible_old_rect, visible_new_rect});
+ }
+}
+
+LayoutShiftTracker::Attribution::Attribution() : node_id(kInvalidDOMNodeId) {}
+LayoutShiftTracker::Attribution::Attribution(DOMNodeId node_id_arg,
+ IntRect old_visual_rect_arg,
+ IntRect new_visual_rect_arg)
+ : node_id(node_id_arg),
+ old_visual_rect(old_visual_rect_arg),
+ new_visual_rect(new_visual_rect_arg) {}
+
+LayoutShiftTracker::Attribution::operator bool() const {
+ return node_id != kInvalidDOMNodeId;
+}
+
+bool LayoutShiftTracker::Attribution::Encloses(const Attribution& other) const {
+ return old_visual_rect.Contains(other.old_visual_rect) &&
+ new_visual_rect.Contains(other.new_visual_rect);
+}
+
+int LayoutShiftTracker::Attribution::Area() const {
+ int old_area = old_visual_rect.Width() * old_visual_rect.Height();
+ int new_area = new_visual_rect.Width() * new_visual_rect.Height();
+
+ IntRect intersection = Intersection(old_visual_rect, new_visual_rect);
+ int shared_area = intersection.Width() * intersection.Height();
+ return old_area + new_area - shared_area;
+}
+
+bool LayoutShiftTracker::Attribution::MoreImpactfulThan(
+ const Attribution& other) const {
+ return Area() > other.Area();
+}
+
+void LayoutShiftTracker::MaybeRecordAttribution(
+ const Attribution& attribution) {
+ Attribution* smallest = nullptr;
+ for (auto& slot : attributions_) {
+ if (!slot || attribution.Encloses(slot)) {
+ slot = attribution;
+ return;
+ }
+ if (slot.Encloses(attribution))
+ return;
+ if (!smallest || smallest->MoreImpactfulThan(slot))
+ smallest = &slot;
+ }
+ // No empty slots or redundancies. Replace smallest existing slot if larger.
+ if (attribution.MoreImpactfulThan(*smallest))
+ *smallest = attribution;
}
void LayoutShiftTracker::NotifyObjectPrePaint(
@@ -288,6 +360,7 @@ void LayoutShiftTracker::NotifyPrePaintFinished() {
frame_max_distance_ = 0.0;
frame_scroll_delta_ = ScrollOffset();
+ attributions_.fill(Attribution());
}
void LayoutShiftTracker::ReportShift(double score_delta,
@@ -378,13 +451,14 @@ void LayoutShiftTracker::UpdateInputTimestamp(base::TimeTicks timestamp) {
}
}
-void LayoutShiftTracker::NotifyScroll(ScrollType scroll_type,
+void LayoutShiftTracker::NotifyScroll(mojom::blink::ScrollType scroll_type,
ScrollOffset delta) {
frame_scroll_delta_ += delta;
// Only set observed_input_or_scroll_ for user-initiated scrolls, and not
// other scrolls such as hash fragment navigations.
- if (scroll_type == kUserScroll || scroll_type == kCompositorScroll)
+ if (scroll_type == mojom::blink::ScrollType::kUser ||
+ scroll_type == mojom::blink::ScrollType::kCompositor)
observed_input_or_scroll_ = true;
}
@@ -413,20 +487,39 @@ std::unique_ptr<TracedValue> LayoutShiftTracker::PerFrameTraceData(
RegionToTracedValue(region_, *value);
value->SetBoolean("is_main_frame", frame_view_->GetFrame().IsMainFrame());
value->SetBoolean("had_recent_input", input_detected);
+ AttributionsToTracedValue(*value);
return value;
}
-void LayoutShiftTracker::SetLayoutShiftRects(const Vector<IntRect>& int_rects) {
- // Store the layout shift rects in the HUD layer.
- GraphicsLayer* root_graphics_layer =
- frame_view_->GetLayoutView()->Compositor()->RootGraphicsLayer();
- if (!root_graphics_layer)
+void LayoutShiftTracker::AttributionsToTracedValue(TracedValue& value) const {
+ const Attribution* it = attributions_.begin();
+ if (!*it)
return;
- cc::Layer* cc_layer = root_graphics_layer->CcLayer();
- if (!cc_layer)
- return;
- if (cc_layer->layer_tree_host()) {
+ bool should_include_names;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(
+ TRACE_DISABLED_BY_DEFAULT("layout_shift.debug"), &should_include_names);
+
+ value.BeginArray("impacted_nodes");
+ while (it != attributions_.end() && it->node_id != kInvalidDOMNodeId) {
+ value.BeginDictionary();
+ value.SetInteger("node_id", it->node_id);
+ RectToTracedValue(it->old_visual_rect, value, "old_rect");
+ RectToTracedValue(it->new_visual_rect, value, "new_rect");
+ if (should_include_names) {
+ Node* node = DOMNodeIds::NodeForId(it->node_id);
+ value.SetString("debug_name", node ? node->DebugName() : "");
+ }
+ value.EndDictionary();
+ it++;
+ }
+ value.EndArray();
+}
+
+void LayoutShiftTracker::SetLayoutShiftRects(const Vector<IntRect>& int_rects) {
+ // Store the layout shift rects in the HUD layer.
+ auto* cc_layer = frame_view_->RootCcLayer();
+ if (cc_layer && cc_layer->layer_tree_host()) {
if (!cc_layer->layer_tree_host()->GetDebugState().show_layout_shift_regions)
return;
if (cc_layer->layer_tree_host()->hud_layer()) {
@@ -443,4 +536,61 @@ void LayoutShiftTracker::SetLayoutShiftRects(const Vector<IntRect>& int_rects) {
}
}
+ReattachHook::Scope::Scope(const Node& node) : active_(node.GetLayoutObject()) {
+ if (active_) {
+ auto& hook = GetReattachHook();
+ outer_ = hook.scope_;
+ hook.scope_ = this;
+ }
+}
+
+ReattachHook::Scope::~Scope() {
+ if (active_) {
+ auto& hook = GetReattachHook();
+ hook.scope_ = outer_;
+ if (!outer_)
+ hook.visual_rects_.clear();
+ }
+}
+
+void ReattachHook::NotifyDetach(const Node& node) {
+ auto& hook = GetReattachHook();
+ if (!hook.scope_)
+ return;
+ auto* layout_object = node.GetLayoutObject();
+ if (!layout_object)
+ return;
+ auto& map = hook.visual_rects_;
+ auto& fragment = layout_object->GetMutableForPainting().FirstFragment();
+
+ // Save the visual rect for restoration on future reattachment.
+ IntRect visual_rect = fragment.VisualRect();
+ if (visual_rect.IsEmpty())
+ return;
+ map.Set(&node, visual_rect);
+}
+
+void ReattachHook::NotifyAttach(const Node& node) {
+ auto& hook = GetReattachHook();
+ if (!hook.scope_)
+ return;
+ auto* layout_object = node.GetLayoutObject();
+ if (!layout_object)
+ return;
+ auto& map = hook.visual_rects_;
+ auto& fragment = layout_object->GetMutableForPainting().FirstFragment();
+
+ // Restore the visual rect that was saved during detach. Note: this does not
+ // affect paint invalidation; we will fully invalidate the new layout object.
+ auto iter = map.find(&node);
+ if (iter == map.end())
+ return;
+ IntRect visual_rect = iter->value;
+ fragment.SetVisualRect(visual_rect);
+}
+
+void ReattachHook::Trace(Visitor* visitor) {
+ visitor->Trace(visual_rects_);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.h b/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.h
index 79185e29907..24bbd221df5 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker.h
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/layout/layout_shift_region.h"
#include "third_party/blink/renderer/core/scroll/scroll_types.h"
#include "third_party/blink/renderer/platform/geometry/region.h"
+#include "third_party/blink/renderer/platform/graphics/dom_node_id.h"
#include "third_party/blink/renderer/platform/timer.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -48,7 +49,7 @@ class CORE_EXPORT LayoutShiftTracker {
FloatSize paint_offset_delta);
void NotifyPrePaintFinished();
void NotifyInput(const WebInputEvent&);
- void NotifyScroll(ScrollType, ScrollOffset delta);
+ void NotifyScroll(mojom::blink::ScrollType, ScrollOffset delta);
void NotifyViewportSizeChanged();
bool IsActive();
double Score() const { return score_; }
@@ -60,6 +61,31 @@ class CORE_EXPORT LayoutShiftTracker {
return most_recent_input_timestamp_;
}
+ // Saves and restores visual rects on layout objects when a layout tree is
+ // rebuilt by Node::ReattachLayoutTree.
+ class ReattachHook : public GarbageCollected<ReattachHook> {
+ public:
+ ReattachHook() : scope_(nullptr) {}
+ void Trace(Visitor*);
+
+ class Scope {
+ public:
+ Scope(const Node&);
+ ~Scope();
+
+ private:
+ bool active_;
+ Scope* outer_;
+ };
+
+ static void NotifyDetach(const Node&);
+ static void NotifyAttach(const Node&);
+
+ private:
+ Scope* scope_;
+ HeapHashMap<Member<const Node>, IntRect> visual_rects_;
+ };
+
private:
void ObjectShifted(const LayoutObject&,
const PropertyTreeState&,
@@ -70,6 +96,7 @@ class CORE_EXPORT LayoutShiftTracker {
void TimerFired(TimerBase*) {}
std::unique_ptr<TracedValue> PerFrameTraceData(double score_delta,
bool input_detected) const;
+ void AttributionsToTracedValue(TracedValue&) const;
double SubframeWeightingFactor() const;
void SetLayoutShiftRects(const Vector<IntRect>& int_rects);
void UpdateInputTimestamp(base::TimeTicks timestamp);
@@ -132,6 +159,29 @@ class CORE_EXPORT LayoutShiftTracker {
// User input includes window resizing but not scrolling.
base::TimeTicks most_recent_input_timestamp_;
bool most_recent_input_timestamp_initialized_;
+
+ struct Attribution {
+ DOMNodeId node_id;
+ IntRect old_visual_rect;
+ IntRect new_visual_rect;
+
+ Attribution();
+ Attribution(DOMNodeId node_id,
+ IntRect old_visual_rect,
+ IntRect new_visual_rect);
+
+ explicit operator bool() const;
+ bool Encloses(const Attribution&) const;
+ bool MoreImpactfulThan(const Attribution&) const;
+ int Area() const;
+ };
+ static constexpr int kMaxAttributions = 5;
+
+ void MaybeRecordAttribution(const Attribution&);
+
+ // Nodes that have contributed to the impact region for the current frame, for
+ // use in trace event. Only populated while tracing.
+ std::array<Attribution, kMaxAttributions> attributions_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc
index 7d60704a20d..4418bcf5202 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_shift_tracker_test.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/renderer/core/layout/layout_shift_tracker.h"
-#include "third_party/blink/public/platform/web_mouse_event.h"
+#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include "third_party/blink/renderer/core/svg_names.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
@@ -30,14 +30,13 @@ class LayoutShiftTrackerTest : public RenderingTest {
void SimulateInput() {
GetLayoutShiftTracker().NotifyInput(WebMouseEvent(
- WebInputEvent::kMouseDown, WebFloatPoint(), WebFloatPoint(),
+ WebInputEvent::kMouseDown, gfx::PointF(), gfx::PointF(),
WebPointerProperties::Button::kLeft, 0,
WebInputEvent::Modifiers::kLeftButtonDown, base::TimeTicks::Now()));
}
void UpdateAllLifecyclePhases() {
- GetFrameView().UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetFrameView().UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
}
};
@@ -81,7 +80,8 @@ TEST_F(LayoutShiftTrackerTest, CompositedShiftBeforeFirstPaint) {
GetDocument().getElementById("B")->setAttribute(html_names::kClassAttr,
AtomicString("tr"));
- GetFrameView().UpdateLifecycleToCompositingCleanPlusScrolling();
+ GetFrameView().UpdateLifecycleToCompositingCleanPlusScrolling(
+ DocumentUpdateReason::kTest);
GetDocument().getElementById("A")->setAttribute(html_names::kClassAttr,
AtomicString("hide"));
UpdateAllLifecyclePhases();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_slider.cc b/chromium/third_party/blink/renderer/core/layout/layout_slider.cc
index f41bbd8335c..21dcbb6421d 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_slider.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_slider.cc
@@ -19,10 +19,7 @@
#include "third_party/blink/renderer/core/layout/layout_slider.h"
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
-#include "third_party/blink/renderer/core/html/forms/slider_thumb_element.h"
-#include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
@@ -48,23 +45,14 @@ LayoutUnit LayoutSlider::BaselinePosition(
return Size().Height() + MarginTop();
}
-void LayoutSlider::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
- max_logical_width =
+MinMaxSizes LayoutSlider::ComputeIntrinsicLogicalWidths() const {
+ MinMaxSizes sizes;
+ sizes += BorderAndPaddingLogicalWidth() + ScrollbarLogicalWidth();
+ sizes.max_size +=
LayoutUnit(kDefaultTrackLength * StyleRef().EffectiveZoom());
if (!StyleRef().Width().IsPercentOrCalc())
- min_logical_width = max_logical_width;
-}
-
-inline SliderThumbElement* LayoutSlider::GetSliderThumbElement() const {
- return To<SliderThumbElement>(
- To<Element>(GetNode())->UserAgentShadowRoot()->getElementById(
- shadow_element_names::SliderThumb()));
-}
-
-bool LayoutSlider::InDragMode() const {
- return GetSliderThumbElement()->IsActive();
+ sizes.min_size = sizes.max_size;
+ return sizes;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_slider.h b/chromium/third_party/blink/renderer/core/layout/layout_slider.h
index 09d62822dc7..401f30d251b 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_slider.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_slider.h
@@ -23,11 +23,11 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
class HTMLInputElement;
-class SliderThumbElement;
class CORE_EXPORT LayoutSlider final : public LayoutFlexibleBox {
public:
@@ -36,8 +36,6 @@ class CORE_EXPORT LayoutSlider final : public LayoutFlexibleBox {
explicit LayoutSlider(HTMLInputElement*);
~LayoutSlider() override;
- bool InDragMode() const;
-
const char* GetName() const override { return "LayoutSlider"; }
private:
@@ -50,14 +48,15 @@ class CORE_EXPORT LayoutSlider final : public LayoutFlexibleBox {
bool first_line,
LineDirectionMode,
LinePositionMode = kPositionOnContainingLine) const override;
- void ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const override;
-
- SliderThumbElement* GetSliderThumbElement() const;
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const override;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutSlider, IsSlider());
+template <>
+struct DowncastTraits<LayoutSlider> {
+ static bool AllowFrom(const LayoutObject& object) {
+ return object.IsSlider();
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_slider_container.cc b/chromium/third_party/blink/renderer/core/layout/layout_slider_container.cc
index b88895afa6f..4df8effbab1 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_slider_container.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_slider_container.cc
@@ -51,22 +51,13 @@ inline static Decimal SliderPosition(HTMLInputElement* element) {
return step_range.ProportionFromValue(step_range.ClampValue(old_value));
}
-inline static bool HasVerticalAppearance(HTMLInputElement* input) {
- DCHECK(input->GetLayoutObject());
- if (!input->GetLayoutObject() || !input->GetLayoutObject()->Style())
- return false;
- const ComputedStyle& slider_style = input->GetLayoutObject()->StyleRef();
- return slider_style.EffectiveAppearance() == kSliderVerticalPart;
-}
-
void LayoutSliderContainer::ComputeLogicalHeight(
LayoutUnit logical_height,
LayoutUnit logical_top,
LogicalExtentComputedValues& computed_values) const {
auto* input = To<HTMLInputElement>(GetNode()->OwnerShadowHost());
- bool is_vertical = HasVerticalAppearance(input);
- if (input->GetLayoutObject()->IsSlider() && !is_vertical && input->list()) {
+ if (input->GetLayoutObject()->IsSlider() && input->list()) {
int offset_from_center =
LayoutTheme::GetTheme().SliderTickOffsetFromTrackCenter();
LayoutUnit track_height;
@@ -87,8 +78,6 @@ void LayoutSliderContainer::ComputeLogicalHeight(
LayoutBox::ComputeLogicalHeight(track_height, logical_top, computed_values);
return;
}
- if (is_vertical)
- logical_height = LayoutUnit(LayoutSlider::kDefaultTrackLength);
// FIXME: The trackHeight should have been added before updateLogicalHeight
// was called to avoid this hack.
@@ -97,9 +86,17 @@ void LayoutSliderContainer::ComputeLogicalHeight(
LayoutBox::ComputeLogicalHeight(logical_height, logical_top, computed_values);
}
+MinMaxSizes LayoutSliderContainer::ComputeIntrinsicLogicalWidths() const {
+ MinMaxSizes sizes;
+ sizes += LayoutUnit(LayoutSlider::kDefaultTrackLength *
+ StyleRef().EffectiveZoom()) +
+ BorderAndPaddingLogicalWidth();
+ return sizes;
+}
+
void LayoutSliderContainer::UpdateLayout() {
auto* input = To<HTMLInputElement>(GetNode()->OwnerShadowHost());
- bool is_vertical = HasVerticalAppearance(input);
+ const bool is_vertical = !StyleRef().IsHorizontalWritingMode();
Element* thumb_element = input->UserAgentShadowRoot()->getElementById(
shadow_element_names::SliderThumb());
@@ -131,8 +128,7 @@ void LayoutSliderContainer::UpdateLayout() {
LayoutUnit offset(percentage_offset * available_extent);
LayoutPoint thumb_location = thumb->Location();
if (is_vertical) {
- thumb_location.SetY(thumb_location.Y() + track->ContentHeight() -
- thumb->Size().Height() - offset);
+ thumb_location.SetY(thumb_location.Y() - offset);
} else if (StyleRef().IsLeftToRightDirection()) {
thumb_location.SetX(thumb_location.X() + offset);
} else {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_slider_container.h b/chromium/third_party/blink/renderer/core/layout/layout_slider_container.h
index bab81f70c04..9acb550efe3 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_slider_container.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_slider_container.h
@@ -46,6 +46,7 @@ class LayoutSliderContainer final : public LayoutFlexibleBox {
void ComputeLogicalHeight(LayoutUnit logical_height,
LayoutUnit logical_top,
LogicalExtentComputedValues&) const override;
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const override;
private:
void UpdateLayout() override;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_state.cc b/chromium/third_party/blink/renderer/core/layout/layout_state.cc
index fbc642e0cb4..c7258a54f38 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_state.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_state.cc
@@ -57,6 +57,11 @@ LayoutState::LayoutState(LayoutBox& layout_object,
height_offset_for_table_footers_ = next_->HeightOffsetForTableFooters();
layout_object.View()->PushLayoutState(*this);
+ if (const AtomicString& named_page = layout_object.StyleRef().Page())
+ page_name_ = named_page;
+ else
+ page_name_ = next_->page_name_;
+
if (layout_object.IsLayoutFlowThread()) {
// Entering a new pagination context.
pagination_offset_ = LayoutSize();
@@ -105,7 +110,7 @@ LayoutState::LayoutState(LayoutObject& root)
next_(root.View()->GetLayoutState()),
layout_object_(root) {
DCHECK(!next_);
- DCHECK(!root.IsLayoutView());
+ DCHECK(!IsA<LayoutView>(root));
root.View()->PushLayoutState(*this);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_state.h b/chromium/third_party/blink/renderer/core/layout/layout_state.h
index eb1b3ce09db..190e5ba2450 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_state.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_state.h
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
namespace blink {
@@ -90,6 +91,8 @@ class LayoutState {
height_offset_for_table_footers_ = offset;
}
+ const AtomicString& PageName() const { return page_name_; }
+
const LayoutSize& PaginationOffset() const { return pagination_offset_; }
bool ContainingBlockLogicalWidthChanged() const {
return containing_block_logical_width_changed_;
@@ -128,6 +131,8 @@ class LayoutState {
// paginated layout.
LayoutUnit height_offset_for_table_footers_;
+ AtomicString page_name_;
+
LayoutObject& layout_object_;
DISALLOW_COPY_AND_ASSIGN(LayoutState);
};
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table.cc b/chromium/third_party/blink/renderer/core/layout/layout_table.cc
index 33333b6b88e..2b41ff4843e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table.cc
@@ -310,11 +310,10 @@ bool LayoutTable::IsLogicalWidthAuto() const {
void LayoutTable::UpdateLogicalWidth() {
RecalcSectionsIfNeeded();
- // Recalculate preferred logical widths now, rather than relying on them being
- // lazily recalculated, via MinPreferredLogicalWidth() further below. We might
- // not even get there.
- if (PreferredLogicalWidthsDirty())
- ComputePreferredLogicalWidths();
+ // Recalculate the intrinsic logical widths now, rather than relying on them
+ // being lazily recalculated, via PreferredLogicalWidths() further below. We
+ // might not even get there.
+ UpdateCachedIntrinsicLogicalWidthsIfNeeded();
if (IsFlexItemIncludingDeprecatedAndNG() || IsGridItem()) {
// TODO(jfernandez): Investigate whether the grid layout algorithm provides
@@ -344,6 +343,8 @@ void LayoutTable::UpdateLogicalWidth() {
? PerpendicularContainingBlockLogicalHeight()
: available_logical_width;
+ MinMaxSizes preferred_logical_widths = PreferredLogicalWidths();
+
if (!IsLogicalWidthAuto()) {
SetLogicalWidth(ConvertStyleLogicalWidthToComputedWidth(
StyleRef().LogicalWidth(), container_width_in_inline_direction));
@@ -375,11 +376,11 @@ void LayoutTable::UpdateLogicalWidth() {
}
// Ensure we aren't bigger than our available width.
- LayoutUnit max_width = MaxPreferredLogicalWidth();
+ LayoutUnit max_width = preferred_logical_widths.max_size;
// scaledWidthFromPercentColumns depends on m_layoutStruct in
- // TableLayoutAlgorithmAuto, which maxPreferredLogicalWidth fills in. So
- // scaledWidthFromPercentColumns has to be called after
- // maxPreferredLogicalWidth.
+ // TableLayoutAlgorithmAuto, which |PreferredLogicalWidths()| fills in. So
+ // |ScaledWidthFromPercentColumns()| has to be called after
+ // |PreferredLogicalWidths()|.
LayoutUnit scaled_width = table_layout_->ScaledWidthFromPercentColumns() +
BordersPaddingAndSpacingInRowDirection();
max_width = std::max(scaled_width, max_width);
@@ -402,8 +403,8 @@ void LayoutTable::UpdateLogicalWidth() {
// Ensure we aren't smaller than our min preferred width. This MUST be done
// after 'max-width' as we ignore it if it means we wouldn't accommodate our
// content.
- SetLogicalWidth(
- LayoutUnit(std::max(LogicalWidth(), MinPreferredLogicalWidth()).Floor()));
+ SetLogicalWidth(LayoutUnit(
+ std::max(LogicalWidth(), preferred_logical_widths.min_size).Floor()));
// Ensure we aren't smaller than our min-width style.
const Length& style_min_logical_width = StyleRef().LogicalMinWidth();
@@ -431,7 +432,7 @@ void LayoutTable::UpdateLogicalWidth() {
// nor what authors expect.
// FIXME: When we convert to sub-pixel layout for tables we can remove the int
// conversion. http://crbug.com/241198
- DCHECK_GE(LogicalWidth().Floor(), MinPreferredLogicalWidth().Floor());
+ DCHECK_GE(LogicalWidth().Floor(), preferred_logical_widths.min_size.Floor());
}
// This method takes a ComputedStyle's logical width, min-width, or max-width
@@ -439,10 +440,10 @@ void LayoutTable::UpdateLogicalWidth() {
LayoutUnit LayoutTable::ConvertStyleLogicalWidthToComputedWidth(
const Length& style_logical_width,
LayoutUnit available_width) const {
- if (style_logical_width.IsIntrinsic())
- return ComputeIntrinsicLogicalWidthUsing(
- style_logical_width, available_width,
- BordersPaddingAndSpacingInRowDirection());
+ if (style_logical_width.IsIntrinsic()) {
+ return ComputeIntrinsicLogicalWidthUsing(style_logical_width,
+ available_width);
+ }
// HTML tables' width styles already include borders and paddings, but CSS
// tables' width styles do not.
@@ -974,6 +975,7 @@ void LayoutTable::ComputeVisualOverflow(bool) {
AddVisualOverflowFromTheme();
if (VisualOverflowRect() != previous_visual_overflow_rect) {
+ InvalidateIntersectionObserverCachedRects();
SetShouldCheckForPaintInvalidation();
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
}
@@ -1088,38 +1090,30 @@ void LayoutTable::PaintMask(const PaintInfo& paint_info,
TablePainter(*this).PaintMask(paint_info, paint_offset);
}
-void LayoutTable::ComputeIntrinsicLogicalWidths(LayoutUnit& min_width,
- LayoutUnit& max_width) const {
+MinMaxSizes LayoutTable::ComputeIntrinsicLogicalWidths() const {
RecalcSectionsIfNeeded();
// FIXME: Restructure the table layout code so that we can make this method
// const.
+ MinMaxSizes sizes;
const_cast<LayoutTable*>(this)->table_layout_->ComputeIntrinsicLogicalWidths(
- min_width, max_width);
+ sizes.min_size, sizes.max_size);
// FIXME: We should include captions widths here like we do in
// computePreferredLogicalWidths.
+ sizes += LayoutUnit(BordersPaddingAndSpacingInRowDirection().ToInt());
+ return sizes;
}
-void LayoutTable::ComputePreferredLogicalWidths() {
- DCHECK(PreferredLogicalWidthsDirty());
-
- ComputeIntrinsicLogicalWidths(min_preferred_logical_width_,
- max_preferred_logical_width_);
-
- int borders_padding_and_spacing =
- BordersPaddingAndSpacingInRowDirection().ToInt();
- min_preferred_logical_width_ += borders_padding_and_spacing;
- max_preferred_logical_width_ += borders_padding_and_spacing;
+MinMaxSizes LayoutTable::PreferredLogicalWidths() const {
+ MinMaxSizes sizes = IntrinsicLogicalWidths();
- table_layout_->ApplyPreferredLogicalWidthQuirks(min_preferred_logical_width_,
- max_preferred_logical_width_);
+ table_layout_->ApplyPreferredLogicalWidthQuirks(sizes.min_size,
+ sizes.max_size);
- for (unsigned i = 0; i < captions_.size(); i++) {
- min_preferred_logical_width_ = std::max(
- min_preferred_logical_width_, captions_[i]->MinPreferredLogicalWidth());
- // Note: using captions' min-width is intentional here:
- max_preferred_logical_width_ = std::max(
- max_preferred_logical_width_, captions_[i]->MinPreferredLogicalWidth());
+ for (const auto* caption : captions_) {
+ LayoutUnit min_preferred_logical_width =
+ caption->PreferredLogicalWidths().min_size;
+ sizes.Encompass(min_preferred_logical_width);
}
const ComputedStyle& style_to_use = StyleRef();
@@ -1127,14 +1121,8 @@ void LayoutTable::ComputePreferredLogicalWidths() {
// able to use percentage or calc values for min-width.
if (style_to_use.LogicalMinWidth().IsFixed() &&
style_to_use.LogicalMinWidth().Value() > 0) {
- max_preferred_logical_width_ =
- std::max(max_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- style_to_use.LogicalMinWidth().Value()));
- min_preferred_logical_width_ =
- std::max(min_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- style_to_use.LogicalMinWidth().Value()));
+ sizes.Encompass(AdjustBorderBoxLogicalWidthForBoxSizing(
+ style_to_use.LogicalMinWidth().Value()));
}
// FIXME: This should probably be checking for isSpecified since you should be
@@ -1142,10 +1130,9 @@ void LayoutTable::ComputePreferredLogicalWidths() {
if (style_to_use.LogicalMaxWidth().IsFixed()) {
// We don't constrain m_minPreferredLogicalWidth as the table should be at
// least the size of its min-content, regardless of 'max-width'.
- max_preferred_logical_width_ =
- std::min(max_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- style_to_use.LogicalMaxWidth().Value()));
+ sizes.max_size =
+ std::min(sizes.max_size, AdjustBorderBoxLogicalWidthForBoxSizing(
+ style_to_use.LogicalMaxWidth().Value()));
}
// 2 cases need this:
@@ -1154,13 +1141,8 @@ void LayoutTable::ComputePreferredLogicalWidths() {
// 2. We buggily calculate min > max for some tables with colspans and
// percent widths. See fast/table/spans-min-greater-than-max-crash.html and
// http://crbug.com/857185
- max_preferred_logical_width_ =
- std::max(min_preferred_logical_width_, max_preferred_logical_width_);
-
- // FIXME: We should be adding borderAndPaddingLogicalWidth here, but
- // m_tableLayout->computePreferredLogicalWidths already does, so a bunch of
- // tests break doing this naively.
- ClearPreferredLogicalWidthsDirty();
+ sizes.max_size = std::max(sizes.min_size, sizes.max_size);
+ return sizes;
}
LayoutTableSection* LayoutTable::TopNonEmptySection() const {
@@ -1865,11 +1847,6 @@ void LayoutTable::UpdateCollapsedOuterBorders() const {
max_border_end - collapsed_outer_border_end_;
}
-bool LayoutTable::PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
- return LayoutBlock::PaintedOutputOfObjectHasNoEffectRegardlessOfSize() &&
- !should_paint_all_collapsed_borders_;
-}
-
// LayoutNGTableCellInterface API
bool LayoutTable::IsFirstCell(const LayoutNGTableCellInterface& cell) const {
const LayoutTableCell& layout_cell = *cell.ToLayoutTableCell();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table.h b/chromium/third_party/blink/renderer/core/layout/layout_table.h
index 1c385155762..53978ca750e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table.h
@@ -427,7 +427,6 @@ class CORE_EXPORT LayoutTable final : public LayoutBlock,
void EnsureIsReadyForPaintInvalidation() override;
void InvalidatePaint(const PaintInvalidatorContext&) const override;
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override;
void ColumnStructureChanged();
// LayoutNGTableInterface methods start.
@@ -460,9 +459,8 @@ class CORE_EXPORT LayoutTable final : public LayoutBlock,
void PaintObject(const PaintInfo&,
const PhysicalOffset& paint_offset) const override;
void UpdateLayout() override;
- void ComputeIntrinsicLogicalWidths(LayoutUnit& min_width,
- LayoutUnit& max_width) const override;
- void ComputePreferredLogicalWidths() override;
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const override;
+ MinMaxSizes PreferredLogicalWidths() const override;
bool NodeAtPoint(HitTestResult&,
const HitTestLocation&,
const PhysicalOffset& accumulated_offset,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_caption.h b/chromium/third_party/blink/renderer/core/layout/layout_table_caption.h
index 240de49be66..5ade10c9191 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_caption.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_caption.h
@@ -62,8 +62,6 @@ class LayoutTableCaption : public LayoutBlockFlow {
LayoutTable* Table() const;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutTableCaption, IsTableCaption());
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_TABLE_CAPTION_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc
index 02b873d3be5..7d041319196 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc
@@ -87,12 +87,12 @@ void LayoutTableCell::WillBeRemovedFromTree() {
// remove-cell-with-border-box.html only passes with setNeedsLayout but
// other places use setChildNeedsLayout.
PreviousCell()->SetNeedsLayout(layout_invalidation_reason::kTableChanged);
- PreviousCell()->SetPreferredLogicalWidthsDirty();
+ PreviousCell()->SetIntrinsicLogicalWidthsDirty();
}
if (NextCell()) {
// TODO(dgrogan): Same as above re: setChildNeedsLayout vs setNeedsLayout.
NextCell()->SetNeedsLayout(layout_invalidation_reason::kTableChanged);
- NextCell()->SetPreferredLogicalWidthsDirty();
+ NextCell()->SetIntrinsicLogicalWidthsDirty();
}
}
@@ -100,17 +100,15 @@ unsigned LayoutTableCell::ParseColSpanFromDOM() const {
DCHECK(GetNode());
// TODO(dgrogan): HTMLTableCellElement::colSpan() already clamps to something
// smaller than maxColumnIndex; can we just DCHECK here?
- if (IsHTMLTableCellElement(*GetNode()))
- return std::min<unsigned>(ToHTMLTableCellElement(*GetNode()).colSpan(),
- kMaxColumnIndex);
+ if (auto* cell_element = DynamicTo<HTMLTableCellElement>(GetNode()))
+ return std::min<unsigned>(cell_element->colSpan(), kMaxColumnIndex);
return 1;
}
unsigned LayoutTableCell::ParseRowSpanFromDOM() const {
DCHECK(GetNode());
- if (IsHTMLTableCellElement(*GetNode()))
- return std::min<unsigned>(ToHTMLTableCellElement(*GetNode()).rowSpan(),
- kMaxRowIndex);
+ if (auto* cell_element = DynamicTo<HTMLTableCellElement>(GetNode()))
+ return std::min<unsigned>(cell_element->rowSpan(), kMaxRowIndex);
return 1;
}
@@ -123,11 +121,11 @@ void LayoutTableCell::UpdateColAndRowSpanFlags() {
void LayoutTableCell::ColSpanOrRowSpanChanged() {
DCHECK(GetNode());
- DCHECK(IsHTMLTableCellElement(*GetNode()));
+ DCHECK(IsA<HTMLTableCellElement>(*GetNode()));
UpdateColAndRowSpanFlags();
- SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kAttributeChanged);
if (Parent() && Section()) {
Section()->SetNeedsCellRecalc();
@@ -177,7 +175,7 @@ Length LayoutTableCell::LogicalWidthFromColumns(
return Length::Fixed(col_width_sum);
}
-void LayoutTableCell::ComputePreferredLogicalWidths() {
+MinMaxSizes LayoutTableCell::PreferredLogicalWidths() const {
// The child cells rely on the grids up in the sections to do their
// computePreferredLogicalWidths work. Normally the sections are set up
// early, as table cells are added, but relayout can cause the cells to be
@@ -189,13 +187,14 @@ void LayoutTableCell::ComputePreferredLogicalWidths() {
// notional height on the cell, such as can happen when a percent sized image
// scales up its width to match the available height. Setting a zero override
// height prevents this from happening.
+ auto* mutable_this = const_cast<LayoutTableCell*>(this);
LayoutUnit logical_height =
HasOverrideLogicalHeight() ? OverrideLogicalHeight() : LayoutUnit(-1);
if (logical_height > -1)
- SetOverrideLogicalHeight(LayoutUnit());
- LayoutBlockFlow::ComputePreferredLogicalWidths();
+ mutable_this->SetOverrideLogicalHeight(LayoutUnit());
+ MinMaxSizes sizes = LayoutBlockFlow::PreferredLogicalWidths();
if (logical_height > -1)
- SetOverrideLogicalHeight(logical_height);
+ mutable_this->SetOverrideLogicalHeight(logical_height);
if (GetNode() && StyleRef().AutoWrap()) {
// See if nowrap was set.
@@ -207,10 +206,11 @@ void LayoutTableCell::ComputePreferredLogicalWidths() {
// set on the cell. Even so, it is a WinIE/Moz trait to make the minwidth
// of the cell into the fixed width. They do this even in strict mode, so
// do not make this a quirk. Affected the top of hiptop.com.
- min_preferred_logical_width_ =
- std::max(LayoutUnit(w.Value()), min_preferred_logical_width_);
+ sizes.min_size = std::max(sizes.min_size, LayoutUnit(w.Value()));
}
}
+
+ return sizes;
}
void LayoutTableCell::ComputeIntrinsicPadding(int collapsed_height,
@@ -476,13 +476,13 @@ void LayoutTableCell::StyleDidChange(StyleDifference diff,
// TODO(dgrogan) Add a web test showing that SetChildNeedsLayout is
// needed instead of SetNeedsLayout.
PreviousCell()->SetChildNeedsLayout();
- PreviousCell()->SetPreferredLogicalWidthsDirty(kMarkOnlyThis);
+ PreviousCell()->SetIntrinsicLogicalWidthsDirty(kMarkOnlyThis);
}
if (NextCell()) {
// TODO(dgrogan) Add a web test showing that SetChildNeedsLayout is
// needed instead of SetNeedsLayout.
NextCell()->SetChildNeedsLayout();
- NextCell()->SetPreferredLogicalWidthsDirty(kMarkOnlyThis);
+ NextCell()->SetIntrinsicLogicalWidthsDirty(kMarkOnlyThis);
}
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_cell.h b/chromium/third_party/blink/renderer/core/layout/layout_table_cell.h
index cd9a057af30..b2f2dd196e5 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_cell.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_cell.h
@@ -363,9 +363,10 @@ class CORE_EXPORT LayoutTableCell : public LayoutBlockFlow,
// LayoutNGTableCellInterface implementation end.
+ MinMaxSizes PreferredLogicalWidths() const override;
+
protected:
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
- void ComputePreferredLogicalWidths() override;
void InvalidatePaint(const PaintInvalidatorContext&) const override;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_cell_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_cell_test.cc
index 77c67634079..0826849fc2e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_cell_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_cell_test.cc
@@ -336,22 +336,26 @@ TEST_F(LayoutTableCellTest, HasNonCollapsedBorderDecoration) {
To<Element>(cell->GetNode())
->setAttribute(html_names::kStyleAttr, "border: 1px solid black");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(cell->HasNonCollapsedBorderDecoration());
To<Element>(cell->Table()->GetNode())
->setAttribute(html_names::kStyleAttr, "border-collapse: collapse");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(cell->HasNonCollapsedBorderDecoration());
To<Element>(cell->GetNode())
->setAttribute(html_names::kStyleAttr, "border: 2px solid black");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(cell->HasNonCollapsedBorderDecoration());
To<Element>(cell->Table()->GetNode())
->setAttribute(html_names::kStyleAttr, "");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(cell->HasNonCollapsedBorderDecoration());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_col.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_col.cc
index 578d91179f3..e2286b94bfa 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_col.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_col.cc
@@ -72,15 +72,14 @@ void LayoutTableCol::StyleDidChange(StyleDifference diff,
void LayoutTableCol::UpdateFromElement() {
unsigned old_span = span_;
- Node* n = GetNode();
- if (IsHTMLTableColElement(n)) {
- HTMLTableColElement& tc = ToHTMLTableColElement(*n);
- span_ = tc.span();
+
+ if (auto* tc = DynamicTo<HTMLTableColElement>(GetNode())) {
+ span_ = tc->span();
} else {
span_ = 1;
}
if (span_ != old_span && Style() && Parent()) {
- SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kAttributeChanged);
}
}
@@ -107,17 +106,11 @@ bool LayoutTableCol::CanHaveChildren() const {
return IsTableColumnGroup();
}
-bool LayoutTableCol::PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
- // LayoutTableCol paints nothing by itself. Its background is painted by
- // LayoutTableSection.
- return true;
-}
-
-void LayoutTableCol::ClearPreferredLogicalWidthsDirtyBits() {
- ClearPreferredLogicalWidthsDirty();
+void LayoutTableCol::ClearIntrinsicLogicalWidthsDirtyBits() {
+ ClearIntrinsicLogicalWidthsDirty();
for (LayoutObject* child = FirstChild(); child; child = child->NextSibling())
- child->ClearPreferredLogicalWidthsDirty();
+ child->ClearIntrinsicLogicalWidthsDirty();
}
LayoutTable* LayoutTableCol::Table() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_col.h b/chromium/third_party/blink/renderer/core/layout/layout_table_col.h
index 56634d3d044..cd905f20d33 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_col.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_col.h
@@ -60,7 +60,7 @@ class LayoutTableCol final : public LayoutTableBoxComponent {
public:
explicit LayoutTableCol(Element*);
- void ClearPreferredLogicalWidthsDirtyBits();
+ void ClearIntrinsicLogicalWidthsDirtyBits();
// The 'span' attribute in HTML.
// For CSS table columns or colgroups, this is always 1.
@@ -86,7 +86,15 @@ class LayoutTableCol final : public LayoutTableBoxComponent {
return type == kLayoutObjectLayoutTableCol || LayoutBox::IsOfType(type);
}
void UpdateFromElement() override;
- void ComputePreferredLogicalWidths() override { NOTREACHED(); }
+
+ MinMaxSizes PreferredLogicalWidths() const override {
+ NOTREACHED();
+ return MinMaxSizes();
+ }
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const final {
+ NOTREACHED();
+ return MinMaxSizes();
+ }
void InsertedIntoTree() override;
void WillBeRemovedFromTree() override;
@@ -95,8 +103,6 @@ class LayoutTableCol final : public LayoutTableBoxComponent {
bool CanHaveChildren() const override;
PaintLayerType LayerTypeRequired() const override { return kNoPaintLayer; }
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const final;
-
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
LayoutTable* Table() const final;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_row.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_row.cc
index 001ade422da..8dbea5af6e8 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_row.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_row.cc
@@ -92,7 +92,7 @@ void LayoutTableRow::StyleDidChange(StyleDifference diff,
// TODO(dgrogan) Add a web test showing that SetChildNeedsLayout is
// needed instead of SetNeedsLayout.
child_box->SetChildNeedsLayout();
- child_box->SetPreferredLogicalWidthsDirty(kMarkOnlyThis);
+ child_box->SetIntrinsicLogicalWidthsDirty(kMarkOnlyThis);
}
// Most table componenents can rely on LayoutObject::styleDidChange
// to mark the container chain dirty. But LayoutTableSection seems
@@ -100,7 +100,7 @@ void LayoutTableRow::StyleDidChange(StyleDifference diff,
// anything under LayoutTableSection has to restart the propagation
// at the table.
// TODO(dgrogan): Make LayoutTableSection clear its dirty bit.
- table->SetPreferredLogicalWidthsDirty();
+ table->SetIntrinsicLogicalWidthsDirty();
}
// When a row gets collapsed or uncollapsed, it's necessary to check all the
@@ -178,11 +178,11 @@ void LayoutTableRow::AddChild(LayoutObject* child, LayoutObject* before_child) {
if (enclosing_table && enclosing_table->ShouldCollapseBorders()) {
enclosing_table->InvalidateCollapsedBorders();
if (LayoutTableCell* previous_cell = cell->PreviousCell()) {
- previous_cell->SetNeedsLayoutAndPrefWidthsRecalc(
+ previous_cell->SetNeedsLayoutAndIntrinsicWidthsRecalc(
layout_invalidation_reason::kTableChanged);
}
if (LayoutTableCell* next_cell = cell->NextCell()) {
- next_cell->SetNeedsLayoutAndPrefWidthsRecalc(
+ next_cell->SetNeedsLayoutAndIntrinsicWidthsRecalc(
layout_invalidation_reason::kTableChanged);
}
}
@@ -376,11 +376,4 @@ void LayoutTableRow::AddVisualOverflowFromCell(const LayoutTableCell* cell) {
AddContentsVisualOverflow(cell_visual_overflow_rect);
}
-bool LayoutTableRow::PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
- return LayoutTableBoxComponent::
- PaintedOutputOfObjectHasNoEffectRegardlessOfSize() &&
- // Row paints collapsed borders.
- !Table()->HasCollapsedBorders();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_row.h b/chromium/third_party/blink/renderer/core/layout/layout_table_row.h
index 7e42e8ef116..82feffcf220 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_row.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_row.h
@@ -128,8 +128,6 @@ class CORE_EXPORT LayoutTableRow final : public LayoutTableBoxComponent,
bool BackgroundIsKnownToBeOpaqueInRect(const PhysicalRect&) const override {
return false;
}
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override;
-
// LayoutNGTableRowInterface methods start.
const LayoutNGTableRowInterface* ToLayoutNGTableRowInterface() const final {
@@ -153,6 +151,11 @@ class CORE_EXPORT LayoutTableRow final : public LayoutTableBoxComponent,
// LayoutNGTableRowInterface methods end.
private:
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const final {
+ NOTREACHED();
+ return MinMaxSizes();
+ }
+
void ComputeVisualOverflow();
void AddLayoutOverflowFromCell(const LayoutTableCell*);
void AddVisualOverflowFromCell(const LayoutTableCell*);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_section.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_section.cc
index f3b49bc2729..e109f213be7 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_section.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_section.cc
@@ -1478,7 +1478,7 @@ void LayoutTableSection::MarkAllCellsWidthsDirtyAndOrNeedsLayout(
for (LayoutTableRow* row = FirstRow(); row; row = row->NextRow()) {
for (LayoutTableCell* cell = row->FirstCell(); cell;
cell = cell->NextCell()) {
- cell->SetPreferredLogicalWidthsDirty();
+ cell->SetIntrinsicLogicalWidthsDirty();
if (what_to_mark == LayoutTable::kMarkDirtyAndNeedsLayout)
cell->SetChildNeedsLayout();
}
@@ -2108,13 +2108,4 @@ bool LayoutTableSection::MapToVisualRectInAncestorSpaceInternal(
ancestor, transform_state, flags);
}
-bool LayoutTableSection::PaintedOutputOfObjectHasNoEffectRegardlessOfSize()
- const {
- // LayoutTableSection paints background from columns.
- if (Table()->HasColElements())
- return false;
- return LayoutTableBoxComponent::
- PaintedOutputOfObjectHasNoEffectRegardlessOfSize();
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_section.h b/chromium/third_party/blink/renderer/core/layout/layout_table_section.h
index 4bab95705be..2e3495ce6e3 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_section.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_section.h
@@ -336,6 +336,11 @@ class CORE_EXPORT LayoutTableSection final
HitTestAction) override;
private:
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const final {
+ NOTREACHED();
+ return MinMaxSizes();
+ }
+
void ComputeVisualOverflowFromDescendants();
bool IsOfType(LayoutObjectType type) const override {
@@ -421,8 +426,6 @@ class CORE_EXPORT LayoutTableSection final
// avoid any repeating headers in its table or ancestor tables.
int OffsetForRepeatedHeader() const;
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override;
-
bool HeaderGroupShouldRepeat() const {
return Table()->Header() == this && GroupShouldRepeat();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_test.cc
index 1ea145a99f4..04897e32a31 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_test.cc
@@ -37,8 +37,7 @@ TEST_F(LayoutTableTest, OverflowViaOutline) {
To<Element>(child->GetNode())
->setAttribute(html_names::kStyleAttr, "outline: 2px solid black");
- target->GetFrameView()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ target->GetFrameView()->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
EXPECT_EQ(LayoutRect(-2, -2, 104, 204), target->SelfVisualOverflowRect());
EXPECT_EQ(LayoutRect(-2, -2, 104, 204), child->SelfVisualOverflowRect());
@@ -358,8 +357,7 @@ TEST_F(LayoutTableTest, VisualOverflowCleared) {
EXPECT_EQ(LayoutRect(-3, -3, 66, 66), table->SelfVisualOverflowRect());
To<Element>(table->GetNode())
->setAttribute(html_names::kStyleAttr, "box-shadow: initial");
- GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetDocument().View()->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
EXPECT_EQ(LayoutRect(0, 0, 50, 50), table->SelfVisualOverflowRect());
}
@@ -370,13 +368,15 @@ TEST_F(LayoutTableTest, HasNonCollapsedBorderDecoration) {
To<Element>(table->GetNode())
->setAttribute(html_names::kStyleAttr, "border: 1px solid black");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(table->HasNonCollapsedBorderDecoration());
To<Element>(table->GetNode())
->setAttribute(html_names::kStyleAttr,
"border: 1px solid black; border-collapse: collapse");
- GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint();
+ GetDocument().View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
EXPECT_FALSE(table->HasNonCollapsedBorderDecoration());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text.cc b/chromium/third_party/blink/renderer/core/layout/layout_text.cc
index f2c80c747a2..b1ccf91480c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text.cc
@@ -29,6 +29,7 @@
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
#include "third_party/blink/renderer/core/content_capture/content_capture_manager.h"
+#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
@@ -181,7 +182,8 @@ void LayoutText::StyleDidChange(StyleDifference diff,
// We do have to schedule layouts, though, since a style change can force us
// to need to relayout.
if (diff.NeedsFullLayout()) {
- SetNeedsLayoutAndPrefWidthsRecalc(layout_invalidation_reason::kStyleChange);
+ SetNeedsLayoutAndIntrinsicWidthsRecalc(
+ layout_invalidation_reason::kStyleChange);
known_to_have_no_overflow_and_no_fallback_fonts_ = false;
}
@@ -221,13 +223,20 @@ void LayoutText::RemoveAndDestroyTextBoxes() {
for (InlineTextBox* box : TextBoxes())
box->Remove();
} else {
- if (NGPaintFragment* first_inline_fragment = FirstInlineFragment()) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (has_abstract_inline_text_box_)
+ ClearFirstInlineFragmentItemIndex();
+ } else if (NGPaintFragment* first_inline_fragment =
+ FirstInlineFragment()) {
first_inline_fragment->LayoutObjectWillBeDestroyed();
SetFirstInlineFragment(nullptr);
}
if (Parent())
Parent()->DirtyLinesFromChangedChild(this);
}
+ } else if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (has_abstract_inline_text_box_)
+ ClearFirstInlineFragmentItemIndex();
} else if (NGPaintFragment* first_inline_fragment = FirstInlineFragment()) {
// Still do this to clear the global hash map in NGAbstractInlineTextBox.
SetFirstInlineFragment(nullptr);
@@ -265,29 +274,42 @@ void LayoutText::RemoveTextBox(InlineTextBox* box) {
void LayoutText::DeleteTextBoxes() {
if (!IsInLayoutNGInlineFormattingContext())
- MutableTextBoxes().DeleteLineBoxes();
+ return MutableTextBoxes().DeleteLineBoxes();
+ DetachAbstractInlineTextBoxesIfNeeded();
}
-void LayoutText::SetFirstInlineFragment(NGPaintFragment* first_fragment) {
- CHECK(IsInLayoutNGInlineFormattingContext());
- // TODO(yosin): Once we remove |NGPaintFragment|, we should get rid of
- // |!fragment|.
- DCHECK(!first_fragment ||
- !RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
+void LayoutText::DetachAbstractInlineTextBoxes() {
// TODO(layout-dev): Because We should call |WillDestroy()| once for
// associated fragments, when you reuse fragments, you should construct
// NGAbstractInlineTextBox for them.
- if (has_abstract_inline_text_box_) {
+ DCHECK(has_abstract_inline_text_box_);
+ has_abstract_inline_text_box_ = false;
+ if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
for (NGPaintFragment* fragment : NGPaintFragment::InlineFragmentsFor(this))
NGAbstractInlineTextBox::WillDestroy(fragment);
- has_abstract_inline_text_box_ = false;
+ return;
}
+ // TODO(yosin): Make sure we call this function within valid containg block
+ // of |this|.
+ NGInlineCursor cursor;
+ for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject())
+ NGAbstractInlineTextBox::WillDestroy(cursor);
+}
+
+void LayoutText::SetFirstInlineFragment(NGPaintFragment* first_fragment) {
+ CHECK(IsInLayoutNGInlineFormattingContext());
+ // TODO(yosin): Once we remove |NGPaintFragment|, we should get rid of
+ // |!fragment|.
+ DCHECK(!first_fragment ||
+ !RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
+ DetachAbstractInlineTextBoxesIfNeeded();
first_paint_fragment_ = first_fragment;
}
void LayoutText::ClearFirstInlineFragmentItemIndex() {
CHECK(IsInLayoutNGInlineFormattingContext()) << *this;
DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
+ DetachAbstractInlineTextBoxesIfNeeded();
first_fragment_item_index_ = 0u;
}
@@ -296,7 +318,10 @@ void LayoutText::SetFirstInlineFragmentItemIndex(wtf_size_t index) {
// TODO(yosin): Call |NGAbstractInlineTextBox::WillDestroy()|.
DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK_NE(index, 0u);
- first_fragment_item_index_ = index;
+ DetachAbstractInlineTextBoxesIfNeeded();
+ // TDOO(yosin): Once we update all |LayoutObject::FirstInlineFragment()|,
+ // we should enable below.
+ // first_fragment_item_index_ = index;
}
void LayoutText::InLayoutNGInlineFormattingContextWillChange(bool new_value) {
@@ -305,9 +330,17 @@ void LayoutText::InLayoutNGInlineFormattingContextWillChange(bool new_value) {
// Because |first_paint_fragment_| and |text_boxes_| are union, when one is
// deleted, the other should be initialized to nullptr.
DCHECK(new_value ? !first_paint_fragment_ : !text_boxes_.First());
+
+ // Because there are no inline boxes associated to this text, we should not
+ // have abstract inline text boxes too.
+ DCHECK(!has_abstract_inline_text_box_);
}
Vector<LayoutText::TextBoxInfo> LayoutText::GetTextBoxInfo() const {
+ // This function may kick the layout (e.g., |LocalRect()|), but Inspector may
+ // call this function outside of the layout phase.
+ FontCachePurgePreventer fontCachePurgePreventer;
+
Vector<TextBoxInfo> results;
if (const NGOffsetMapping* mapping = GetNGOffsetMapping()) {
bool in_hidden_for_paint = false;
@@ -317,7 +350,7 @@ Vector<LayoutText::TextBoxInfo> LayoutText::GetTextBoxInfo() const {
// TODO(yosin): We should introduce
// |NGPhysicalTextFragment::IsTruncated()| to skip them instead of using
// |IsHiddenForPaint()| with ordering of fragments.
- if (cursor.IsHiddenForPaint()) {
+ if (cursor.Current().IsHiddenForPaint()) {
in_hidden_for_paint = true;
} else if (in_hidden_for_paint) {
// Because of we finished original fragments (not painted), we should
@@ -326,31 +359,31 @@ Vector<LayoutText::TextBoxInfo> LayoutText::GetTextBoxInfo() const {
}
// We don't put generated texts, e.g. ellipsis, hyphen, etc. not in text
// content, into results. Note: CSS "content" aren't categorized this.
- if (cursor.IsGeneratedTextType())
+ if (cursor.Current().IsGeneratedTextType())
continue;
// When the corresponding DOM range contains collapsed whitespaces, NG
// produces one fragment but legacy produces multiple text boxes broken at
// collapsed whitespaces. We break the fragment at collapsed whitespaces
// to match the legacy output.
+ const NGTextOffset offset = cursor.Current().TextOffset();
for (const NGOffsetMappingUnit& unit :
- mapping->GetMappingUnitsForTextContentOffsetRange(
- cursor.CurrentTextStartOffset(),
- cursor.CurrentTextEndOffset())) {
+ mapping->GetMappingUnitsForTextContentOffsetRange(offset.start,
+ offset.end)) {
DCHECK_EQ(unit.GetLayoutObject(), this);
if (unit.GetType() == NGOffsetMappingUnitType::kCollapsed)
continue;
// [clamped_start, clamped_end] of |fragment| matches a legacy text box.
const unsigned clamped_start =
- std::max(unit.TextContentStart(), cursor.CurrentTextStartOffset());
+ std::max(unit.TextContentStart(), offset.start);
const unsigned clamped_end =
- std::min(unit.TextContentEnd(), cursor.CurrentTextEndOffset());
+ std::min(unit.TextContentEnd(), offset.end);
DCHECK_LT(clamped_start, clamped_end);
const unsigned box_length = clamped_end - clamped_start;
// Compute rect of the legacy text box.
LayoutRect rect =
cursor.CurrentLocalRect(clamped_start, clamped_end).ToLayoutRect();
- rect.MoveBy(cursor.CurrentOffset().ToLayoutPoint());
+ rect.MoveBy(cursor.Current().OffsetInContainerBlock().ToLayoutPoint());
// Compute start of the legacy text box.
if (unit.AssociatedNode()) {
@@ -380,15 +413,13 @@ Vector<LayoutText::TextBoxInfo> LayoutText::GetTextBoxInfo() const {
return results;
}
-bool LayoutText::HasTextBoxes() const {
- if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
- auto fragments = NGPaintFragment::InlineFragmentsFor(this);
- if (fragments.IsInLayoutNGInlineFormattingContext())
- return !(fragments.begin() == fragments.end());
- // When legacy is forced, IsInLayoutNGInlineFormattingContext is false,
- // and we fall back to normal HasTextBox
- return FirstTextBox();
- }
+bool LayoutText::HasInlineFragments() const {
+ if (IsInLayoutNGInlineFormattingContext()) {
+ NGInlineCursor cursor;
+ cursor.MoveTo(*this);
+ return cursor.IsNotNull();
+ }
+
return FirstTextBox();
}
@@ -473,10 +504,10 @@ void LayoutText::CollectLineBoxRects(const PhysicalRectCollector& yield,
for (; cursor; cursor.MoveToNextForSameLayoutObject()) {
if (UNLIKELY(option != ClippingOption::kNoClipping)) {
DCHECK_EQ(option, ClippingOption::kClipToEllipsis);
- if (cursor.IsHiddenForPaint())
+ if (cursor.Current().IsHiddenForPaint())
continue;
}
- yield(cursor.CurrentRect());
+ yield(cursor.Current().RectInContainerBlock());
}
return;
}
@@ -585,13 +616,13 @@ void LayoutText::AbsoluteQuadsForRange(Vector<FloatQuad>& quads,
block_for_flipping = ContainingBlock();
NGInlineCursor cursor;
for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject()) {
- const NGTextOffset offset = cursor.CurrentTextOffset();
+ const NGTextOffset offset = cursor.Current().TextOffset();
if (start > offset.end || end < offset.start)
continue;
const unsigned clamped_start = std::max(start, offset.start);
const unsigned clamped_end = std::min(end, offset.end);
PhysicalRect rect = cursor.CurrentLocalRect(clamped_start, clamped_end);
- rect.Move(cursor.CurrentOffset());
+ rect.Move(cursor.Current().OffsetInContainerBlock());
const FloatQuad quad = LocalRectToAbsoluteQuad(rect);
if (clamped_start < clamped_end) {
quads.push_back(quad);
@@ -979,7 +1010,7 @@ void LayoutText::TrimmedPrefWidths(LayoutUnit lead_width_layout_unit,
if (!collapse_white_space)
strip_front_spaces = false;
- if (has_tab_ || PreferredLogicalWidthsDirty())
+ if (has_tab_ || IntrinsicLogicalWidthsDirty())
ComputePreferredLogicalWidths(lead_width);
has_breakable_start = !strip_front_spaces && has_breakable_start_;
@@ -1070,14 +1101,14 @@ void LayoutText::TrimmedPrefWidths(LayoutUnit lead_width_layout_unit,
}
float LayoutText::MinLogicalWidth() const {
- if (PreferredLogicalWidthsDirty())
+ if (IntrinsicLogicalWidthsDirty())
const_cast<LayoutText*>(this)->ComputePreferredLogicalWidths(0);
return min_width_;
}
float LayoutText::MaxLogicalWidth() const {
- if (PreferredLogicalWidthsDirty())
+ if (IntrinsicLogicalWidthsDirty())
const_cast<LayoutText*>(this)->ComputePreferredLogicalWidths(0);
return max_width_;
@@ -1173,7 +1204,7 @@ void LayoutText::ComputePreferredLogicalWidths(
float lead_width,
HashSet<const SimpleFontData*>& fallback_fonts,
FloatRect& glyph_bounds) {
- DCHECK(has_tab_ || PreferredLogicalWidthsDirty() ||
+ DCHECK(has_tab_ || IntrinsicLogicalWidthsDirty() ||
!known_to_have_no_overflow_and_no_fallback_fonts_);
min_width_ = 0;
@@ -1523,7 +1554,7 @@ void LayoutText::ComputePreferredLogicalWidths(
known_to_have_no_overflow_and_no_fallback_fonts_ =
fallback_fonts.IsEmpty() && glyph_overflow.IsApproximatelyZero();
- ClearPreferredLogicalWidthsDirty();
+ ClearIntrinsicLogicalWidthsDirty();
}
bool LayoutText::IsAllCollapsibleWhitespace() const {
@@ -1564,7 +1595,7 @@ UChar32 LayoutText::FirstCharacterAfterWhitespaceCollapsing() const {
NGInlineCursor cursor;
cursor.MoveTo(*this);
if (cursor) {
- const StringView text = cursor.CurrentText();
+ const StringView text = cursor.Current().Text(cursor);
return text.length() ? text.CodepointAt(0) : 0;
}
}
@@ -1580,7 +1611,7 @@ UChar32 LayoutText::LastCharacterAfterWhitespaceCollapsing() const {
NGInlineCursor cursor;
cursor.MoveTo(*this);
if (cursor) {
- const StringView text = cursor.CurrentText();
+ const StringView text = cursor.Current().Text(cursor);
return text.length() ? text.CodepointAt(text.length() - 1) : 0;
}
}
@@ -1588,12 +1619,15 @@ UChar32 LayoutText::LastCharacterAfterWhitespaceCollapsing() const {
}
PhysicalOffset LayoutText::FirstLineBoxTopLeft() const {
- if (const NGPaintFragment* fragment = FirstInlineFragment()) {
+ if (IsInLayoutNGInlineFormattingContext()) {
// TODO(kojii): Some clients call this against dirty-tree, but NG fragments
// are not safe to read for dirty-tree. crbug.com/963103
if (UNLIKELY(!IsFirstInlineFragmentSafe()))
return PhysicalOffset();
- return fragment->InlineOffsetToContainerBox();
+ NGInlineCursor cursor;
+ cursor.MoveTo(*this);
+ return cursor ? cursor.Current().OffsetInContainerBlock()
+ : PhysicalOffset();
}
if (const auto* text_box = FirstTextBox()) {
LayoutPoint location = text_box->Location();
@@ -1798,7 +1832,7 @@ static inline bool IsInlineFlowOrEmptyText(const LayoutObject* o) {
}
OnlyWhitespaceOrNbsp LayoutText::ContainsOnlyWhitespaceOrNbsp() const {
- return PreferredLogicalWidthsDirty() ? OnlyWhitespaceOrNbsp::kUnknown
+ return IntrinsicLogicalWidthsDirty() ? OnlyWhitespaceOrNbsp::kUnknown
: static_cast<OnlyWhitespaceOrNbsp>(
contains_only_whitespace_or_nbsp_);
}
@@ -1889,10 +1923,10 @@ void LayoutText::ForceSetText(scoped_refptr<StringImpl> text) {
void LayoutText::TextDidChange() {
// If preferredLogicalWidthsDirty() of an orphan child is true,
// LayoutObjectChildList::insertChildNode() fails to set true to owner.
- // To avoid that, we call setNeedsLayoutAndPrefWidthsRecalc() only if this
- // LayoutText has parent.
+ // To avoid that, we call SetNeedsLayoutAndIntrinsicWidthsRecalc() only if
+ // this LayoutText has parent.
if (Parent()) {
- SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
layout_invalidation_reason::kTextChanged);
}
TextDidChangeWithoutInvalidation();
@@ -1918,6 +1952,14 @@ void LayoutText::TextDidChangeWithoutInvalidation() {
SetNeedsCollectInlines();
}
+void LayoutText::InvalidateSubtreeLayoutForFontUpdates() {
+ known_to_have_no_overflow_and_no_fallback_fonts_ = false;
+ valid_ng_items_ = false;
+ SetNeedsCollectInlines();
+ SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
+ layout_invalidation_reason::kFontsChanged);
+}
+
void LayoutText::DirtyOrDeleteLineBoxesIfNeeded(bool full_layout) {
if (full_layout)
DeleteTextBoxes();
@@ -1999,7 +2041,7 @@ float LayoutText::Width(unsigned from,
if (!StyleRef().PreserveNewline() && !from && len == TextLength()) {
if (fallback_fonts) {
DCHECK(glyph_bounds);
- if (PreferredLogicalWidthsDirty() ||
+ if (IntrinsicLogicalWidthsDirty() ||
!known_to_have_no_overflow_and_no_fallback_fonts_) {
const_cast<LayoutText*>(this)->ComputePreferredLogicalWidths(
0, *fallback_fonts, *glyph_bounds);
@@ -2110,14 +2152,14 @@ PhysicalRect LayoutText::LocalSelectionVisualRect() const {
PhysicalRect rect;
NGInlineCursor cursor(*RootInlineFormattingContext());
for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject()) {
- if (cursor.IsHiddenForPaint())
+ if (cursor.Current().IsHiddenForPaint())
continue;
const LayoutSelectionStatus status =
frame_selection.ComputeLayoutSelectionStatus(cursor);
if (status.start == status.end)
continue;
PhysicalRect item_rect = ComputeLocalSelectionRectForText(cursor, status);
- item_rect.offset += cursor.CurrentOffset();
+ item_rect.offset += cursor.Current().OffsetInContainerBlock();
rect.Unite(item_rect);
}
return rect;
@@ -2415,12 +2457,10 @@ void LayoutText::MomentarilyRevealLastTypedCharacter(
}
scoped_refptr<AbstractInlineTextBox> LayoutText::FirstAbstractInlineTextBox() {
- if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
- auto fragments = NGPaintFragment::InlineFragmentsFor(this);
- if (!fragments.IsEmpty() &&
- fragments.IsInLayoutNGInlineFormattingContext()) {
- return NGAbstractInlineTextBox::GetOrCreate(fragments.front());
- }
+ if (IsInLayoutNGInlineFormattingContext()) {
+ NGInlineCursor cursor;
+ cursor.MoveTo(*this);
+ return NGAbstractInlineTextBox::GetOrCreate(cursor);
}
return LegacyAbstractInlineTextBox::GetOrCreate(LineLayoutText(this),
FirstTextBox());
@@ -2430,7 +2470,8 @@ void LayoutText::InvalidateDisplayItemClients(
PaintInvalidationReason invalidation_reason) const {
ObjectPaintInvalidator paint_invalidator(*this);
- if (RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled()) {
+ if (RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled() &&
+ !RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
auto fragments = NGPaintFragment::InlineFragmentsFor(this);
if (fragments.IsInLayoutNGInlineFormattingContext()) {
for (NGPaintFragment* fragment : fragments) {
@@ -2445,7 +2486,7 @@ void LayoutText::InvalidateDisplayItemClients(
NGInlineCursor cursor;
for (cursor.MoveTo(*this); cursor; cursor.MoveToNextForSameLayoutObject()) {
paint_invalidator.InvalidateDisplayItemClient(
- *cursor.CurrentDisplayItemClient(), invalidation_reason);
+ *cursor.Current().GetDisplayItemClient(), invalidation_reason);
}
return;
}
@@ -2467,8 +2508,11 @@ PhysicalRect LayoutText::DebugRect() const {
DOMNodeId LayoutText::EnsureNodeId() {
if (node_id_ == kInvalidDOMNodeId) {
- if (auto* content_capture_manager = GetContentCaptureManager())
- node_id_ = content_capture_manager->GetNodeId(*GetNode());
+ auto* content_capture_manager = GetContentCaptureManager();
+ if (content_capture_manager) {
+ content_capture_manager->ScheduleTaskIfNeeded();
+ node_id_ = DOMNodeIds::IdForNode(GetNode());
+ }
}
return node_id_;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text.h b/chromium/third_party/blink/renderer/core/layout/layout_text.h
index 3548afaf77a..17ca490ad20 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text.h
@@ -97,6 +97,7 @@ class CORE_EXPORT LayoutText : public LayoutObject {
void AttachTextBox(InlineTextBox*);
void RemoveTextBox(InlineTextBox*);
+ bool HasInlineFragments() const final;
NGPaintFragment* FirstInlineFragment() const final;
void SetFirstInlineFragment(NGPaintFragment*) final;
wtf_size_t FirstInlineFragmentItemIndex() const final;
@@ -218,10 +219,6 @@ class CORE_EXPORT LayoutText : public LayoutObject {
InlineTextBox* FirstTextBox() const { return TextBoxes().First(); }
InlineTextBox* LastTextBox() const { return TextBoxes().Last(); }
- // True if we have inline text box children which implies rendered text (or
- // whitespace) output.
- bool HasTextBoxes() const;
-
// TODO(layoutng) Legacy-only implementation of HasTextBoxes.
// All callers should call HasTextBoxes instead, and take NG into account.
bool HasLegacyTextBoxes() const { return FirstTextBox(); }
@@ -331,6 +328,10 @@ class CORE_EXPORT LayoutText : public LayoutObject {
}
virtual base::span<NGInlineItem>* GetNGInlineItems() { return nullptr; }
+ void InvalidateSubtreeLayoutForFontUpdates() override;
+
+ void DetachAbstractInlineTextBoxesIfNeeded();
+
protected:
void WillBeDestroyed() override;
@@ -439,6 +440,7 @@ class CORE_EXPORT LayoutText : public LayoutObject {
private:
ContentCaptureManager* GetContentCaptureManager();
+ void DetachAbstractInlineTextBoxes();
// Used for LayoutNG with accessibility. True if inline fragments are
// associated to |NGAbstractInlineTextBox|.
@@ -517,6 +519,11 @@ inline float LayoutText::HyphenWidth(const Font& font,
style, direction));
}
+inline void LayoutText::DetachAbstractInlineTextBoxesIfNeeded() {
+ if (UNLIKELY(has_abstract_inline_text_box_))
+ DetachAbstractInlineTextBoxes();
+}
+
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutText, IsText());
inline LayoutText* Text::GetLayoutObject() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_combine.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_combine.cc
index 62c19718366..cb823919580 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_combine.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_combine.cc
@@ -177,7 +177,7 @@ void LayoutTextCombine::UpdateFontStyleForCombinedText() {
FontSelector* font_selector = style->GetFont().GetFontSelector();
// Need to change font orientation to horizontal.
- bool should_update_font = style->SetFontDescription(description);
+ style->SetFontDescription(description);
if (combined_text_width_ <= em_width) {
scale_x_ = 1.0f;
@@ -187,14 +187,13 @@ void LayoutTextCombine::UpdateFontStyleForCombinedText() {
kQuarterWidth};
for (size_t i = 0; i < base::size(kWidthVariants); ++i) {
description.SetWidthVariant(kWidthVariants[i]);
- Font compressed_font = Font(description);
- compressed_font.Update(font_selector);
+ Font compressed_font(description, font_selector);
float run_width = compressed_font.Width(run);
if (run_width <= em_width) {
combined_text_width_ = run_width;
// Replace my font with the new one.
- should_update_font = style->SetFontDescription(description);
+ style->SetFontDescription(description);
break;
}
}
@@ -209,9 +208,6 @@ void LayoutTextCombine::UpdateFontStyleForCombinedText() {
scale_x_ = 1.0f;
}
}
-
- if (should_update_font)
- style->GetFont().Update(font_selector);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_control.cc
index 966bfa81583..cce0469a265 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_control.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control.cc
@@ -208,69 +208,25 @@ float LayoutTextControl::GetAvgCharWidth(const AtomicString& family) const {
return font.Width(text_run);
}
-void LayoutTextControl::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
+MinMaxSizes LayoutTextControl::ComputeIntrinsicLogicalWidths() const {
+ MinMaxSizes sizes;
+ sizes += BorderAndPaddingLogicalWidth();
+
// Use average character width. Matches IE.
AtomicString family =
StyleRef().GetFont().GetFontDescription().Family().Family();
- max_logical_width = PreferredContentLogicalWidth(
+ sizes.max_size += PreferredContentLogicalWidth(
const_cast<LayoutTextControl*>(this)->GetAvgCharWidth(family));
if (InnerEditorElement()) {
if (LayoutBox* inner_editor_layout_box =
- InnerEditorElement()->GetLayoutBox())
- max_logical_width += inner_editor_layout_box->PaddingStart() +
- inner_editor_layout_box->PaddingEnd();
+ InnerEditorElement()->GetLayoutBox()) {
+ sizes.max_size += inner_editor_layout_box->PaddingStart() +
+ inner_editor_layout_box->PaddingEnd();
+ }
}
if (!StyleRef().LogicalWidth().IsPercentOrCalc())
- min_logical_width = max_logical_width;
-}
-
-void LayoutTextControl::ComputePreferredLogicalWidths() {
- DCHECK(PreferredLogicalWidthsDirty());
-
- min_preferred_logical_width_ = LayoutUnit();
- max_preferred_logical_width_ = LayoutUnit();
- const ComputedStyle& style_to_use = StyleRef();
-
- if (style_to_use.LogicalWidth().IsFixed() &&
- style_to_use.LogicalWidth().Value() >= 0)
- min_preferred_logical_width_ = max_preferred_logical_width_ =
- AdjustContentBoxLogicalWidthForBoxSizing(
- style_to_use.LogicalWidth().Value());
- else
- ComputeIntrinsicLogicalWidths(min_preferred_logical_width_,
- max_preferred_logical_width_);
-
- if (style_to_use.LogicalMinWidth().IsFixed() &&
- style_to_use.LogicalMinWidth().Value() > 0) {
- max_preferred_logical_width_ =
- std::max(max_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- style_to_use.LogicalMinWidth().Value()));
- min_preferred_logical_width_ =
- std::max(min_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- style_to_use.LogicalMinWidth().Value()));
- }
-
- if (style_to_use.LogicalMaxWidth().IsFixed()) {
- max_preferred_logical_width_ =
- std::min(max_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- style_to_use.LogicalMaxWidth().Value()));
- min_preferred_logical_width_ =
- std::min(min_preferred_logical_width_,
- AdjustContentBoxLogicalWidthForBoxSizing(
- style_to_use.LogicalMaxWidth().Value()));
- }
-
- LayoutUnit to_add = BorderAndPaddingLogicalWidth();
-
- min_preferred_logical_width_ += to_add;
- max_preferred_logical_width_ += to_add;
-
- ClearPreferredLogicalWidthsDirty();
+ sizes.min_size = sizes.max_size;
+ return sizes;
}
void LayoutTextControl::AddOutlineRects(Vector<PhysicalRect>& rects,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control.h b/chromium/third_party/blink/renderer/core/layout/layout_text_control.h
index 4c6b2bfb358..b3298fc3835 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_control.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control.h
@@ -75,22 +75,13 @@ class CORE_EXPORT LayoutTextControl : public LayoutBlockFlow {
SubtreeLayoutScope&) override;
LayoutUnit FirstLineBoxBaseline() const override;
- // We need to override this function because we don't want overflow:hidden on
- // an <input> to affect the baseline calculation. This is necessary because we
- // are an inline-block element as an implementation detail which would
- // normally be affected by this.
- bool ShouldIgnoreOverflowPropertyForInlineBlockBaseline() const override {
- return true;
- }
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectTextControl || LayoutBlockFlow::IsOfType(type);
}
private:
- void ComputeIntrinsicLogicalWidths(LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const final;
- void ComputePreferredLogicalWidths() final;
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const final;
void RemoveLeftoverAnonymousBlock(LayoutBlock*) final {}
void AddOutlineRects(Vector<PhysicalRect>&,
@@ -100,33 +91,10 @@ class CORE_EXPORT LayoutTextControl : public LayoutBlockFlow {
bool CanBeProgramaticallyScrolled() const final { return true; }
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutTextControl, IsTextControl());
-
-// LayoutObject for our inner container, for <search> and others.
-// We can't use LayoutFlexibleBox directly, because flexboxes have a different
-// baseline definition, and then inputs of different types wouldn't line up
-// anymore.
-class LayoutTextControlInnerContainer final : public LayoutFlexibleBox {
- public:
- explicit LayoutTextControlInnerContainer(Element* element)
- : LayoutFlexibleBox(element) {}
- ~LayoutTextControlInnerContainer() override = default;
-
- LayoutUnit BaselinePosition(FontBaseline baseline,
- bool first_line,
- LineDirectionMode direction,
- LinePositionMode position) const override {
- return LayoutBlock::BaselinePosition(baseline, first_line, direction,
- position);
- }
- LayoutUnit FirstLineBoxBaseline() const override {
- return LayoutBlock::FirstLineBoxBaseline();
- }
- LayoutUnit InlineBlockBaseline(LineDirectionMode direction) const override {
- return LayoutBlock::InlineBlockBaseline(direction);
- }
- bool ShouldIgnoreOverflowPropertyForInlineBlockBaseline() const override {
- return true;
+template <>
+struct DowncastTraits<LayoutTextControl> {
+ static bool AllowFrom(const LayoutObject& object) {
+ return object.IsTextControl();
}
};
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control_multi_line.h b/chromium/third_party/blink/renderer/core/layout/layout_text_control_multi_line.h
index 35fff854e5b..21111aa1a63 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_control_multi_line.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control_multi_line.h
@@ -66,8 +66,6 @@ class LayoutTextControlMultiLine final : public LayoutTextControl {
LayoutUnit ScrollHeight() const override;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutTextControlMultiLine, IsTextArea());
-
} // namespace blink
#endif
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
index 6f1f6bc19ae..b2c0cebcab0 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.cc
@@ -197,17 +197,6 @@ void LayoutTextControlSingleLine::CapsLockStateMayHaveChanged() {
}
}
-bool LayoutTextControlSingleLine::HasControlClip() const {
- return true;
-}
-
-PhysicalRect LayoutTextControlSingleLine::ControlClipRect(
- const PhysicalOffset& additional_offset) const {
- PhysicalRect clip_rect = PhysicalPaddingBoxRect();
- clip_rect.offset += additional_offset;
- return clip_rect;
-}
-
LayoutUnit LayoutTextControlSingleLine::PreferredContentLogicalWidth(
float char_width) const {
int factor;
@@ -249,14 +238,6 @@ LayoutUnit LayoutTextControlSingleLine::ComputeControlLogicalHeight(
return line_height + non_content_height;
}
-void LayoutTextControlSingleLine::Autoscroll(const PhysicalOffset& position) {
- LayoutBox* layout_object = InnerEditorElement()->GetLayoutBox();
- if (!layout_object)
- return;
-
- layout_object->Autoscroll(position);
-}
-
LayoutUnit LayoutTextControlSingleLine::ScrollWidth() const {
// If in preview state, fake the scroll width to prevent that any information
// about the suggested content can be derived from the size.
@@ -309,6 +290,7 @@ void LayoutTextControlSingleLine::ComputeVisualOverflow(
AddVisualOverflowFromFloats();
if (VisualOverflowRect() != previous_visual_overflow_rect) {
+ InvalidateIntersectionObserverCachedRects();
SetShouldCheckForPaintInvalidation();
GetFrameView()->SetIntersectionObservationState(LocalFrameView::kDesired);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.h b/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
index a49de236a8d..59323298ca3 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.h
@@ -31,6 +31,12 @@ namespace blink {
class HTMLInputElement;
+// LayoutObject for text-field <input>s.
+//
+// This class inherits from LayoutTextControl and LayoutBlockFlow. If we'd like
+// to change the base class, we need to make sure that
+// ShouldIgnoreOverflowPropertyForInlineBlockBaseline flag works with the new
+// base class.
class LayoutTextControlSingleLine : public LayoutTextControl {
public:
LayoutTextControlSingleLine(HTMLInputElement*);
@@ -47,8 +53,6 @@ class LayoutTextControlSingleLine : public LayoutTextControl {
HTMLInputElement* InputElement() const;
private:
- bool HasControlClip() const final;
- PhysicalRect ControlClipRect(const PhysicalOffset&) const final;
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectTextField || LayoutTextControl::IsOfType(type);
}
@@ -61,8 +65,6 @@ class LayoutTextControlSingleLine : public LayoutTextControl {
const PhysicalOffset& accumulated_offset,
HitTestAction) final;
- void Autoscroll(const PhysicalOffset&) final;
-
// Subclassed to forward to our inner div.
LayoutUnit ScrollWidth() const final;
LayoutUnit ScrollHeight() const final;
@@ -87,16 +89,18 @@ class LayoutTextControlSingleLine : public LayoutTextControl {
bool should_draw_caps_lock_indicator_;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutTextControlSingleLine, IsTextField());
+template <>
+struct DowncastTraits<LayoutTextControlSingleLine> {
+ static bool AllowFrom(const LayoutObject& object) {
+ return object.IsTextField();
+ }
+};
// ----------------------------
class LayoutTextControlInnerEditor : public LayoutBlockFlow {
public:
LayoutTextControlInnerEditor(Element* element) : LayoutBlockFlow(element) {}
- bool ShouldIgnoreOverflowPropertyForInlineBlockBaseline() const override {
- return true;
- }
private:
bool IsIntrinsicallyScrollable(
@@ -105,7 +109,6 @@ class LayoutTextControlInnerEditor : public LayoutBlockFlow {
}
bool ScrollsOverflowX() const override { return HasOverflowClip(); }
bool ScrollsOverflowY() const override { return false; }
- bool HasLineIfEmpty() const override { return true; }
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line_test.cc
index a0533fd75c5..a04b29a50f4 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line_test.cc
@@ -6,6 +6,7 @@
#include "build/build_config.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "ui/base/ui_base_features.h"
namespace blink {
@@ -23,21 +24,28 @@ TEST_F(LayoutTextControlSingleLineTest, VisualOverflowCleared) {
<input id=input type="text"></input.
)HTML");
auto* input =
- ToLayoutTextControlSingleLine(GetLayoutObjectByElementId("input"));
+ To<LayoutTextControlSingleLine>(GetLayoutObjectByElementId("input"));
+ if (::features::IsFormControlsRefreshEnabled()) {
+ EXPECT_EQ(LayoutRect(-3, -3, 74, 72), input->SelfVisualOverflowRect());
+ } else {
#if defined(OS_MACOSX)
- EXPECT_EQ(LayoutRect(-3, -3, 72, 72), input->SelfVisualOverflowRect());
+ EXPECT_EQ(LayoutRect(-3, -3, 72, 72), input->SelfVisualOverflowRect());
#else
- EXPECT_EQ(LayoutRect(-3, -3, 70, 72), input->SelfVisualOverflowRect());
+ EXPECT_EQ(LayoutRect(-3, -3, 70, 72), input->SelfVisualOverflowRect());
#endif
+ }
To<Element>(input->GetNode())
->setAttribute(html_names::kStyleAttr, "box-shadow: initial");
- GetDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ GetDocument().View()->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
+ if (::features::IsFormControlsRefreshEnabled()) {
+ EXPECT_EQ(LayoutRect(0, 0, 58, 56), input->SelfVisualOverflowRect());
+ } else {
#if defined(OS_MACOSX)
- EXPECT_EQ(LayoutRect(0, 0, 56, 56), input->SelfVisualOverflowRect());
+ EXPECT_EQ(LayoutRect(0, 0, 56, 56), input->SelfVisualOverflowRect());
#else
- EXPECT_EQ(LayoutRect(0, 0, 54, 56), input->SelfVisualOverflowRect());
+ EXPECT_EQ(LayoutRect(0, 0, 54, 56), input->SelfVisualOverflowRect());
#endif
+ }
}
} // anonymous namespace
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_control_test.cc
index 18d55934be9..b8446166f0c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_control_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control_test.cc
@@ -44,7 +44,8 @@ TEST_F(LayoutTextControlTest,
EXPECT_FALSE(selectedText->ShouldInvalidateSelection());
inputElement->setAttribute(html_names::kClassAttr, "pseudoSelection");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(selectedText->ShouldInvalidateSelection());
UpdateAllLifecyclePhasesForTest();
@@ -69,7 +70,8 @@ TEST_F(LayoutTextControlTest,
EXPECT_FALSE(selectedText->ShouldInvalidateSelection());
inputElement->setAttribute(html_names::kClassAttr, "pseudoSelection");
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(selectedText->ShouldInvalidateSelection());
UpdateAllLifecyclePhasesForTest();
@@ -94,7 +96,8 @@ TEST_F(LayoutTextControlTest,
EXPECT_FALSE(selectedText->ShouldInvalidateSelection());
inputElement->removeAttribute(html_names::kClassAttr);
- GetDocument().View()->UpdateLifecycleToLayoutClean();
+ GetDocument().View()->UpdateLifecycleToLayoutClean(
+ DocumentUpdateReason::kTest);
EXPECT_TRUE(selectedText->ShouldInvalidateSelection());
UpdateAllLifecyclePhasesForTest();
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_fragment_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_fragment_test.cc
index e8bacc966f2..3405d85c0ae 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_fragment_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_fragment_test.cc
@@ -17,7 +17,7 @@ class LayoutTextFragmentTest : public RenderingTest {
protected:
void SetUp() override {
RenderingTest::SetUp();
- GetDocument().head()->SetInnerHTMLFromString(
+ GetDocument().head()->setInnerHTML(
"<style>#target::first-letter{color:red}</style>");
}
@@ -52,7 +52,9 @@ class ParameterizedLayoutTextFragmentTest
ParameterizedLayoutTextFragmentTest() : ScopedLayoutNGForTest(GetParam()) {}
protected:
- bool LayoutNGEnabled() const { return GetParam(); }
+ bool LayoutNGEnabled() const {
+ return RuntimeEnabledFeatures::LayoutNGEnabled();
+ }
};
INSTANTIATE_TEST_SUITE_P(All,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_test.cc
index ac8fb58a804..ec907acd7fa 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_test.cc
@@ -78,7 +78,9 @@ class ParameterizedLayoutTextTest : public testing::WithParamInterface<bool>,
ParameterizedLayoutTextTest() : ScopedLayoutNGForTest(GetParam()) {}
protected:
- bool LayoutNGEnabled() const { return GetParam(); }
+ bool LayoutNGEnabled() const {
+ return RuntimeEnabledFeatures::LayoutNGEnabled();
+ }
};
INSTANTIATE_TEST_SUITE_P(All, ParameterizedLayoutTextTest, testing::Bool());
@@ -252,7 +254,7 @@ TEST_P(ParameterizedLayoutTextTest, CharacterAfterWhitespaceCollapsing) {
SetBodyInnerHTML("a <span id=target> </span>b");
layout_text = GetLayoutTextById("target");
- DCHECK(!layout_text->HasTextBoxes());
+ DCHECK(!layout_text->HasInlineFragments());
EXPECT_EQ(0, layout_text->FirstCharacterAfterWhitespaceCollapsing());
EXPECT_EQ(0, layout_text->LastCharacterAfterWhitespaceCollapsing());
@@ -268,7 +270,7 @@ TEST_P(ParameterizedLayoutTextTest, CharacterAfterWhitespaceCollapsing) {
EXPECT_EQ(' ', layout_text->LastCharacterAfterWhitespaceCollapsing());
layout_text =
ToLayoutText(GetLayoutObjectByElementId("target")->NextSibling());
- DCHECK(!layout_text->HasTextBoxes());
+ DCHECK(!layout_text->HasInlineFragments());
EXPECT_EQ(0, layout_text->FirstCharacterAfterWhitespaceCollapsing());
EXPECT_EQ(0, layout_text->LastCharacterAfterWhitespaceCollapsing());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme.cc b/chromium/third_party/blink/renderer/core/layout/layout_theme.cc
index 488f6f7d225..b1cbf5326ba 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme.cc
@@ -30,7 +30,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
-#include "third_party/blink/renderer/core/fileapi/file_list.h"
+#include "third_party/blink/renderer/core/fileapi/file.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/forms/html_data_list_element.h"
@@ -55,12 +55,11 @@
#include "third_party/blink/renderer/core/style/computed_style_initial_values.h"
#include "third_party/blink/renderer/platform/file_metadata.h"
#include "third_party/blink/renderer/platform/fonts/font_selector.h"
-#include "third_party/blink/renderer/platform/fonts/string_truncator.h"
#include "third_party/blink/renderer/platform/graphics/touch_action.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/text/platform_locale.h"
#include "third_party/blink/renderer/platform/web_test_support.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+#include "ui/base/ui_base_features.h"
#include "ui/native_theme/native_theme.h"
// The methods in this file are shared by all themes on every platform.
@@ -164,9 +163,6 @@ ControlPart LayoutTheme::AdjustAppearanceWithElementType(
const ComputedStyle& style,
const Element* element) {
ControlPart part = style.EffectiveAppearance();
- if (!RuntimeEnabledFeatures::RestrictedWebkitAppearanceEnabled())
- return part;
-
if (!element)
return kNoControlPart;
@@ -186,6 +182,7 @@ ControlPart LayoutTheme::AdjustAppearanceWithElementType(
// Aliases of 'auto'.
// https://drafts.csswg.org/css-ui-4/#typedef-appearance-compat-auto
+ case kAutoPart:
case kCheckboxPart:
case kRadioPart:
case kPushButtonPart:
@@ -262,6 +259,7 @@ void LayoutTheme::AdjustStyle(ComputedStyle& style, Element* e) {
ControlPart part = AdjustAppearanceWithAuthorStyle(
AdjustAppearanceWithElementType(style, e), style);
style.SetEffectiveAppearance(part);
+ DCHECK_NE(part, kAutoPart);
if (part == kNoControlPart)
return;
@@ -297,6 +295,19 @@ void LayoutTheme::AdjustStyle(ComputedStyle& style, Element* e) {
}
String LayoutTheme::ExtraDefaultStyleSheet() {
+ if (RuntimeEnabledFeatures::LayoutNGForControlsEnabled()) {
+ return String(R"CSS(
+input[type="file" i] {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: pre;
+}
+
+input[type="file" i]::-webkit-file-upload-button {
+ margin-inline-end: 4px;
+}
+)CSS");
+ }
return g_empty_string;
}
@@ -612,7 +623,12 @@ void LayoutTheme::AdjustButtonStyle(ComputedStyle& style) const {}
void LayoutTheme::AdjustInnerSpinButtonStyle(ComputedStyle&) const {}
-void LayoutTheme::AdjustMenuListStyle(ComputedStyle&, Element*) const {}
+void LayoutTheme::AdjustMenuListStyle(ComputedStyle& style, Element*) const {
+ // Menulists should have visible overflow
+ // https://bugs.webkit.org/show_bug.cgi?id=21287
+ style.SetOverflowX(EOverflow::kVisible);
+ style.SetOverflowY(EOverflow::kVisible);
+}
base::TimeDelta LayoutTheme::AnimationRepeatIntervalForProgressBar() const {
return base::TimeDelta();
@@ -634,11 +650,15 @@ void LayoutTheme::AdjustSliderContainerStyle(ComputedStyle& style,
if (e && (e->ShadowPseudoId() == "-webkit-media-slider-container" ||
e->ShadowPseudoId() == "-webkit-slider-container")) {
if (style.EffectiveAppearance() == kSliderVerticalPart) {
- style.SetTouchAction(TouchAction::kTouchActionPanX);
+ style.SetTouchAction(TouchAction::kPanX);
style.SetEffectiveAppearance(kNoControlPart);
+ style.SetWritingMode(WritingMode::kVerticalRl);
+ // It's always in RTL because the slider value increases up even in LTR.
+ style.SetDirection(TextDirection::kRtl);
} else {
- style.SetTouchAction(TouchAction::kTouchActionPanY);
+ style.SetTouchAction(TouchAction::kPanY);
style.SetEffectiveAppearance(kNoControlPart);
+ style.SetWritingMode(WritingMode::kHorizontalTb);
}
}
}
@@ -749,7 +769,7 @@ Color LayoutTheme::SystemColor(CSSValueID css_value_id,
case CSSValueID::kButtonshadow:
return 0xFF888888;
case CSSValueID::kButtontext:
- return color_scheme == WebColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
+ return color_scheme == WebColorScheme::kDark ? 0xFFAAAAAA : 0xFF000000;
case CSSValueID::kCaptiontext:
return color_scheme == WebColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
case CSSValueID::kField:
@@ -855,27 +875,16 @@ Color LayoutTheme::FocusRingColor() const {
: GetTheme().PlatformFocusRingColor();
}
-String LayoutTheme::FileListNameForWidth(Locale& locale,
- const FileList* file_list,
- const Font& font,
- int width) const {
- if (width <= 0)
- return String();
-
- String string;
- if (file_list->IsEmpty()) {
- string = locale.QueryString(IDS_FORM_FILE_NO_FILE_LABEL);
- } else if (file_list->length() == 1) {
- string = file_list->item(0)->name();
- } else {
- return StringTruncator::RightTruncate(
- locale.QueryString(IDS_FORM_FILE_MULTIPLE_UPLOAD,
- locale.ConvertToLocalizedNumber(
- String::Number(file_list->length()))),
- width, font);
- }
+bool LayoutTheme::DelegatesMenuListRendering() const {
+ return delegates_menu_list_rendering_;
+}
+
+void LayoutTheme::SetDelegatesMenuListRenderingForTesting(bool flag) {
+ delegates_menu_list_rendering_ = flag;
+}
- return StringTruncator::CenterTruncate(string, width, font);
+String LayoutTheme::DisplayNameForFile(const File& file) const {
+ return file.name();
}
bool LayoutTheme::ShouldOpenPickerWithF4Key() const {
@@ -884,7 +893,7 @@ bool LayoutTheme::ShouldOpenPickerWithF4Key() const {
bool LayoutTheme::SupportsCalendarPicker(const AtomicString& type) const {
DCHECK(RuntimeEnabledFeatures::InputMultipleFieldsUIEnabled());
- if (RuntimeEnabledFeatures::FormControlsRefreshEnabled() &&
+ if (features::IsFormControlsRefreshEnabled() &&
type == input_type_names::kTime)
return true;
@@ -993,12 +1002,6 @@ void LayoutTheme::AdjustRadioStyleUsingFallbackTheme(
style.ResetBorder();
}
-Color LayoutTheme::RootElementColor(WebColorScheme color_scheme) const {
- if (color_scheme == WebColorScheme::kDark)
- return Color::kWhite;
- return ComputedStyleInitialValues::InitialColor();
-}
-
LengthBox LayoutTheme::ControlPadding(ControlPart part,
const FontDescription&,
const Length& zoomed_box_top,
@@ -1053,4 +1056,12 @@ void LayoutTheme::AdjustControlPartStyle(ComputedStyle& style) {
}
}
+bool LayoutTheme::HasCustomFocusRingColor() const {
+ return has_custom_focus_ring_color_;
+}
+
+Color LayoutTheme::GetCustomFocusRingColor() const {
+ return custom_focus_ring_color_;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme.h b/chromium/third_party/blink/renderer/core/layout/layout_theme.h
index 0c92b958f8f..9ffb65caaab 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme.h
@@ -29,6 +29,7 @@
#include "third_party/blink/renderer/core/scroll/scroll_types.h"
#include "third_party/blink/renderer/platform/fonts/font_description.h"
#include "third_party/blink/renderer/platform/fonts/font_selection_types.h"
+#include "third_party/blink/renderer/platform/geometry/int_rect.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/geometry/length_box.h"
#include "third_party/blink/renderer/platform/geometry/length_size.h"
@@ -42,12 +43,11 @@ namespace blink {
class ComputedStyle;
class Element;
-class FileList;
-class Font;
+class File;
class FontDescription;
class HTMLInputElement;
+class IntRect;
class LengthSize;
-class Locale;
class LocalFrame;
class Node;
class ThemePainter;
@@ -170,22 +170,18 @@ class CORE_EXPORT LayoutTheme : public RefCounted<LayoutTheme> {
WebColorScheme color_scheme) const;
virtual bool IsFocusRingOutset() const;
- Color FocusRingColor() const;
+ virtual Color FocusRingColor() const;
virtual Color PlatformFocusRingColor() const { return Color(0, 0, 0); }
void SetCustomFocusRingColor(const Color&);
static Color TapHighlightColor();
- // Root element text color. It can be different from the initial color in
- // other color schemes than the light theme.
- Color RootElementColor(WebColorScheme) const;
-
virtual Color PlatformTapHighlightColor() const {
return LayoutTheme::kDefaultTapHighlightColor;
}
virtual Color PlatformDefaultCompositionBackgroundColor() const {
return kDefaultCompositionBackgroundColor;
}
- virtual void PlatformColorsDidChange();
+ void PlatformColorsDidChange();
virtual void ColorSchemeDidChange();
void SetCaretBlinkInterval(base::TimeDelta);
@@ -236,16 +232,16 @@ class CORE_EXPORT LayoutTheme : public RefCounted<LayoutTheme> {
virtual bool ShouldHaveSpinButton(HTMLInputElement*) const;
// Functions for <select> elements.
- virtual bool DelegatesMenuListRendering() const { return false; }
+ virtual bool DelegatesMenuListRendering() const;
+ // This function has no effect for LayoutThemeAndroid, of which
+ // DelegatesMenuListRendering() always returns true.
+ void SetDelegatesMenuListRenderingForTesting(bool flag);
virtual bool PopsMenuByArrowKeys() const { return false; }
virtual bool PopsMenuBySpaceKey() const { return false; }
virtual bool PopsMenuByReturnKey() const { return false; }
virtual bool PopsMenuByAltDownUpOrF4Key() const { return false; }
- virtual String FileListNameForWidth(Locale&,
- const FileList*,
- const Font&,
- int width) const;
+ virtual String DisplayNameForFile(const File& file) const;
virtual bool ShouldOpenPickerWithF4Key() const;
@@ -356,6 +352,10 @@ class CORE_EXPORT LayoutTheme : public RefCounted<LayoutTheme> {
static bool IsSpinUpButtonPartHovered(const Node*);
static bool IsReadOnlyControl(const Node*);
+ protected:
+ bool HasCustomFocusRingColor() const;
+ Color GetCustomFocusRingColor() const;
+
private:
// This function is to be implemented in your platform-specific theme
// implementation to hand back the appropriate platform theme.
@@ -372,6 +372,8 @@ class CORE_EXPORT LayoutTheme : public RefCounted<LayoutTheme> {
base::TimeDelta caret_blink_interval_ =
base::TimeDelta::FromMilliseconds(500);
+ bool delegates_menu_list_rendering_ = false;
+
// This color is expected to be drawn on a semi-transparent overlay,
// making it more transparent than its alpha value indicates.
static const RGBA32 kDefaultTapHighlightColor = 0x66000000;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme_default.cc b/chromium/third_party/blink/renderer/core/layout/layout_theme_default.cc
index 8c38b306a47..806f976d723 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme_default.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme_default.cc
@@ -36,6 +36,7 @@
#include "third_party/blink/renderer/platform/data_resource_helper.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+#include "ui/base/ui_base_features.h"
namespace blink {
@@ -45,10 +46,16 @@ static const float kDefaultCancelButtonSize = 9;
static const float kMinCancelButtonSize = 5;
static const float kMaxCancelButtonSize = 21;
-LayoutThemeDefault::LayoutThemeDefault()
- : LayoutTheme(),
- caret_blink_interval_(LayoutTheme::CaretBlinkInterval()),
- painter_(*this) {}
+base::TimeDelta LayoutThemeDefault::caret_blink_interval_;
+
+Color LayoutThemeDefault::active_selection_background_color_ = 0xff1e90ff;
+Color LayoutThemeDefault::active_selection_foreground_color_ = Color::kBlack;
+Color LayoutThemeDefault::inactive_selection_background_color_ = 0xffc8c8c8;
+Color LayoutThemeDefault::inactive_selection_foreground_color_ = 0xff323232;
+
+LayoutThemeDefault::LayoutThemeDefault() : LayoutTheme(), painter_(*this) {
+ caret_blink_interval_ = LayoutTheme::CaretBlinkInterval();
+}
LayoutThemeDefault::~LayoutThemeDefault() = default;
@@ -94,7 +101,7 @@ String LayoutThemeDefault::ExtraDefaultStyleSheet() {
String windows_style_sheet =
UncompressResourceAsASCIIString(IDR_UASTYLE_THEME_WIN_CSS);
String controls_refresh_style_sheet =
- RuntimeEnabledFeatures::FormControlsRefreshEnabled()
+ features::IsFormControlsRefreshEnabled()
? UncompressResourceAsASCIIString(
IDR_UASTYLE_THEME_CONTROLS_REFRESH_CSS)
: String();
@@ -154,14 +161,14 @@ Color LayoutThemeDefault::PlatformInactiveSelectionForegroundColor(
}
IntSize LayoutThemeDefault::SliderTickSize() const {
- if (RuntimeEnabledFeatures::FormControlsRefreshEnabled())
+ if (features::IsFormControlsRefreshEnabled())
return IntSize(1, 4);
else
return IntSize(1, 6);
}
int LayoutThemeDefault::SliderTickOffsetFromTrackCenter() const {
- if (RuntimeEnabledFeatures::FormControlsRefreshEnabled())
+ if (features::IsFormControlsRefreshEnabled())
return 7;
else
return -16;
@@ -294,7 +301,8 @@ void LayoutThemeDefault::AdjustSearchFieldCancelButtonStyle(
}
void LayoutThemeDefault::AdjustMenuListStyle(ComputedStyle& style,
- Element*) const {
+ Element* element) const {
+ LayoutTheme::AdjustMenuListStyle(style, element);
// Height is locked to auto on all browsers.
style.SetLineHeight(ComputedStyleInitialValues::InitialLineHeight());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme_default.h b/chromium/third_party/blink/renderer/core/layout/layout_theme_default.h
index 397383f420e..50588077553 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme_default.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme_default.h
@@ -150,12 +150,13 @@ class CORE_EXPORT LayoutThemeDefault : public LayoutTheme {
int MenuListInternalPadding(const ComputedStyle&, int padding) const;
static const RGBA32 kDefaultTapHighlightColor = 0x2e000000; // 18% black.
- base::TimeDelta caret_blink_interval_;
- Color active_selection_background_color_ = 0xff1e90ff;
- Color active_selection_foreground_color_ = Color::kBlack;
- Color inactive_selection_background_color_ = 0xffc8c8c8;
- Color inactive_selection_foreground_color_ = 0xff323232;
+ static base::TimeDelta caret_blink_interval_;
+
+ static Color active_selection_background_color_;
+ static Color active_selection_foreground_color_;
+ static Color inactive_selection_background_color_;
+ static Color inactive_selection_foreground_color_;
ThemePainterDefault painter_;
// Cached values for crbug.com/673754.
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.h b/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.h
index ae22fe65b67..43219d5853f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.h
@@ -29,7 +29,6 @@
#include "base/mac/scoped_nsobject.h"
#import "third_party/blink/renderer/core/layout/layout_theme.h"
#import "third_party/blink/renderer/core/paint/theme_painter_mac.h"
-#import "third_party/blink/renderer/platform/wtf/hash_map.h"
@class BlinkLayoutThemeNotificationObserver;
@@ -67,8 +66,6 @@ class LayoutThemeMac final : public LayoutTheme {
return part == kListboxPart ? kSmallScrollbar : kRegularScrollbar;
}
- void PlatformColorsDidChange() override;
-
// System fonts.
void SystemFont(CSSValueID system_font_id,
FontSelectionValue& font_slope,
@@ -276,10 +273,7 @@ class LayoutThemeMac final : public LayoutTheme {
private:
const int* ProgressBarHeights() const;
const int* ProgressBarMargins(NSControlSize) const;
- String FileListNameForWidth(Locale&,
- const FileList*,
- const Font&,
- int width) const override;
+ String DisplayNameForFile(const File& file) const override;
String ExtraDefaultStyleSheet() override;
bool ThemeDrawsFocusRing(const ComputedStyle&) const override;
@@ -289,8 +283,6 @@ class LayoutThemeMac final : public LayoutTheme {
mutable base::scoped_nsobject<NSSearchFieldCell> search_;
mutable base::scoped_nsobject<NSTextFieldCell> text_field_;
- mutable HashMap<CSSValueID, RGBA32> system_color_cache_;
-
base::scoped_nsobject<BlinkLayoutThemeNotificationObserver>
notification_observer_;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.mm b/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.mm
index 09eb072a39f..f9912f0c745 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.mm
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme_mac.mm
@@ -31,21 +31,21 @@
#import "third_party/blink/public/resources/grit/blink_resources.h"
#import "third_party/blink/public/strings/grit/blink_strings.h"
#import "third_party/blink/renderer/core/css_value_keywords.h"
-#import "third_party/blink/renderer/core/fileapi/file_list.h"
+#import "third_party/blink/renderer/core/fileapi/file.h"
#import "third_party/blink/renderer/core/html_names.h"
#import "third_party/blink/renderer/core/layout/layout_progress.h"
#import "third_party/blink/renderer/core/layout/layout_theme_default.h"
#import "third_party/blink/renderer/core/layout/layout_view.h"
#import "third_party/blink/renderer/core/style/shadow_list.h"
#import "third_party/blink/renderer/platform/data_resource_helper.h"
-#import "third_party/blink/renderer/platform/fonts/string_truncator.h"
#import "third_party/blink/renderer/platform/graphics/bitmap_image.h"
#import "third_party/blink/renderer/platform/mac/block_exceptions.h"
#import "third_party/blink/renderer/platform/mac/color_mac.h"
#import "third_party/blink/renderer/platform/mac/web_core_ns_cell_extras.h"
#import "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#import "third_party/blink/renderer/platform/text/platform_locale.h"
#import "third_party/blink/renderer/platform/web_test_support.h"
+#include "ui/base/ui_base_features.h"
+#include "ui/native_theme/native_theme.h"
// This is a view whose sole purpose is to tell AppKit that it's flipped.
@interface BlinkFlippedControl : NSControl
@@ -146,6 +146,27 @@ class LayoutThemeMacRefresh final : public LayoutThemeDefault {
static scoped_refptr<LayoutTheme> Create() {
return base::AdoptRef(new LayoutThemeMacRefresh());
}
+
+ Color PlatformActiveSelectionBackgroundColor(
+ WebColorScheme color_scheme) const override;
+ Color PlatformInactiveSelectionBackgroundColor(
+ WebColorScheme color_scheme) const override;
+ Color PlatformActiveSelectionForegroundColor(
+ WebColorScheme color_scheme) const override;
+ Color PlatformSpellingMarkerUnderlineColor() const override;
+ Color PlatformGrammarMarkerUnderlineColor() const override;
+ Color FocusRingColor() const override;
+ String DisplayNameForFile(const File& file) const override {
+ if (file.GetUserVisibility() == File::kIsUserVisible)
+ return [[NSFileManager defaultManager] displayNameAtPath:file.GetPath()];
+ return file.name();
+ }
+ bool PopsMenuByArrowKeys() const override;
+
+ protected:
+ // Controls color values returned from FocusRingColor().
+ bool UsesTestModeFocusRingColor() const;
+ bool IsAccentColorCustomized(WebColorScheme color_scheme) const;
};
// Inflate an IntRect to account for specific padding around margins.
@@ -162,13 +183,13 @@ bool FontSizeMatchesToControlSize(const ComputedStyle& style) {
return false;
}
-Color GetSystemColor(MacSystemColorID color_id) {
+Color GetSystemColor(MacSystemColorID color_id, WebColorScheme color_scheme) {
// In tests, a WebSandboxSupport may not be set up. Just return a dummy
// color, in this case, black.
auto* sandbox_support = Platform::Current()->GetSandboxSupport();
if (!sandbox_support)
return Color();
- return sandbox_support->GetSystemColor(color_id);
+ return sandbox_support->GetSystemColor(color_id, color_scheme);
}
// Helper functions used by a bunch of different control parts.
@@ -225,12 +246,14 @@ LayoutThemeMac::~LayoutThemeMac() {
Color LayoutThemeMac::PlatformActiveSelectionBackgroundColor(
WebColorScheme color_scheme) const {
- return GetSystemColor(MacSystemColorID::kSelectedTextBackground);
+ return GetSystemColor(MacSystemColorID::kSelectedTextBackground,
+ color_scheme);
}
Color LayoutThemeMac::PlatformInactiveSelectionBackgroundColor(
WebColorScheme color_scheme) const {
- return GetSystemColor(MacSystemColorID::kSecondarySelectedControl);
+ return GetSystemColor(MacSystemColorID::kSecondarySelectedControl,
+ color_scheme);
}
Color LayoutThemeMac::PlatformActiveSelectionForegroundColor(
@@ -240,7 +263,8 @@ Color LayoutThemeMac::PlatformActiveSelectionForegroundColor(
Color LayoutThemeMac::PlatformActiveListBoxSelectionBackgroundColor(
WebColorScheme color_scheme) const {
- return GetSystemColor(MacSystemColorID::kAlternateSelectedControl);
+ return GetSystemColor(MacSystemColorID::kAlternateSelectedControl,
+ color_scheme);
}
Color LayoutThemeMac::PlatformActiveListBoxSelectionForegroundColor(
@@ -276,6 +300,88 @@ Color LayoutThemeMac::PlatformInactiveListBoxSelectionBackgroundColor(
return PlatformInactiveSelectionBackgroundColor(color_scheme);
}
+Color LayoutThemeMacRefresh::PlatformActiveSelectionBackgroundColor(
+ WebColorScheme color_scheme) const {
+ return GetSystemColor(MacSystemColorID::kSelectedTextBackground,
+ color_scheme);
+}
+
+Color LayoutThemeMacRefresh::PlatformInactiveSelectionBackgroundColor(
+ WebColorScheme color_scheme) const {
+ return GetSystemColor(MacSystemColorID::kSecondarySelectedControl,
+ color_scheme);
+}
+
+Color LayoutThemeMacRefresh::PlatformActiveSelectionForegroundColor(
+ WebColorScheme color_scheme) const {
+ return Color::kBlack;
+}
+
+Color LayoutThemeMacRefresh::PlatformSpellingMarkerUnderlineColor() const {
+ return Color(251, 45, 29);
+}
+
+Color LayoutThemeMacRefresh::PlatformGrammarMarkerUnderlineColor() const {
+ return Color(107, 107, 107);
+}
+
+bool LayoutThemeMacRefresh::IsAccentColorCustomized(
+ WebColorScheme color_scheme) const {
+ if (@available(macOS 10.14, *)) {
+ static const Color kControlBlueAccentColor =
+ GetSystemColor(MacSystemColorID::kControlAccentBlueColor, color_scheme);
+ if (kControlBlueAccentColor ==
+ GetSystemColor(MacSystemColorID::kControlAccentColor, color_scheme)) {
+ return false;
+ }
+ } else {
+ if (NSBlueControlTint == [[NSUserDefaults standardUserDefaults]
+ integerForKey:@"AppleAquaColorVariant"]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+Color LayoutThemeMacRefresh::FocusRingColor() const {
+ static const RGBA32 kDefaultFocusRingColor = 0xFF101010;
+ if (UsesTestModeFocusRingColor()) {
+ return HasCustomFocusRingColor() ? GetCustomFocusRingColor()
+ : kDefaultFocusRingColor;
+ }
+
+ if (ui::NativeTheme::GetInstanceForWeb()->UsesHighContrastColors()) {
+ // When high contrast is enabled, #101010 should be used.
+ return Color(0xFF101010);
+ }
+
+ // TODO(crbug.com/929098) Need to pass an appropriate color scheme here.
+ WebColorScheme color_scheme = ComputedStyle::InitialStyle().UsedColorScheme();
+
+ Color keyboard_focus_indicator =
+ GetSystemColor(MacSystemColorID::kKeyboardFocusIndicator, color_scheme);
+ // Take the RGB values from the keyboard_focus_indicator color, but use a
+ // different alpha value to avoid having a color too light.
+ Color focus_ring =
+ Color(keyboard_focus_indicator.Red(), keyboard_focus_indicator.Green(),
+ keyboard_focus_indicator.Blue(), /*alpha=*/166);
+ if (!HasCustomFocusRingColor())
+ return focus_ring;
+ // Use the custom focus ring color when the system accent color wasn't
+ // changed.
+ if (!IsAccentColorCustomized(color_scheme))
+ return GetCustomFocusRingColor();
+ return focus_ring;
+}
+
+bool LayoutThemeMacRefresh::UsesTestModeFocusRingColor() const {
+ return WebTestSupport::IsRunningWebTest();
+}
+
+bool LayoutThemeMacRefresh::PopsMenuByArrowKeys() const {
+ return true;
+}
+
static FontSelectionValue ToFontWeight(NSInteger app_kit_font_weight) {
DCHECK_GT(app_kit_font_weight, 0);
DCHECK_LT(app_kit_font_weight, 15);
@@ -334,138 +440,96 @@ void LayoutThemeMac::SystemFont(CSSValueID system_font_id,
font_family = font_family_names::kSystemUi;
}
-void LayoutThemeMac::PlatformColorsDidChange() {
- system_color_cache_.clear();
- LayoutTheme::PlatformColorsDidChange();
-}
-
Color LayoutThemeMac::SystemColor(CSSValueID css_value_id,
WebColorScheme color_scheme) const {
- {
- HashMap<CSSValueID, RGBA32>::iterator it =
- system_color_cache_.find(css_value_id);
- if (it != system_color_cache_.end())
- return it->value;
- }
+ if (!Platform::Current()->GetSandboxSupport())
+ return LayoutTheme::SystemColor(css_value_id, color_scheme);
- Color color;
- bool needs_fallback = false;
switch (css_value_id) {
case CSSValueID::kActiveborder:
- color = GetSystemColor(MacSystemColorID::kKeyboardFocusIndicator);
- break;
+ return GetSystemColor(MacSystemColorID::kKeyboardFocusIndicator,
+ color_scheme);
case CSSValueID::kActivecaption:
- color = GetSystemColor(MacSystemColorID::kWindowFrameText);
- break;
+ return GetSystemColor(MacSystemColorID::kWindowFrameText, color_scheme);
case CSSValueID::kAppworkspace:
- color = GetSystemColor(MacSystemColorID::kHeader);
- break;
+ return GetSystemColor(MacSystemColorID::kHeader, color_scheme);
case CSSValueID::kBackground:
- // Use theme independent default
- needs_fallback = true;
+ // Use theme independent default.
break;
case CSSValueID::kButtonface:
- color = GetSystemColor(MacSystemColorID::kControlBackground);
- break;
+ return GetSystemColor(MacSystemColorID::kControlBackground, color_scheme);
case CSSValueID::kButtonhighlight:
- color = GetSystemColor(MacSystemColorID::kControlHighlight);
- break;
+ return GetSystemColor(MacSystemColorID::kControlHighlight, color_scheme);
case CSSValueID::kButtonshadow:
- color = GetSystemColor(MacSystemColorID::kControlShadow);
- break;
+ return GetSystemColor(MacSystemColorID::kControlShadow, color_scheme);
case CSSValueID::kButtontext:
- color = GetSystemColor(MacSystemColorID::kControlText);
- break;
+ return GetSystemColor(MacSystemColorID::kControlText, color_scheme);
case CSSValueID::kCaptiontext:
- color = GetSystemColor(MacSystemColorID::kText);
- break;
+ return GetSystemColor(MacSystemColorID::kText, color_scheme);
case CSSValueID::kField:
- color = GetSystemColor(MacSystemColorID::kControlBackground);
- break;
+ return GetSystemColor(MacSystemColorID::kControlBackground, color_scheme);
case CSSValueID::kFieldtext:
- color = GetSystemColor(MacSystemColorID::kText);
- break;
+ return GetSystemColor(MacSystemColorID::kText, color_scheme);
case CSSValueID::kGraytext:
- color = GetSystemColor(MacSystemColorID::kDisabledControlText);
- break;
+ return GetSystemColor(MacSystemColorID::kDisabledControlText,
+ color_scheme);
case CSSValueID::kHighlight:
- color = GetSystemColor(MacSystemColorID::kSelectedTextBackground);
- break;
+ return GetSystemColor(MacSystemColorID::kSelectedTextBackground,
+ color_scheme);
case CSSValueID::kHighlighttext:
- color = GetSystemColor(MacSystemColorID::kSelectedText);
- break;
+ return GetSystemColor(MacSystemColorID::kSelectedText, color_scheme);
case CSSValueID::kInactiveborder:
- color = GetSystemColor(MacSystemColorID::kControlBackground);
- break;
+ return GetSystemColor(MacSystemColorID::kControlBackground, color_scheme);
case CSSValueID::kInactivecaption:
- color = GetSystemColor(MacSystemColorID::kControlBackground);
- break;
+ return GetSystemColor(MacSystemColorID::kControlBackground, color_scheme);
case CSSValueID::kInactivecaptiontext:
- color = GetSystemColor(MacSystemColorID::kText);
- break;
+ return GetSystemColor(MacSystemColorID::kText, color_scheme);
case CSSValueID::kInfobackground:
// There is no corresponding NSColor for this so we use a hard coded
// value.
- color = 0xFFFBFCC5;
- break;
+ return 0xFFFBFCC5;
case CSSValueID::kInfotext:
- color = GetSystemColor(MacSystemColorID::kText);
- break;
+ return GetSystemColor(MacSystemColorID::kText, color_scheme);
case CSSValueID::kMenu:
- color = GetSystemColor(MacSystemColorID::kMenuBackground);
- break;
+ return GetSystemColor(MacSystemColorID::kMenuBackground, color_scheme);
case CSSValueID::kMenutext:
- color = GetSystemColor(MacSystemColorID::kSelectedMenuItemText);
- break;
+ return GetSystemColor(MacSystemColorID::kSelectedMenuItemText,
+ color_scheme);
case CSSValueID::kScrollbar:
- color = GetSystemColor(MacSystemColorID::kScrollBar);
- break;
+ return GetSystemColor(MacSystemColorID::kScrollBar, color_scheme);
case CSSValueID::kText:
- color = GetSystemColor(MacSystemColorID::kText);
- break;
+ return GetSystemColor(MacSystemColorID::kText, color_scheme);
case CSSValueID::kThreeddarkshadow:
- color = GetSystemColor(MacSystemColorID::kControlDarkShadow);
- break;
+ return GetSystemColor(MacSystemColorID::kControlDarkShadow, color_scheme);
case CSSValueID::kThreedshadow:
- color = GetSystemColor(MacSystemColorID::kShadow);
- break;
+ return GetSystemColor(MacSystemColorID::kShadow, color_scheme);
case CSSValueID::kThreedface:
// We use this value instead of NSColor's controlColor to avoid website
// incompatibilities. We may want to change this to use the NSColor in
// future.
- color = 0xFFC0C0C0;
- break;
+ return 0xFFC0C0C0;
case CSSValueID::kThreedhighlight:
- color = GetSystemColor(MacSystemColorID::kHighlight);
- break;
+ return GetSystemColor(MacSystemColorID::kHighlight, color_scheme);
case CSSValueID::kThreedlightshadow:
- color = GetSystemColor(MacSystemColorID::kControlLightHighlight);
- break;
+ return GetSystemColor(MacSystemColorID::kControlLightHighlight,
+ color_scheme);
case CSSValueID::kWebkitFocusRingColor:
- color = GetSystemColor(MacSystemColorID::kKeyboardFocusIndicator);
- break;
+ return GetSystemColor(MacSystemColorID::kKeyboardFocusIndicator,
+ color_scheme);
case CSSValueID::kWindow:
case CSSValueID::kCanvas:
- color = GetSystemColor(MacSystemColorID::kWindowBackground);
- break;
+ return GetSystemColor(MacSystemColorID::kWindowBackground, color_scheme);
case CSSValueID::kWindowframe:
- color = GetSystemColor(MacSystemColorID::kWindowFrame);
- break;
+ return GetSystemColor(MacSystemColorID::kWindowFrame, color_scheme);
case CSSValueID::kWindowtext:
+ return GetSystemColor(MacSystemColorID::kWindowFrameText, color_scheme);
case CSSValueID::kCanvastext:
- color = GetSystemColor(MacSystemColorID::kWindowFrameText);
- break;
+ return GetSystemColor(MacSystemColorID::kText, color_scheme);
default:
- needs_fallback = true;
break;
}
- if (needs_fallback)
- color = LayoutTheme::SystemColor(css_value_id, color_scheme);
-
- system_color_cache_.Set(css_value_id, color.Rgb());
-
- return color;
+ return LayoutTheme::SystemColor(css_value_id, color_scheme);
}
bool LayoutThemeMac::IsControlStyled(ControlPart part,
@@ -656,10 +720,7 @@ void LayoutThemeMac::SetFontFromControlSize(ComputedStyle& style,
// Reset line height.
style.SetLineHeight(ComputedStyleInitialValues::InitialLineHeight());
- // TODO(esprehn): The fontSelector manual management is buggy and error prone.
- FontSelector* font_selector = style.GetFont().GetFontSelector();
- if (style.SetFontDescription(font_description))
- style.GetFont().Update(font_selector);
+ style.SetFontDescription(font_description);
}
NSControlSize LayoutThemeMac::ControlSizeForSystemFont(
@@ -715,6 +776,7 @@ static const IntSize* MenuListButtonSizes() {
void LayoutThemeMac::AdjustMenuListStyle(ComputedStyle& style,
Element* e) const {
+ LayoutTheme::AdjustMenuListStyle(style, e);
NSControlSize control_size = ControlSizeForFont(style);
style.ResetBorder();
@@ -1003,32 +1065,10 @@ NSTextFieldCell* LayoutThemeMac::TextField() const {
return text_field_;
}
-String LayoutThemeMac::FileListNameForWidth(Locale& locale,
- const FileList* file_list,
- const Font& font,
- int width) const {
- if (width <= 0)
- return String();
-
- String str_to_truncate;
- if (file_list->IsEmpty()) {
- str_to_truncate = locale.QueryString(IDS_FORM_FILE_NO_FILE_LABEL);
- } else if (file_list->length() == 1) {
- File* file = file_list->item(0);
- if (file->GetUserVisibility() == File::kIsUserVisible)
- str_to_truncate = [[NSFileManager defaultManager]
- displayNameAtPath:(file_list->item(0)->GetPath())];
- else
- str_to_truncate = file->name();
- } else {
- return StringTruncator::RightTruncate(
- locale.QueryString(IDS_FORM_FILE_MULTIPLE_UPLOAD,
- locale.ConvertToLocalizedNumber(
- String::Number(file_list->length()))),
- width, font);
- }
-
- return StringTruncator::CenterTruncate(str_to_truncate, width, font);
+String LayoutThemeMac::DisplayNameForFile(const File& file) const {
+ if (file.GetUserVisibility() == File::kIsUserVisible)
+ return [[NSFileManager defaultManager] displayNameAtPath:file.GetPath()];
+ return file.name();
}
NSView* FlippedView() {
@@ -1037,7 +1077,7 @@ NSView* FlippedView() {
}
LayoutTheme& LayoutTheme::NativeTheme() {
- if (RuntimeEnabledFeatures::FormControlsRefreshEnabled()) {
+ if (features::IsFormControlsRefreshEnabled()) {
DEFINE_STATIC_REF(LayoutTheme, layout_theme,
(LayoutThemeMacRefresh::Create()));
return *layout_theme;
@@ -1052,7 +1092,8 @@ scoped_refptr<LayoutTheme> LayoutThemeMac::Create() {
}
bool LayoutThemeMac::UsesTestModeFocusRingColor() const {
- return WebTestSupport::IsRunningWebTest();
+ return WebTestSupport::IsRunningWebTest() ||
+ !Platform::Current()->GetSandboxSupport();
}
NSView* LayoutThemeMac::DocumentView() const {
@@ -1475,8 +1516,7 @@ void LayoutThemeMac::AdjustControlPartStyle(ComputedStyle& style) {
style.SetLineHeight(ComputedStyleInitialValues::InitialLineHeight());
// Now update our font.
- if (style.SetFontDescription(control_font))
- style.GetFont().Update(nullptr);
+ style.SetFontDescription(control_font);
}
break;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_theme_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_theme_test.cc
index ef113db19ff..7461a3457ca 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme_test.cc
@@ -24,15 +24,17 @@
namespace blink {
class LayoutThemeTest : public PageTestBase,
- private ScopedCSSColorSchemeForTest {
+ private ScopedCSSColorSchemeForTest,
+ private ScopedCSSColorSchemeUARenderingForTest {
protected:
- LayoutThemeTest() : ScopedCSSColorSchemeForTest(true) {}
+ LayoutThemeTest()
+ : ScopedCSSColorSchemeForTest(true),
+ ScopedCSSColorSchemeUARenderingForTest(true) {}
void SetHtmlInnerHTML(const char* html_content);
};
void LayoutThemeTest::SetHtmlInnerHTML(const char* html_content) {
- GetDocument().documentElement()->SetInnerHTMLFromString(
- String::FromUTF8(html_content));
+ GetDocument().documentElement()->setInnerHTML(String::FromUTF8(html_content));
UpdateAllLifecyclePhasesForTest();
}
@@ -78,57 +80,8 @@ TEST_F(LayoutThemeTest, ChangeFocusRingColor) {
EXPECT_EQ(custom_color, OutlineColor(span));
}
-TEST_F(LayoutThemeTest, RootElementColor) {
- EXPECT_EQ(Color::kBlack,
- LayoutTheme::GetTheme().RootElementColor(WebColorScheme::kLight));
- EXPECT_EQ(Color::kWhite,
- LayoutTheme::GetTheme().RootElementColor(WebColorScheme::kDark));
-}
-
-TEST_F(LayoutThemeTest, RootElementColorChange) {
- SetHtmlInnerHTML(R"HTML(
- <style>
- :root { color-scheme: light dark }
- #initial { color: initial }
- </style>
- <div id="initial"></div>
- )HTML");
-
- Element* initial = GetDocument().getElementById("initial");
- ASSERT_TRUE(initial);
- ASSERT_TRUE(GetDocument().documentElement());
- const ComputedStyle* document_element_style =
- GetDocument().documentElement()->GetComputedStyle();
- ASSERT_TRUE(document_element_style);
- EXPECT_EQ(Color::kBlack, document_element_style->VisitedDependentColor(
- GetCSSPropertyColor()));
-
- const ComputedStyle* initial_style = initial->GetComputedStyle();
- ASSERT_TRUE(initial_style);
- EXPECT_EQ(Color::kBlack,
- initial_style->VisitedDependentColor(GetCSSPropertyColor()));
-
- // Change color scheme to dark.
- ColorSchemeHelper color_scheme_helper;
- color_scheme_helper.SetPreferredColorScheme(GetDocument(),
- PreferredColorScheme::kDark);
- UpdateAllLifecyclePhasesForTest();
-
- document_element_style = GetDocument().documentElement()->GetComputedStyle();
- ASSERT_TRUE(document_element_style);
- EXPECT_EQ(Color::kWhite, document_element_style->VisitedDependentColor(
- GetCSSPropertyColor()));
-
- initial_style = initial->GetComputedStyle();
- ASSERT_TRUE(initial_style);
- // Theming does not change the initial value for color, only the UA style for
- // the root element.
- EXPECT_EQ(Color::kBlack,
- initial_style->VisitedDependentColor(GetCSSPropertyColor()));
-}
-
-// The expectations are based on LayoutThemeDefault::SystemColor.
-// LayoutThemeMac doesn't use that code path.
+// The expectations in the tests below are relying on LayoutThemeDefault.
+// LayoutThemeMac doesn't inherit from that class.
#if !defined(OS_MACOSX)
TEST_F(LayoutThemeTest, SystemColorWithColorScheme) {
SetHtmlInnerHTML(R"HTML(
@@ -150,9 +103,8 @@ TEST_F(LayoutThemeTest, SystemColorWithColorScheme) {
style->VisitedDependentColor(GetCSSPropertyColor()));
// Change color scheme to dark.
- ColorSchemeHelper color_scheme_helper;
- color_scheme_helper.SetPreferredColorScheme(GetDocument(),
- PreferredColorScheme::kDark);
+ ColorSchemeHelper color_scheme_helper(GetDocument());
+ color_scheme_helper.SetPreferredColorScheme(PreferredColorScheme::kDark);
UpdateAllLifecyclePhasesForTest();
style = dark_element->GetComputedStyle();
@@ -160,6 +112,32 @@ TEST_F(LayoutThemeTest, SystemColorWithColorScheme) {
EXPECT_EQ(Color(0x44, 0x44, 0x44),
style->VisitedDependentColor(GetCSSPropertyColor()));
}
+
+TEST_F(LayoutThemeTest, SetSelectionColors) {
+ LayoutTheme::GetTheme().SetSelectionColors(Color::kBlack, Color::kBlack,
+ Color::kBlack, Color::kBlack);
+ EXPECT_EQ(Color::kBlack,
+ LayoutTheme::GetTheme().ActiveSelectionForegroundColor(
+ WebColorScheme::kLight));
+ {
+ // Enabling MobileLayoutTheme switches which instance is returned from
+ // LayoutTheme::GetTheme(). Devtools expect SetSelectionColors() to affect
+ // both LayoutTheme instances.
+ ScopedMobileLayoutThemeForTest scope(true);
+ EXPECT_EQ(Color::kBlack,
+ LayoutTheme::GetTheme().ActiveSelectionForegroundColor(
+ WebColorScheme::kLight));
+
+ LayoutTheme::GetTheme().SetSelectionColors(Color::kWhite, Color::kWhite,
+ Color::kWhite, Color::kWhite);
+ EXPECT_EQ(Color::kWhite,
+ LayoutTheme::GetTheme().ActiveSelectionForegroundColor(
+ WebColorScheme::kLight));
+ }
+ EXPECT_EQ(Color::kWhite,
+ LayoutTheme::GetTheme().ActiveSelectionForegroundColor(
+ WebColorScheme::kLight));
+}
#endif // !defined(OS_MACOSX)
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc b/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
index 47bdaee8cb0..28cc1cbd7c3 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc
@@ -49,7 +49,7 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
+#include "third_party/blink/renderer/core/layout/ng/list/list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_image.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_inline.h"
@@ -487,8 +487,7 @@ static void WriteTextFragment(WTF::TextStream& ts,
const NGTextFragment fragment(paint_fragment->Style().GetWritingMode(),
*physical_text_fragment);
WriteTextFragment(ts, paint_fragment->GetLayoutObject(),
- PhysicalRect(paint_fragment->InlineOffsetToContainerBox(),
- paint_fragment->Size()),
+ paint_fragment->RectInContainerBlock(),
paint_fragment->Style(), physical_text_fragment->Text(),
fragment.InlineSize());
return;
@@ -499,8 +498,8 @@ static void WriteTextFragment(WTF::TextStream& ts,
item.Type() == NGFragmentItem::kGeneratedText);
const LayoutUnit inline_size =
item.IsHorizontal() ? item.Size().width : item.Size().height;
- WriteTextFragment(ts, item.GetLayoutObject(), item.Rect(), item.Style(),
- item.Text(cursor.Items()), inline_size);
+ WriteTextFragment(ts, item.GetLayoutObject(), item.RectInContainerBlock(),
+ item.Style(), item.Text(cursor.Items()), inline_size);
}
static void WritePaintProperties(WTF::TextStream& ts,
@@ -610,7 +609,8 @@ void Write(WTF::TextStream& ts,
FrameView* frame_view = ToLayoutEmbeddedContent(o).ChildFrameView();
if (auto* local_frame_view = DynamicTo<LocalFrameView>(frame_view)) {
if (auto* layout_view = local_frame_view->GetLayoutView()) {
- layout_view->GetDocument().UpdateStyleAndLayout();
+ layout_view->GetDocument().UpdateStyleAndLayout(
+ DocumentUpdateReason::kTest);
if (auto* layer = layout_view->Layer()) {
LayoutTreeAsText::WriteLayers(ts, layer, layer, indent + 1, behavior);
}
@@ -900,7 +900,8 @@ String ExternalRepresentation(LocalFrame* frame,
LayoutAsTextBehavior behavior,
const PaintLayer* marked_layer) {
if (!(behavior & kLayoutAsTextDontUpdateLayout)) {
- bool success = frame->View()->UpdateAllLifecyclePhasesExceptPaint();
+ bool success = frame->View()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kTest);
DCHECK(success);
};
@@ -931,8 +932,9 @@ String ExternalRepresentation(LocalFrame* frame,
String ExternalRepresentation(Element* element, LayoutAsTextBehavior behavior) {
// Doesn't support printing mode.
DCHECK(!(behavior & kLayoutAsTextPrintingMode));
- if (!(behavior & kLayoutAsTextDontUpdateLayout))
- element->GetDocument().UpdateStyleAndLayout();
+ if (!(behavior & kLayoutAsTextDontUpdateLayout)) {
+ element->GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
+ }
LayoutObject* layout_object = element->GetLayoutObject();
if (!layout_object || !layout_object->IsBox())
@@ -958,11 +960,14 @@ static void WriteCounterValuesFromChildren(WTF::TextStream& stream,
}
String CounterValueForElement(Element* element) {
- element->GetDocument().UpdateStyleAndLayout();
+ element->GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
WTF::TextStream stream;
bool is_first_counter = true;
- // The counter layoutObjects should be children of :before or :after
- // pseudo-elements.
+ // The counter LayoutObjects should be children of ::marker, ::before or
+ // ::after pseudo-elements.
+ if (LayoutObject* marker =
+ element->PseudoElementLayoutObject(kPseudoIdMarker))
+ WriteCounterValuesFromChildren(stream, marker, is_first_counter);
if (LayoutObject* before =
element->PseudoElementLayoutObject(kPseudoIdBefore))
WriteCounterValuesFromChildren(stream, before, is_first_counter);
@@ -972,14 +977,16 @@ String CounterValueForElement(Element* element) {
}
String MarkerTextForListItem(Element* element) {
- element->GetDocument().UpdateStyleAndLayout();
+ element->GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
LayoutObject* layout_object = element->GetLayoutObject();
if (layout_object) {
if (layout_object->IsListItem())
return ToLayoutListItem(layout_object)->MarkerText();
- if (layout_object->IsLayoutNGListItem())
- return ToLayoutNGListItem(layout_object)->MarkerTextWithoutSuffix();
+ if (layout_object->IsLayoutNGListItem()) {
+ if (LayoutObject* marker = ToLayoutNGListItem(layout_object)->Marker())
+ return ListMarker::Get(marker)->MarkerTextWithoutSuffix(*marker);
+ }
}
return String();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_video.cc b/chromium/third_party/blink/renderer/core/layout/layout_video.cc
index 5b910056fbe..5a71ef5b8ce 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_video.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_video.cc
@@ -28,7 +28,6 @@
#include "third_party/blink/public/platform/web_size.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/html/media/html_video_element.h"
-#include "third_party/blink/renderer/core/html/media/media_element_parser_helpers.h"
#include "third_party/blink/renderer/core/paint/video_painter.h"
namespace blink {
@@ -62,7 +61,7 @@ void LayoutVideo::UpdateIntrinsicSize(bool is_in_layout) {
return;
SetIntrinsicSize(size);
- SetPreferredLogicalWidthsDirty();
+ SetIntrinsicLogicalWidthsDirty();
if (!is_in_layout) {
SetNeedsLayoutAndFullPaintInvalidation(
layout_invalidation_reason::kSizeChanged);
@@ -73,9 +72,10 @@ LayoutSize LayoutVideo::CalculateIntrinsicSize() {
HTMLVideoElement* video = VideoElement();
DCHECK(video);
- if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
- !video->GetOverriddenIntrinsicSize().IsEmpty())
- return LayoutSize(video->GetOverriddenIntrinsicSize());
+ if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled()) {
+ if (video->IsDefaultIntrinsicSize())
+ return DefaultSize();
+ }
// Spec text from 4.8.6
//
@@ -91,7 +91,7 @@ LayoutSize LayoutVideo::CalculateIntrinsicSize() {
WebMediaPlayer* web_media_player = MediaElement()->GetWebMediaPlayer();
if (web_media_player &&
video->getReadyState() >= HTMLVideoElement::kHaveMetadata) {
- IntSize size = web_media_player->NaturalSize();
+ IntSize size(web_media_player->NaturalSize());
if (!size.IsEmpty())
return LayoutSize(size);
}
@@ -189,7 +189,7 @@ bool LayoutVideo::SupportsAcceleratedRendering() const {
}
CompositingReasons LayoutVideo::AdditionalCompositingReasons() const {
- HTMLMediaElement* element = ToHTMLMediaElement(GetNode());
+ auto* element = To<HTMLMediaElement>(GetNode());
if (element->IsFullscreen() && element->UsesOverlayFullscreenVideo())
return CompositingReason::kVideo;
@@ -199,13 +199,4 @@ CompositingReasons LayoutVideo::AdditionalCompositingReasons() const {
return CompositingReason::kNone;
}
-void LayoutVideo::UpdateAfterLayout() {
- LayoutBox::UpdateAfterLayout();
- // Report violation of unsized-media policy.
- if (auto* video_element = DynamicTo<HTMLVideoElement>(GetNode())) {
- media_element_parser_helpers::ReportUnsizedMediaViolation(
- this, video_element->IsDefaultIntrinsicSize());
- }
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_video.h b/chromium/third_party/blink/renderer/core/layout/layout_video.h
index 66d2550ef51..ed6ce6aa006 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_video.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_video.h
@@ -27,6 +27,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_VIDEO_H_
#include "third_party/blink/renderer/core/layout/layout_media.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -50,8 +51,6 @@ class LayoutVideo final : public LayoutMedia {
void IntrinsicSizeChanged() override;
- void UpdateAfterLayout() override;
-
bool ComputeShouldClipOverflow() const final { return true; }
private:
@@ -77,6 +76,7 @@ class LayoutVideo final : public LayoutMedia {
LayoutUnit estimated_used_width = LayoutUnit()) const override;
LayoutUnit MinimumReplacedHeight() const override;
+ bool CanHaveAdditionalCompositingReasons() const override { return true; }
CompositingReasons AdditionalCompositingReasons() const override;
void UpdatePlayer(bool is_in_layout);
@@ -84,7 +84,10 @@ class LayoutVideo final : public LayoutMedia {
LayoutSize cached_image_size_;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutVideo, IsVideo());
+template <>
+struct DowncastTraits<LayoutVideo> {
+ static bool AllowFrom(const LayoutObject& object) { return object.IsVideo(); }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_view.cc b/chromium/third_party/blink/renderer/core/layout/layout_view.cc
index f1af97319ad..65ecfe44e87 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_view.cc
@@ -24,6 +24,7 @@
#include <inttypes.h>
#include "build/build_config.h"
+#include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_screen_info.h"
#include "third_party/blink/renderer/core/dom/document.h"
@@ -34,6 +35,7 @@
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/html_iframe_element.h"
+#include "third_party/blink/renderer/core/html/plugin_document.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/layout/geometry/transform_state.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
@@ -96,22 +98,20 @@ LayoutView::LayoutView(Document* document)
: LayoutBlockFlow(document),
frame_view_(document->View()),
layout_state_(nullptr),
- // TODO(pdr): This should be null if CompositeAfterPaintEnabled() is true.
- compositor_(std::make_unique<PaintLayerCompositor>(*this)),
+ compositor_(RuntimeEnabledFeatures::CompositeAfterPaintEnabled()
+ ? nullptr
+ : std::make_unique<PaintLayerCompositor>(*this)),
layout_quote_head_(nullptr),
layout_counter_count_(0),
hit_test_count_(0),
hit_test_cache_hits_(0),
hit_test_cache_(MakeGarbageCollected<HitTestCache>()),
- autosize_h_scrollbar_mode_(ScrollbarMode::kAuto),
- autosize_v_scrollbar_mode_(ScrollbarMode::kAuto) {
+ autosize_h_scrollbar_mode_(mojom::blink::ScrollbarMode::kAuto),
+ autosize_v_scrollbar_mode_(mojom::blink::ScrollbarMode::kAuto) {
// init LayoutObject attributes
SetInline(false);
- min_preferred_logical_width_ = LayoutUnit();
- max_preferred_logical_width_ = LayoutUnit();
-
- SetPreferredLogicalWidthsDirty(kMarkOnlyThis);
+ SetIntrinsicLogicalWidthsDirty(kMarkOnlyThis);
SetPositionState(EPosition::kAbsolute); // to 0,0 :)
@@ -135,7 +135,8 @@ bool LayoutView::HitTest(const HitTestLocation& location,
// Note that if an iframe has its render pipeline throttled, it will not
// update layout here, and it will also not propagate the hit test into the
// iframe's inner document.
- if (!GetFrameView()->UpdateAllLifecyclePhasesExceptPaint())
+ if (!GetFrameView()->UpdateAllLifecyclePhasesExceptPaint(
+ DocumentUpdateReason::kHitTest))
return false;
HitTestLatencyRecorder hit_test_latency_recorder(
result.GetHitTestRequest().AllowsChildFrameContent());
@@ -240,7 +241,8 @@ bool LayoutView::CanHaveChildren() const {
// the PluginDocument's <embed> element to have an EmbeddedContentView, which
// it acquires during LocalFrameView::UpdatePlugins, which operates on the
// <embed> element's layout object (LayoutEmbeddedObject).
- if (GetDocument().IsPluginDocument() || GetDocument().IsForExternalHandler())
+ if (IsA<PluginDocument>(GetDocument()) ||
+ GetDocument().IsForExternalHandler())
return true;
return !owner->IsDisplayNone();
}
@@ -308,8 +310,7 @@ void LayoutView::UpdateLayout() {
SetPageLogicalHeight(LayoutUnit());
if (PageLogicalHeight() && ShouldUsePrintingLayout()) {
- min_preferred_logical_width_ = max_preferred_logical_width_ =
- LogicalWidth();
+ intrinsic_logical_widths_ = LogicalWidth();
if (!fragmentation_context_) {
fragmentation_context_ =
std::make_unique<ViewFragmentationContext>(*this);
@@ -528,7 +529,8 @@ bool LayoutView::MapToVisualRectInAncestorSpaceInternal(
if (!owner) {
PhysicalRect rect = PhysicalRect::EnclosingRect(
transform_state.LastPlanarQuad().BoundingBox());
- bool retval = GetFrameView()->MapToVisualRectInRemoteRootFrame(rect);
+ bool retval = GetFrameView()->MapToVisualRectInRemoteRootFrame(
+ rect, !(visual_rect_flags & kDontApplyMainFrameOverflowClip));
transform_state.SetQuad(FloatQuad(FloatRect(rect)));
return retval;
}
@@ -617,15 +619,17 @@ PhysicalRect LayoutView::OverflowClipRect(
return rect;
}
-void LayoutView::SetAutosizeScrollbarModes(ScrollbarMode h_mode,
- ScrollbarMode v_mode) {
- DCHECK_EQ(v_mode == ScrollbarMode::kAuto, h_mode == ScrollbarMode::kAuto);
+void LayoutView::SetAutosizeScrollbarModes(mojom::blink::ScrollbarMode h_mode,
+ mojom::blink::ScrollbarMode v_mode) {
+ DCHECK_EQ(v_mode == mojom::blink::ScrollbarMode::kAuto,
+ h_mode == mojom::blink::ScrollbarMode::kAuto);
autosize_v_scrollbar_mode_ = v_mode;
autosize_h_scrollbar_mode_ = h_mode;
}
-void LayoutView::CalculateScrollbarModes(ScrollbarMode& h_mode,
- ScrollbarMode& v_mode) const {
+void LayoutView::CalculateScrollbarModes(
+ mojom::blink::ScrollbarMode& h_mode,
+ mojom::blink::ScrollbarMode& v_mode) const {
#define RETURN_SCROLLBAR_MODE(mode) \
{ \
h_mode = v_mode = mode; \
@@ -634,8 +638,8 @@ void LayoutView::CalculateScrollbarModes(ScrollbarMode& h_mode,
// FrameViewAutoSizeInfo manually controls the appearance of the main frame's
// scrollbars so defer to those if we're in AutoSize mode.
- if (AutosizeVerticalScrollbarMode() != ScrollbarMode::kAuto ||
- AutosizeHorizontalScrollbarMode() != ScrollbarMode::kAuto) {
+ if (AutosizeVerticalScrollbarMode() != mojom::blink::ScrollbarMode::kAuto ||
+ AutosizeHorizontalScrollbarMode() != mojom::blink::ScrollbarMode::kAuto) {
h_mode = AutosizeHorizontalScrollbarMode();
v_mode = AutosizeVerticalScrollbarMode();
return;
@@ -643,19 +647,19 @@ void LayoutView::CalculateScrollbarModes(ScrollbarMode& h_mode,
LocalFrame* frame = GetFrame();
if (!frame)
- RETURN_SCROLLBAR_MODE(ScrollbarMode::kAlwaysOff);
+ RETURN_SCROLLBAR_MODE(mojom::blink::ScrollbarMode::kAlwaysOff);
if (FrameOwner* owner = frame->Owner()) {
// Setting scrolling="no" on an iframe element disables scrolling.
- if (owner->ScrollingMode() == ScrollbarMode::kAlwaysOff)
- RETURN_SCROLLBAR_MODE(ScrollbarMode::kAlwaysOff);
+ if (owner->ScrollbarMode() == mojom::blink::ScrollbarMode::kAlwaysOff)
+ RETURN_SCROLLBAR_MODE(mojom::blink::ScrollbarMode::kAlwaysOff);
}
Document& document = GetDocument();
if (Node* body = document.body()) {
// Framesets can't scroll.
if (body->GetLayoutObject() && body->GetLayoutObject()->IsFrameSet())
- RETURN_SCROLLBAR_MODE(ScrollbarMode::kAlwaysOff);
+ RETURN_SCROLLBAR_MODE(mojom::blink::ScrollbarMode::kAlwaysOff);
}
if (document.IsCapturingLayout()) {
@@ -663,40 +667,40 @@ void LayoutView::CalculateScrollbarModes(ScrollbarMode& h_mode,
// displayed.
// TODO(szager): Figure out the right behavior when printing an overflowing
// iframe. https://bugs.chromium.org/p/chromium/issues/detail?id=777528
- RETURN_SCROLLBAR_MODE(ScrollbarMode::kAlwaysOff);
+ RETURN_SCROLLBAR_MODE(mojom::blink::ScrollbarMode::kAlwaysOff);
}
if (LocalFrameView* frameView = GetFrameView()) {
// Scrollbars can be disabled by LocalFrameView::setCanHaveScrollbars.
if (!frameView->CanHaveScrollbars())
- RETURN_SCROLLBAR_MODE(ScrollbarMode::kAlwaysOff);
+ RETURN_SCROLLBAR_MODE(mojom::blink::ScrollbarMode::kAlwaysOff);
}
Element* viewportDefiningElement = document.ViewportDefiningElement();
if (!viewportDefiningElement)
- RETURN_SCROLLBAR_MODE(ScrollbarMode::kAuto);
+ RETURN_SCROLLBAR_MODE(mojom::blink::ScrollbarMode::kAuto);
LayoutObject* viewport = viewportDefiningElement->GetLayoutObject();
if (!viewport)
- RETURN_SCROLLBAR_MODE(ScrollbarMode::kAuto);
+ RETURN_SCROLLBAR_MODE(mojom::blink::ScrollbarMode::kAuto);
const ComputedStyle* style = viewport->Style();
if (!style)
- RETURN_SCROLLBAR_MODE(ScrollbarMode::kAuto);
+ RETURN_SCROLLBAR_MODE(mojom::blink::ScrollbarMode::kAuto);
if (viewport->IsSVGRoot()) {
// Don't allow overflow to affect <img> and css backgrounds
if (ToLayoutSVGRoot(viewport)->IsEmbeddedThroughSVGImage())
- RETURN_SCROLLBAR_MODE(ScrollbarMode::kAuto);
+ RETURN_SCROLLBAR_MODE(mojom::blink::ScrollbarMode::kAuto);
// FIXME: evaluate if we can allow overflow for these cases too.
// Overflow is always hidden when stand-alone SVG documents are embedded.
if (ToLayoutSVGRoot(viewport)
->IsEmbeddedThroughFrameContainingSVGDocument())
- RETURN_SCROLLBAR_MODE(ScrollbarMode::kAlwaysOff);
+ RETURN_SCROLLBAR_MODE(mojom::blink::ScrollbarMode::kAlwaysOff);
}
- h_mode = v_mode = ScrollbarMode::kAuto;
+ h_mode = v_mode = mojom::blink::ScrollbarMode::kAuto;
EOverflow overflow_x = style->OverflowX();
EOverflow overflow_y = style->OverflowY();
@@ -709,25 +713,19 @@ void LayoutView::CalculateScrollbarModes(ScrollbarMode& h_mode,
}
if (!shouldIgnoreOverflowHidden) {
if (overflow_x == EOverflow::kHidden)
- h_mode = ScrollbarMode::kAlwaysOff;
+ h_mode = mojom::blink::ScrollbarMode::kAlwaysOff;
if (overflow_y == EOverflow::kHidden)
- v_mode = ScrollbarMode::kAlwaysOff;
+ v_mode = mojom::blink::ScrollbarMode::kAlwaysOff;
}
if (overflow_x == EOverflow::kScroll)
- h_mode = ScrollbarMode::kAlwaysOn;
+ h_mode = mojom::blink::ScrollbarMode::kAlwaysOn;
if (overflow_y == EOverflow::kScroll)
- v_mode = ScrollbarMode::kAlwaysOn;
+ v_mode = mojom::blink::ScrollbarMode::kAlwaysOn;
#undef RETURN_SCROLLBAR_MODE
}
-void LayoutView::MayUpdateHoverWhenContentUnderMouseChanged(
- EventHandler& event_handler) {
- event_handler.MayUpdateHoverWhenContentUnderMouseChanged(
- MouseEventManager::UpdateHoverReason::kScrollOffsetChanged);
-}
-
PhysicalRect LayoutView::DocumentRect() const {
return FlipForWritingMode(LayoutOverflowRect());
}
@@ -813,7 +811,6 @@ bool LayoutView::UsesCompositing() const {
}
PaintLayerCompositor* LayoutView::Compositor() {
- DCHECK(compositor_);
return compositor_.get();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_view.h b/chromium/third_party/blink/renderer/core/layout/layout_view.h
index 38b4e574759..10753eb247a 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_view.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_view.h
@@ -23,6 +23,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_VIEW_H_
#include <memory>
+#include "third_party/blink/public/mojom/scroll/scrollbar_mode.mojom-blink.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/hit_test_cache.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
@@ -31,6 +32,7 @@
#include "third_party/blink/renderer/core/scroll/scrollable_area.h"
#include "third_party/blink/renderer/platform/graphics/scroll_types.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -164,18 +166,17 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
kIgnorePlatformOverlayScrollbarSize) const override;
// If either direction has a non-auto mode, the other must as well.
- void SetAutosizeScrollbarModes(ScrollbarMode h_mode, ScrollbarMode v_mode);
- ScrollbarMode AutosizeHorizontalScrollbarMode() const {
+ void SetAutosizeScrollbarModes(mojom::blink::ScrollbarMode h_mode,
+ mojom::blink::ScrollbarMode v_mode);
+ mojom::blink::ScrollbarMode AutosizeHorizontalScrollbarMode() const {
return autosize_h_scrollbar_mode_;
}
- ScrollbarMode AutosizeVerticalScrollbarMode() const {
+ mojom::blink::ScrollbarMode AutosizeVerticalScrollbarMode() const {
return autosize_v_scrollbar_mode_;
}
- void CalculateScrollbarModes(ScrollbarMode& h_mode,
- ScrollbarMode& v_mode) const;
-
- void MayUpdateHoverWhenContentUnderMouseChanged(EventHandler&) override;
+ void CalculateScrollbarModes(mojom::blink::ScrollbarMode& h_mode,
+ mojom::blink::ScrollbarMode& v_mode) const;
LayoutState* GetLayoutState() const { return layout_state_; }
@@ -277,6 +278,10 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
previous_background_rect_ = r;
}
+ void MapAncestorToLocal(const LayoutBoxModelObject*,
+ TransformState&,
+ MapCoordinatesFlags) const override;
+
private:
void MapLocalToAncestor(const LayoutBoxModelObject* ancestor,
TransformState&,
@@ -285,10 +290,6 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
const LayoutObject* PushMappingToContainer(
const LayoutBoxModelObject* ancestor_to_stop_at,
LayoutGeometryMap&) const override;
- void MapAncestorToLocal(const LayoutBoxModelObject*,
- TransformState&,
- MapCoordinatesFlags) const override;
-
bool CanHaveChildren() const override;
void UpdateBlockLayout(bool relayout_children) override;
@@ -338,15 +339,20 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
// FrameViewAutoSizeInfo controls scrollbar appearance manually rather than
// relying on layout. These members are used to override the ScrollbarModes
// calculated from style. kScrollbarAuto disables the override.
- ScrollbarMode autosize_h_scrollbar_mode_;
- ScrollbarMode autosize_v_scrollbar_mode_;
+ mojom::blink::ScrollbarMode autosize_h_scrollbar_mode_;
+ mojom::blink::ScrollbarMode autosize_v_scrollbar_mode_;
Vector<IntRect> tickmarks_override_;
mutable PhysicalRect previous_background_rect_;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutView, IsLayoutView());
+template <>
+struct DowncastTraits<LayoutView> {
+ static bool AllowFrom(const LayoutObject& object) {
+ return object.IsLayoutView();
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_view_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_view_test.cc
index 1f69fd44cdc..94dbb303112 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_view_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_view_test.cc
@@ -57,7 +57,7 @@ TEST_F(LayoutViewTest, DisplayNoneFrame) {
EXPECT_FALSE(view->CanHaveChildren());
EXPECT_FALSE(frame_doc->documentElement()->GetComputedStyle());
- frame_doc->body()->SetInnerHTMLFromString(R"HTML(
+ frame_doc->body()->setInnerHTML(R"HTML(
<div id="div"></div>
)HTML");
@@ -74,11 +74,11 @@ class LayoutViewHitTestTest : public testing::WithParamInterface<HitTestConfig>,
public RenderingTest {
public:
LayoutViewHitTestTest()
- : ScopedLayoutNGForTest(LayoutNG()),
+ : ScopedLayoutNGForTest(GetParam().layout_ng),
RenderingTest(MakeGarbageCollected<SingleChildLocalFrameClient>()) {}
protected:
- bool LayoutNG() { return GetParam().layout_ng; }
+ bool LayoutNG() { return RuntimeEnabledFeatures::LayoutNGEnabled(); }
bool IsAndroidOrWindowsEditingBehavior() {
// TODO(crbug.com/971414): For now LayoutNG always uses Android/Windows
// behavior for ShouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom().
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_vtt_cue.cc b/chromium/third_party/blink/renderer/core/layout/layout_vtt_cue.cc
index fa49a3ec625..f882270bd8c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_vtt_cue.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_vtt_cue.cc
@@ -329,8 +329,7 @@ IntRect LayoutVTTCue::ComputeControlsRect() const {
// the MediaControls.
DCHECK(Parent()->GetNode()->IsTextTrackContainer());
- HTMLMediaElement* media_element =
- ToHTMLMediaElement(Parent()->Parent()->GetNode());
+ auto* media_element = To<HTMLMediaElement>(Parent()->Parent()->GetNode());
DCHECK(media_element);
MediaControls* controls = media_element->GetMediaControls();
diff --git a/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc b/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc
index 1907ede364d..371d92665ef 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box.cc
@@ -305,6 +305,8 @@ bool LegacyAbstractInlineTextBox::IsLineBreak() const {
const NGOffsetMapping* LegacyAbstractInlineTextBox::GetOffsetMapping() const {
const auto* text_node = DynamicTo<Text>(GetNode());
+ if (!text_node)
+ return nullptr;
LayoutBlockFlow& block_flow = *NGOffsetMapping::GetInlineFormattingContextOf(
*text_node->GetLayoutObject());
diff --git a/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box_test.cc b/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box_test.cc
index d63206fe779..5067af15179 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/line/abstract_inline_text_box_test.cc
@@ -20,7 +20,9 @@ class AbstractInlineTextBoxTest : public testing::WithParamInterface<bool>,
AbstractInlineTextBoxTest() : ScopedLayoutNGForTest(GetParam()) {}
protected:
- bool LayoutNGEnabled() const { return GetParam(); }
+ bool LayoutNGEnabled() const {
+ return RuntimeEnabledFeatures::LayoutNGEnabled();
+ }
};
INSTANTIATE_TEST_SUITE_P(All, AbstractInlineTextBoxTest, testing::Bool());
@@ -116,9 +118,10 @@ TEST_P(AbstractInlineTextBoxTest, GetTextWithLineBreakAtTrailingWhiteSpace) {
TEST_P(AbstractInlineTextBoxTest, GetTextOffsetInContainer) {
// "&#10" is a Line Feed ("\n").
- SetBodyInnerHTML(
- R"HTML(<style>p { white-space: pre-line; }</style>
- <p id="paragraph">First sentence of the &#10; paragraph. Second sentence of &#10; the paragraph.</p>)HTML");
+ SetBodyInnerHTML(R"HTML(
+ <style>p { white-space: pre-line; }</style>
+ <p id="paragraph">First sentence of the &#10; paragraph. Second sentence of &#10; the paragraph. </p>
+ <br id='br'>)HTML");
const Element& paragraph = *GetDocument().getElementById("paragraph");
LayoutText& layout_text =
@@ -145,6 +148,13 @@ TEST_P(AbstractInlineTextBoxTest, GetTextOffsetInContainer) {
inline_text_box = inline_text_box->NextInlineTextBox()->NextInlineTextBox();
EXPECT_EQ("the paragraph.", inline_text_box->GetText());
EXPECT_EQ(52u, inline_text_box->TextOffsetInContainer(0));
+
+ // Ensure that calling TextOffsetInContainer on a br gives the correct result.
+ const Element& br_element = *GetDocument().getElementById("br");
+ LayoutText& br_text = *ToLayoutText(br_element.GetLayoutObject());
+ inline_text_box = br_text.FirstAbstractInlineTextBox();
+ EXPECT_EQ("\n", inline_text_box->GetText());
+ EXPECT_EQ(0u, inline_text_box->TextOffsetInContainer(0));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/line/inline_box.cc b/chromium/third_party/blink/renderer/core/layout/line/inline_box.cc
index e9fb4e46810..234f99caab9 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/inline_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/line/inline_box.cc
@@ -20,6 +20,7 @@
#include "third_party/blink/renderer/core/layout/line/inline_box.h"
#include "base/allocator/partition_allocator/partition_alloc.h"
+#include "third_party/blink/renderer/core/dom/dom_node_ids.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_api_shim.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/hit_test_location.h"
@@ -100,6 +101,12 @@ IntRect InlineBox::PartialInvalidationVisualRect() const {
return GetLineLayoutItem().PartialInvalidationVisualRectForInlineBox();
}
+DOMNodeId InlineBox::OwnerNodeId() const {
+ return GetLineLayoutItem().GetNode()
+ ? DOMNodeIds::IdForNode(GetLineLayoutItem().GetNode())
+ : kInvalidDOMNodeId;
+}
+
#if DCHECK_IS_ON()
void InlineBox::ShowTreeForThis() const {
GetLineLayoutItem().ShowTreeForThis();
diff --git a/chromium/third_party/blink/renderer/core/layout/line/inline_box.h b/chromium/third_party/blink/renderer/core/layout/line/inline_box.h
index 2d5dc2026b9..07c06a0bc5c 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/inline_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/line/inline_box.h
@@ -131,6 +131,7 @@ class CORE_EXPORT InlineBox : public DisplayItemClient {
String DebugName() const override;
IntRect VisualRect() const override;
IntRect PartialInvalidationVisualRect() const override;
+ DOMNodeId OwnerNodeId() const override;
bool IsText() const { return bitfields_.IsText(); }
void SetIsText(bool is_text) { bitfields_.SetIsText(is_text); }
diff --git a/chromium/third_party/blink/renderer/core/layout/map_coordinates_test.cc b/chromium/third_party/blink/renderer/core/layout/map_coordinates_test.cc
index ae0b43acf1f..22aefbe8f04 100644
--- a/chromium/third_party/blink/renderer/core/layout/map_coordinates_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/map_coordinates_test.cc
@@ -363,7 +363,7 @@ TEST_F(MapCoordinatesTest, FixedPos) {
LayoutBox* body = container->ParentBox();
LayoutBox* html = body->ParentBox();
LayoutBox* view = html->ParentBox();
- ASSERT_TRUE(view->IsLayoutView());
+ ASSERT_TRUE(IsA<LayoutView>(view));
PhysicalOffset mapped_point =
MapLocalToAncestor(target, view, PhysicalOffset());
@@ -423,7 +423,7 @@ TEST_F(MapCoordinatesTest, FixedPosAuto) {
LayoutBox* body = container->ParentBox();
LayoutBox* html = body->ParentBox();
LayoutBox* view = html->ParentBox();
- ASSERT_TRUE(view->IsLayoutView());
+ ASSERT_TRUE(IsA<LayoutView>(view));
PhysicalOffset mapped_point =
MapLocalToAncestor(target, target->ContainingBlock(), PhysicalOffset());
@@ -489,7 +489,7 @@ TEST_F(MapCoordinatesTest, FixedPosInFixedPos) {
LayoutBox* body = container->ParentBox();
LayoutBox* html = body->ParentBox();
LayoutBox* view = html->ParentBox();
- ASSERT_TRUE(view->IsLayoutView());
+ ASSERT_TRUE(IsA<LayoutView>(view));
PhysicalOffset mapped_point =
MapLocalToAncestor(target, view, PhysicalOffset());
@@ -549,10 +549,10 @@ TEST_F(MapCoordinatesTest, FixedPosInFixedPosScrollView) {
LayoutBox* body = container->ParentBox();
LayoutBox* html = body->ParentBox();
LayoutBox* view = html->ParentBox();
- ASSERT_TRUE(view->IsLayoutView());
+ ASSERT_TRUE(IsA<LayoutView>(view));
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0.0, 50),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0.0, 50), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(50,
GetDocument().View()->LayoutViewport()->ScrollOffsetInt().Height());
@@ -584,10 +584,10 @@ TEST_F(MapCoordinatesTest, FixedPosInAbsolutePosScrollView) {
LayoutBox* body = container->ParentBox();
LayoutBox* html = body->ParentBox();
LayoutBox* view = html->ParentBox();
- ASSERT_TRUE(view->IsLayoutView());
+ ASSERT_TRUE(IsA<LayoutView>(view));
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0.0, 50),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0.0, 50), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(50,
GetDocument().View()->LayoutViewport()->ScrollOffsetInt().Height());
@@ -615,8 +615,8 @@ TEST_F(MapCoordinatesTest, FixedPosInTransform) {
<div class='spacer'></div>
)HTML");
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0.0, 50),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0.0, 50), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(50,
GetDocument().View()->LayoutViewport()->ScrollOffsetInt().Height());
@@ -626,7 +626,7 @@ TEST_F(MapCoordinatesTest, FixedPosInTransform) {
LayoutBox* body = container->ParentBox();
LayoutBox* html = body->ParentBox();
LayoutBox* view = html->ParentBox();
- ASSERT_TRUE(view->IsLayoutView());
+ ASSERT_TRUE(IsA<LayoutView>(view));
PhysicalOffset mapped_point =
MapLocalToAncestor(target, view, PhysicalOffset());
@@ -655,8 +655,8 @@ TEST_F(MapCoordinatesTest, FixedPosInContainPaint) {
<div class='spacer'></div>
)HTML");
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0.0, 50),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0.0, 50), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
EXPECT_EQ(50,
GetDocument().View()->LayoutViewport()->ScrollOffsetInt().Height());
@@ -666,7 +666,7 @@ TEST_F(MapCoordinatesTest, FixedPosInContainPaint) {
LayoutBox* body = container->ParentBox();
LayoutBox* html = body->ParentBox();
LayoutBox* view = html->ParentBox();
- ASSERT_TRUE(view->IsLayoutView());
+ ASSERT_TRUE(IsA<LayoutView>(view));
PhysicalOffset mapped_point =
MapLocalToAncestor(target, view, PhysicalOffset());
@@ -700,7 +700,7 @@ TEST_F(MapCoordinatesTest, FixedPosInIFrameWhenMainFrameScrolled) {
"position:fixed}</style><div id=target></div>");
GetDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0.0, 1000), kProgrammaticScroll);
+ ScrollOffset(0.0, 1000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
Element* target = ChildDocument().getElementById("target");
@@ -731,9 +731,8 @@ TEST_F(MapCoordinatesTest, IFrameTransformed) {
UpdateAllLifecyclePhasesForTest();
ChildDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0.0, 1000), kProgrammaticScroll);
- ChildDocument().View()->UpdateAllLifecyclePhases(
- DocumentLifecycle::LifecycleUpdateReason::kTest);
+ ScrollOffset(0.0, 1000), mojom::blink::ScrollType::kProgrammatic);
+ ChildDocument().View()->UpdateAllLifecyclePhases(DocumentUpdateReason::kTest);
Element* target = ChildDocument().getElementById("target");
ASSERT_TRUE(target);
@@ -768,7 +767,7 @@ TEST_F(MapCoordinatesTest, FixedPosInScrolledIFrameWithTransform) {
UpdateAllLifecyclePhasesForTest();
ChildDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0.0, 1000), kProgrammaticScroll);
+ ScrollOffset(0.0, 1000), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
Element* target = ChildDocument().getElementById("target");
diff --git a/chromium/third_party/blink/renderer/core/layout/min_max_size_test.cc b/chromium/third_party/blink/renderer/core/layout/min_max_size_test.cc
index af5cb1e84b0..31171af4b41 100644
--- a/chromium/third_party/blink/renderer/core/layout/min_max_size_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/min_max_size_test.cc
@@ -2,7 +2,7 @@
// 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/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -11,7 +11,7 @@ namespace blink {
namespace {
TEST(NGUnitsTest, ShrinkToFit) {
- MinMaxSize sizes;
+ MinMaxSizes sizes;
sizes.min_size = LayoutUnit(100);
sizes.max_size = LayoutUnit(200);
diff --git a/chromium/third_party/blink/renderer/core/layout/min_max_size.cc b/chromium/third_party/blink/renderer/core/layout/min_max_sizes.cc
index e6980104b3c..15f5bf6aca8 100644
--- a/chromium/third_party/blink/renderer/core/layout/min_max_size.cc
+++ b/chromium/third_party/blink/renderer/core/layout/min_max_sizes.cc
@@ -2,13 +2,13 @@
// 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/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include <algorithm>
namespace blink {
-std::ostream& operator<<(std::ostream& stream, const MinMaxSize& value) {
+std::ostream& operator<<(std::ostream& stream, const MinMaxSizes& value) {
return stream << "(" << value.min_size << ", " << value.max_size << ")";
}
diff --git a/chromium/third_party/blink/renderer/core/layout/min_max_size.h b/chromium/third_party/blink/renderer/core/layout/min_max_sizes.h
index 4233e6c79a1..721ecec1738 100644
--- a/chromium/third_party/blink/renderer/core/layout/min_max_size.h
+++ b/chromium/third_party/blink/renderer/core/layout/min_max_sizes.h
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_MIN_MAX_SIZE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_MIN_MAX_SIZE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_MIN_MAX_SIZES_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_MIN_MAX_SIZES_H_
#include <algorithm>
@@ -15,12 +15,12 @@ namespace blink {
// A struct that holds a pair of two sizes, a "min" size and a "max" size.
// Useful for holding a {min,max}-content size pair or a
// {min,max}-{width,height}.
-struct CORE_EXPORT MinMaxSize {
+struct CORE_EXPORT MinMaxSizes {
LayoutUnit min_size;
LayoutUnit max_size;
// Make sure that our min/max sizes are at least as large as |other|.
- void Encompass(const MinMaxSize& other) {
+ void Encompass(const MinMaxSizes& other) {
min_size = std::max(min_size, other.min_size);
max_size = std::max(max_size, other.max_size);
}
@@ -50,30 +50,30 @@ struct CORE_EXPORT MinMaxSize {
return std::max(min_size, std::min(size, max_size));
}
- bool operator==(const MinMaxSize& other) const {
+ bool operator==(const MinMaxSizes& other) const {
return min_size == other.min_size && max_size == other.max_size;
}
void operator=(LayoutUnit value) { min_size = max_size = value; }
- MinMaxSize& operator+=(MinMaxSize extra) {
+ MinMaxSizes& operator+=(MinMaxSizes extra) {
min_size += extra.min_size;
max_size += extra.max_size;
return *this;
}
- MinMaxSize& operator+=(const LayoutUnit length) {
+ MinMaxSizes& operator+=(const LayoutUnit length) {
min_size += length;
max_size += length;
return *this;
}
- MinMaxSize& operator-=(const LayoutUnit length) {
+ MinMaxSizes& operator-=(const LayoutUnit length) {
min_size -= length;
max_size -= length;
return *this;
}
};
-CORE_EXPORT std::ostream& operator<<(std::ostream&, const MinMaxSize&);
+CORE_EXPORT std::ostream& operator<<(std::ostream&, const MinMaxSizes&);
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_MIN_MAX_SIZE_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_MIN_MAX_SIZES_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.cc
index 3ac1c1fbcb5..b662f819135 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.cc
@@ -13,6 +13,8 @@
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_fragment_result_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_function.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_intrinsic_sizes_callback.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_intrinsic_sizes_result_options.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_layout_callback.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_no_argument_constructor.h"
#include "third_party/blink/renderer/core/css/cssom/prepopulated_computed_style_property_map.h"
@@ -23,20 +25,41 @@
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_edges.h"
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_scope.h"
-#include "third_party/blink/renderer/core/layout/ng/custom/fragment_result_options.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
#include "third_party/blink/renderer/platform/bindings/microtask.h"
#include "third_party/blink/renderer/platform/bindings/script_state.h"
#include "third_party/blink/renderer/platform/bindings/v8_binding_macros.h"
#include "third_party/blink/renderer/platform/bindings/v8_object_constructor.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
namespace blink {
+namespace {
+
+void GatherChildren(const NGBlockNode& node,
+ CustomLayoutScope* custom_layout_scope,
+ HeapVector<Member<CustomLayoutChild>>* children) {
+ // TODO(ikilpatrick): Determine if knowing the size of the array ahead of
+ // time improves performance in any noticeable way.
+ for (NGLayoutInputNode child = node.FirstChild(); child;
+ child = child.NextSibling()) {
+ if (child.IsOutOfFlowPositioned())
+ continue;
+
+ CustomLayoutChild* layout_child = child.GetCustomLayoutChild();
+ layout_child->SetCustomLayoutToken(custom_layout_scope->Token());
+ DCHECK(layout_child);
+ children->push_back(layout_child);
+ }
+}
+
+} // anonymous namespace
+
CSSLayoutDefinition::CSSLayoutDefinition(
ScriptState* script_state,
V8NoArgumentConstructor* constructor,
- V8Function* intrinsic_sizes,
+ V8IntrinsicSizesCallback* intrinsic_sizes,
V8LayoutCallback* layout,
const Vector<CSSPropertyID>& native_invalidation_properties,
const Vector<AtomicString>& custom_invalidation_properties,
@@ -44,7 +67,7 @@ CSSLayoutDefinition::CSSLayoutDefinition(
const Vector<AtomicString>& child_custom_invalidation_properties)
: script_state_(script_state),
constructor_(constructor),
- unused_intrinsic_sizes_(intrinsic_sizes),
+ intrinsic_sizes_(intrinsic_sizes),
layout_(layout),
native_invalidation_properties_(native_invalidation_properties),
custom_invalidation_properties_(custom_invalidation_properties),
@@ -66,8 +89,9 @@ bool CSSLayoutDefinition::Instance::Layout(
const NGBlockNode& node,
const LogicalSize& border_box_size,
const NGBoxStrut& border_scrollbar_padding,
+ const LayoutUnit child_percentage_resolution_block_size_for_min_max,
CustomLayoutScope* custom_layout_scope,
- FragmentResultOptions* fragment_result_options,
+ FragmentResultOptions*& fragment_result_options,
scoped_refptr<SerializedScriptValue>* fragment_result_data) {
ScriptState* script_state = definition_->GetScriptState();
v8::Isolate* isolate = script_state->GetIsolate();
@@ -77,19 +101,8 @@ bool CSSLayoutDefinition::Instance::Layout(
ScriptState::Scope scope(script_state);
- // TODO(ikilpatrick): Determine if knowing the size of the array ahead of
- // time improves performance in any noticeable way.
HeapVector<Member<CustomLayoutChild>> children;
- for (NGLayoutInputNode child = node.FirstChild(); child;
- child = child.NextSibling()) {
- if (child.IsOutOfFlowPositioned())
- continue;
-
- CustomLayoutChild* layout_child = child.GetCustomLayoutChild();
- layout_child->SetCustomLayoutToken(custom_layout_scope->Token());
- DCHECK(layout_child);
- children.push_back(layout_child);
- }
+ GatherChildren(node, custom_layout_scope, &children);
CustomLayoutEdges* edges =
MakeGarbageCollected<CustomLayoutEdges>(border_scrollbar_padding);
@@ -121,18 +134,20 @@ bool CSSLayoutDefinition::Instance::Layout(
v8::Local<v8::Value> v8_return_value = return_value.V8Value();
if (v8_return_value.IsEmpty() || !v8_return_value->IsPromise()) {
- execution_context->AddConsoleMessage(
- ConsoleMessage::Create(mojom::ConsoleMessageSource::kJavaScript,
- mojom::ConsoleMessageLevel::kInfo,
- "The layout function must be async or return a "
- "promise, falling back to block layout."));
+ execution_context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::ConsoleMessageSource::kJavaScript,
+ mojom::ConsoleMessageLevel::kInfo,
+ "The layout function must be async or return a "
+ "promise, falling back to block layout."));
return false;
}
// Run the work queue until exhaustion.
while (!custom_layout_scope->Queue()->IsEmpty()) {
- for (auto& task : *custom_layout_scope->Queue())
- task.Run(space, node.Style());
+ for (auto& task : *custom_layout_scope->Queue()) {
+ task.Run(space, node.Style(),
+ child_percentage_resolution_block_size_for_min_max);
+ }
custom_layout_scope->Queue()->clear();
{
v8::MicrotasksScope microtasks_scope(isolate, microtask_queue,
@@ -149,27 +164,28 @@ bool CSSLayoutDefinition::Instance::Layout(
v8::Local<v8::Promise>::Cast(v8_return_value);
if (v8_result_promise->State() != v8::Promise::kFulfilled) {
- execution_context->AddConsoleMessage(
- ConsoleMessage::Create(mojom::ConsoleMessageSource::kJavaScript,
- mojom::ConsoleMessageLevel::kInfo,
- "The layout function promise must resolve, "
- "falling back to block layout."));
+ execution_context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::ConsoleMessageSource::kJavaScript,
+ mojom::ConsoleMessageLevel::kInfo,
+ "The layout function promise must resolve, "
+ "falling back to block layout."));
return false;
}
v8::Local<v8::Value> inner_value = v8_result_promise->Result();
// Attempt to convert the result.
- V8FragmentResultOptions::ToImpl(isolate, inner_value, fragment_result_options,
- exception_state);
+ fragment_result_options =
+ NativeValueTraits<FragmentResultOptions>::NativeValue(
+ isolate, inner_value, exception_state);
if (exception_state.HadException()) {
V8ScriptRunner::ReportException(isolate, exception_state.GetException());
exception_state.ClearException();
- execution_context->AddConsoleMessage(
- ConsoleMessage::Create(mojom::ConsoleMessageSource::kJavaScript,
- mojom::ConsoleMessageLevel::kInfo,
- "Unable to parse the layout function "
- "result, falling back to block layout."));
+ execution_context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::ConsoleMessageSource::kJavaScript,
+ mojom::ConsoleMessageLevel::kInfo,
+ "Unable to parse the layout function "
+ "result, falling back to block layout."));
return false;
}
@@ -188,11 +204,114 @@ bool CSSLayoutDefinition::Instance::Layout(
if (exception_state.HadException()) {
V8ScriptRunner::ReportException(isolate, exception_state.GetException());
exception_state.ClearException();
- execution_context->AddConsoleMessage(
- ConsoleMessage::Create(mojom::ConsoleMessageSource::kJavaScript,
- mojom::ConsoleMessageLevel::kInfo,
- "Unable to serialize the data provided in the "
- "result, falling back to block layout."));
+ execution_context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::ConsoleMessageSource::kJavaScript,
+ mojom::ConsoleMessageLevel::kInfo,
+ "Unable to serialize the data provided in the "
+ "result, falling back to block layout."));
+ return false;
+ }
+
+ return true;
+}
+
+bool CSSLayoutDefinition::Instance::IntrinsicSizes(
+ const NGConstraintSpace& space,
+ const Document& document,
+ const NGBlockNode& node,
+ const LogicalSize& border_box_size,
+ const NGBoxStrut& border_scrollbar_padding,
+ const LayoutUnit child_percentage_resolution_block_size_for_min_max,
+ CustomLayoutScope* custom_layout_scope,
+ IntrinsicSizesResultOptions*& intrinsic_sizes_result_options) {
+ ScriptState* script_state = definition_->GetScriptState();
+ v8::Isolate* isolate = script_state->GetIsolate();
+
+ if (!script_state->ContextIsValid())
+ return false;
+
+ ScriptState::Scope scope(script_state);
+
+ HeapVector<Member<CustomLayoutChild>> children;
+ GatherChildren(node, custom_layout_scope, &children);
+
+ CustomLayoutEdges* edges =
+ MakeGarbageCollected<CustomLayoutEdges>(border_scrollbar_padding);
+
+ // TODO(ikilpatrick): Instead of creating a new style_map each time here,
+ // store on LayoutCustom, and update when the style changes.
+ StylePropertyMapReadOnly* style_map =
+ MakeGarbageCollected<PrepopulatedComputedStylePropertyMap>(
+ document, node.Style(), definition_->native_invalidation_properties_,
+ definition_->custom_invalidation_properties_);
+
+ ScriptValue return_value;
+ if (!definition_->intrinsic_sizes_
+ ->Invoke(instance_.NewLocal(isolate), children, edges, style_map)
+ .To(&return_value))
+ return false;
+
+ ExecutionContext* execution_context = ExecutionContext::From(script_state);
+ v8::MicrotaskQueue* microtask_queue = ToMicrotaskQueue(execution_context);
+ DCHECK(microtask_queue);
+
+ ExceptionState exception_state(isolate, ExceptionState::kExecutionContext,
+ "CSSLayoutAPI", "IntrinsicSizes");
+
+ v8::Local<v8::Value> v8_return_value = return_value.V8Value();
+ if (v8_return_value.IsEmpty() || !v8_return_value->IsPromise()) {
+ execution_context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::ConsoleMessageSource::kJavaScript,
+ mojom::ConsoleMessageLevel::kInfo,
+ "The intrinsicSizes function must be async or return a "
+ "promise, falling back to block layout."));
+ return false;
+ }
+
+ // Run the work queue until exhaustion.
+ while (!custom_layout_scope->Queue()->IsEmpty()) {
+ for (auto& task : *custom_layout_scope->Queue()) {
+ task.Run(space, node.Style(),
+ child_percentage_resolution_block_size_for_min_max);
+ }
+ custom_layout_scope->Queue()->clear();
+ {
+ v8::MicrotasksScope microtasks_scope(isolate, microtask_queue,
+ v8::MicrotasksScope::kRunMicrotasks);
+ }
+ }
+
+ if (exception_state.HadException()) {
+ ReportException(&exception_state);
+ return false;
+ }
+
+ v8::Local<v8::Promise> v8_result_promise =
+ v8::Local<v8::Promise>::Cast(v8_return_value);
+
+ if (v8_result_promise->State() != v8::Promise::kFulfilled) {
+ execution_context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::ConsoleMessageSource::kJavaScript,
+ mojom::ConsoleMessageLevel::kInfo,
+ "The intrinsicSizes function promise must resolve, "
+ "falling back to block layout."));
+ return false;
+ }
+ v8::Local<v8::Value> inner_value = v8_result_promise->Result();
+
+ // Attempt to convert the result.
+ intrinsic_sizes_result_options =
+ NativeValueTraits<IntrinsicSizesResultOptions>::NativeValue(
+ isolate, inner_value, exception_state);
+
+ if (exception_state.HadException()) {
+ V8ScriptRunner::ReportException(isolate, exception_state.GetException());
+ exception_state.ClearException();
+ execution_context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::ConsoleMessageSource::kJavaScript,
+ mojom::ConsoleMessageLevel::kInfo,
+ "Unable to parse the intrinsicSizes function "
+ "result, falling back to block layout."));
return false;
}
@@ -209,7 +328,7 @@ void CSSLayoutDefinition::Instance::ReportException(
// again (as the callbacks are invoked directly by the UA).
V8ScriptRunner::ReportException(isolate, exception_state->GetException());
exception_state->ClearException();
- execution_context->AddConsoleMessage(ConsoleMessage::Create(
+ execution_context->AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
mojom::ConsoleMessageSource::kJavaScript,
mojom::ConsoleMessageLevel::kInfo,
"The layout function failed, falling back to block layout."));
@@ -234,14 +353,14 @@ CSSLayoutDefinition::Instance* CSSLayoutDefinition::CreateInstance() {
return MakeGarbageCollected<Instance>(this, instance.V8Value());
}
-void CSSLayoutDefinition::Instance::Trace(blink::Visitor* visitor) {
+void CSSLayoutDefinition::Instance::Trace(Visitor* visitor) {
visitor->Trace(definition_);
visitor->Trace(instance_);
}
void CSSLayoutDefinition::Trace(Visitor* visitor) {
visitor->Trace(constructor_);
- visitor->Trace(unused_intrinsic_sizes_);
+ visitor->Trace(intrinsic_sizes_);
visitor->Trace(layout_);
visitor->Trace(script_state_);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.h
index b8690a9e84f..4c1ff77f733 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/css_layout_definition.h
@@ -17,13 +17,15 @@ namespace blink {
class CustomLayoutScope;
class FragmentResultOptions;
+class IntrinsicSizesResultOptions;
+class LayoutUnit;
struct LogicalSize;
class NGBlockNode;
struct NGBoxStrut;
class NGConstraintSpace;
class ScriptState;
class SerializedScriptValue;
-class V8Function;
+class V8IntrinsicSizesCallback;
class V8LayoutCallback;
class V8NoArgumentConstructor;
@@ -36,7 +38,7 @@ class CSSLayoutDefinition final : public GarbageCollected<CSSLayoutDefinition>,
CSSLayoutDefinition(
ScriptState*,
V8NoArgumentConstructor* constructor,
- V8Function* intrinsic_sizes,
+ V8IntrinsicSizesCallback* intrinsic_sizes,
V8LayoutCallback* layout,
const Vector<CSSPropertyID>& native_invalidation_properties,
const Vector<AtomicString>& custom_invalidation_properties,
@@ -53,16 +55,30 @@ class CSSLayoutDefinition final : public GarbageCollected<CSSLayoutDefinition>,
// Runs the web developer defined layout, returns true if everything
// succeeded. It populates the FragmentResultOptions dictionary, and
// fragment_result_data.
- bool Layout(const NGConstraintSpace&,
- const Document&,
- const NGBlockNode&,
- const LogicalSize& border_box_size,
- const NGBoxStrut& border_scrollbar_padding,
- CustomLayoutScope*,
- FragmentResultOptions*,
- scoped_refptr<SerializedScriptValue>* fragment_result_data);
-
- void Trace(blink::Visitor*);
+ bool Layout(
+ const NGConstraintSpace&,
+ const Document&,
+ const NGBlockNode&,
+ const LogicalSize& border_box_size,
+ const NGBoxStrut& border_scrollbar_padding,
+ const LayoutUnit child_percentage_resolution_block_size_for_min_max,
+ CustomLayoutScope*,
+ FragmentResultOptions*&,
+ scoped_refptr<SerializedScriptValue>* fragment_result_data);
+
+ // Runs the web developer defined intrinsicSizes, returns true if everything
+ // succeeded. It populates the IntrinsicSizesResultOptions dictionary.
+ bool IntrinsicSizes(
+ const NGConstraintSpace&,
+ const Document&,
+ const NGBlockNode&,
+ const LogicalSize& border_box_size,
+ const NGBoxStrut& border_scrollbar_padding,
+ const LayoutUnit child_percentage_resolution_block_size_for_min_max,
+ CustomLayoutScope*,
+ IntrinsicSizesResultOptions*&);
+
+ void Trace(Visitor*);
private:
void ReportException(ExceptionState*);
@@ -90,7 +106,7 @@ class CSSLayoutDefinition final : public GarbageCollected<CSSLayoutDefinition>,
ScriptState* GetScriptState() const { return script_state_; }
- virtual void Trace(blink::Visitor* visitor);
+ virtual void Trace(Visitor* visitor);
const char* NameInHeapSnapshot() const override {
return "CSSLayoutDefinition";
@@ -103,7 +119,7 @@ class CSSLayoutDefinition final : public GarbageCollected<CSSLayoutDefinition>,
// sizes function, and layout function alive. It participates in wrapper
// tracing as it holds onto V8 wrappers.
Member<V8NoArgumentConstructor> constructor_;
- Member<V8Function> unused_intrinsic_sizes_;
+ Member<V8IntrinsicSizesCallback> intrinsic_sizes_;
Member<V8LayoutCallback> layout_;
// If a constructor call ever fails, we'll refuse to create any more
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_intrinsic_sizes.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_intrinsic_sizes.cc
new file mode 100644
index 00000000000..7dd9c992f83
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_intrinsic_sizes.cc
@@ -0,0 +1,30 @@
+// Copyright 2019 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/ng/custom/custom_intrinsic_sizes.h"
+
+#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.h"
+
+namespace blink {
+
+CustomIntrinsicSizes::CustomIntrinsicSizes(CustomLayoutChild* child,
+ CustomLayoutToken* token,
+ double min_content_size,
+ double max_content_size)
+ : child_(child),
+ token_(token),
+ min_content_size_(min_content_size),
+ max_content_size_(max_content_size) {}
+
+const NGLayoutInputNode& CustomIntrinsicSizes::GetLayoutNode() const {
+ return child_->GetLayoutNode();
+}
+
+void CustomIntrinsicSizes::Trace(Visitor* visitor) {
+ visitor->Trace(child_);
+ visitor->Trace(token_);
+ ScriptWrappable::Trace(visitor);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_intrinsic_sizes.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_intrinsic_sizes.h
new file mode 100644
index 00000000000..1bfa9cea738
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_intrinsic_sizes.h
@@ -0,0 +1,53 @@
+// Copyright 2019 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_CUSTOM_CUSTOM_INTRINSIC_SIZES_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_CUSTOM_CUSTOM_INTRINSIC_SIZES_H_
+
+#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_scope.h"
+#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
+
+namespace blink {
+
+class NGLayoutInputNode;
+class CustomLayoutChild;
+
+// This represents the result of intrinsicSizes (on a LayoutChild).
+//
+// This should mirror the information in a MinMaxSize, and it has the
+// additional capability that it is exposed to web developers.
+class CustomIntrinsicSizes : public ScriptWrappable {
+ DEFINE_WRAPPERTYPEINFO();
+
+ public:
+ CustomIntrinsicSizes(CustomLayoutChild*,
+ CustomLayoutToken*,
+ double min_content_size,
+ double max_content_size);
+ ~CustomIntrinsicSizes() override = default;
+
+ CustomIntrinsicSizes(const CustomIntrinsicSizes&) = delete;
+ CustomIntrinsicSizes& operator=(const CustomIntrinsicSizes&) = delete;
+
+ double minContentSize() const { return min_content_size_; }
+ double maxContentSize() const { return max_content_size_; }
+
+ const NGLayoutInputNode& GetLayoutNode() const;
+
+ bool IsValid() const { return token_->IsValid(); }
+
+ void Trace(Visitor*) override;
+
+ private:
+ Member<CustomLayoutChild> child_;
+ Member<CustomLayoutToken> token_;
+
+ // The min and max content sizes on this object should never change.
+ const double min_content_size_;
+ const double max_content_size_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_CUSTOM_CUSTOM_INTRINSIC_SIZES_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.cc
index 043110aec8f..11a2762ad9d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.cc
@@ -11,9 +11,14 @@
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_scope.h"
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
namespace blink {
+namespace {
+const char kInvalidLayoutChild[] = "The LayoutChild is not valid.";
+} // namespace
+
CustomLayoutChild::CustomLayoutChild(const CSSLayoutDefinition& definition,
NGLayoutInputNode node)
: node_(node),
@@ -23,6 +28,24 @@ CustomLayoutChild::CustomLayoutChild(const CSSLayoutDefinition& definition,
definition.ChildNativeInvalidationProperties(),
definition.ChildCustomInvalidationProperties())) {}
+ScriptPromise CustomLayoutChild::intrinsicSizes(
+ ScriptState* script_state,
+ ExceptionState& exception_state) {
+ // A layout child may be invalid if it has been removed from the tree (it is
+ // possible for a web developer to hold onto a LayoutChild object after its
+ // underlying LayoutObject has been destroyed).
+ if (!node_ || !token_->IsValid()) {
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kInvalidLayoutChild);
+ return ScriptPromise();
+ }
+
+ auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
+ CustomLayoutScope::Current()->Queue()->emplace_back(
+ this, token_, resolver, CustomLayoutWorkTask::TaskType::kIntrinsicSizes);
+ return resolver->Promise();
+}
+
ScriptPromise CustomLayoutChild::layoutNextFragment(
ScriptState* script_state,
const CustomLayoutConstraintsOptions* options,
@@ -31,10 +54,9 @@ ScriptPromise CustomLayoutChild::layoutNextFragment(
// possible for a web developer to hold onto a LayoutChild object after its
// underlying LayoutObject has been destroyed).
if (!node_ || !token_->IsValid()) {
- return ScriptPromise::RejectWithDOMException(
- script_state,
- MakeGarbageCollected<DOMException>(DOMExceptionCode::kInvalidStateError,
- "The LayoutChild is not valid."));
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
+ kInvalidLayoutChild);
+ return ScriptPromise();
}
// Serialize the provided data if needed.
@@ -54,11 +76,12 @@ ScriptPromise CustomLayoutChild::layoutNextFragment(
auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state);
CustomLayoutScope::Current()->Queue()->emplace_back(
- this, token_, resolver, options, std::move(constraint_data));
+ this, token_, resolver, options, std::move(constraint_data),
+ CustomLayoutWorkTask::TaskType::kLayoutFragment);
return resolver->Promise();
}
-void CustomLayoutChild::Trace(blink::Visitor* visitor) {
+void CustomLayoutChild::Trace(Visitor* visitor) {
visitor->Trace(style_map_);
visitor->Trace(token_);
ScriptWrappable::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.h
index 5b7c1c435f3..7943adc0ac3 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.h
@@ -16,6 +16,7 @@ namespace blink {
class CSSLayoutDefinition;
class CustomLayoutConstraintsOptions;
class CustomLayoutToken;
+class ExceptionState;
// Represents a "CSS box" for use by a web developer. This is passed into the
// web developer defined layout and intrinsicSizes functions so that they can
@@ -32,6 +33,7 @@ class CustomLayoutChild : public ScriptWrappable {
// LayoutChild.idl
PrepopulatedComputedStylePropertyMap* styleMap() const { return style_map_; }
+ ScriptPromise intrinsicSizes(ScriptState*, ExceptionState&);
ScriptPromise layoutNextFragment(ScriptState*,
const CustomLayoutConstraintsOptions*,
ExceptionState&);
@@ -44,7 +46,7 @@ class CustomLayoutChild : public ScriptWrappable {
void SetCustomLayoutToken(CustomLayoutToken* token) { token_ = token; }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
NGLayoutInputNode node_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.cc
index ec4f27e6957..268d0e72343 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.cc
@@ -25,6 +25,13 @@ CustomLayoutConstraints::CustomLayoutConstraints(
CustomLayoutConstraints::~CustomLayoutConstraints() = default;
+base::Optional<double> CustomLayoutConstraints::fixedBlockSize() const {
+ // Check if we've been passed an indefinite block-size.
+ if (fixed_block_size_ < 0.0)
+ return base::nullopt;
+ return fixed_block_size_;
+}
+
double CustomLayoutConstraints::fixedBlockSize(bool& is_null) const {
// Check if we've been passed an indefinite block-size.
if (fixed_block_size_ < 0.0) {
@@ -50,7 +57,7 @@ ScriptValue CustomLayoutConstraints::data(ScriptState* script_state) const {
layout_worklet_world_v8_data_.NewLocal(script_state->GetIsolate()));
}
-void CustomLayoutConstraints::Trace(blink::Visitor* visitor) {
+void CustomLayoutConstraints::Trace(Visitor* visitor) {
visitor->Trace(layout_worklet_world_v8_data_);
ScriptWrappable::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.h
index 1c66b7c437f..42ce5a8fa06 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints.h
@@ -29,10 +29,12 @@ class CustomLayoutConstraints : public ScriptWrappable {
// LayoutConstraints.idl
double fixedInlineSize() const { return fixed_inline_size_; }
- double fixedBlockSize(bool& is_null) const;
+ base::Optional<double> fixedBlockSize() const;
+ // TODO(crbug.com/1060971): Remove |is_null| version.
+ double fixedBlockSize(bool& is_null) const; // DEPRECATED
ScriptValue data(ScriptState*) const;
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
double fixed_inline_size_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.cc
index 1019fd242bb..476d990a0b4 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.cc
@@ -15,12 +15,14 @@ CustomLayoutFragment::CustomLayoutFragment(
CustomLayoutToken* token,
scoped_refptr<const NGLayoutResult> layout_result,
const LogicalSize& size,
+ const base::Optional<LayoutUnit> baseline,
v8::Isolate* isolate)
: child_(child),
token_(token),
layout_result_(std::move(layout_result)),
inline_size_(size.inline_size.ToDouble()),
- block_size_(size.block_size.ToDouble()) {
+ block_size_(size.block_size.ToDouble()),
+ baseline_(baseline) {
// Immediately store the result data, so that it remains immutable between
// layout calls to the child.
if (SerializedScriptValue* data = layout_result_->CustomLayoutData())
@@ -36,6 +38,11 @@ const NGLayoutInputNode& CustomLayoutFragment::GetLayoutNode() const {
return child_->GetLayoutNode();
}
+double CustomLayoutFragment::baseline(bool& is_null) const {
+ is_null = !baseline_.has_value();
+ return baseline_.value_or(0.0);
+}
+
ScriptValue CustomLayoutFragment::data(ScriptState* script_state) const {
// "data" is *only* exposed to the LayoutWorkletGlobalScope, and we are able
// to return the same deserialized object. We don't need to check which world
@@ -51,7 +58,7 @@ ScriptValue CustomLayoutFragment::data(ScriptState* script_state) const {
layout_worklet_world_v8_data_.NewLocal(script_state->GetIsolate()));
}
-void CustomLayoutFragment::Trace(blink::Visitor* visitor) {
+void CustomLayoutFragment::Trace(Visitor* visitor) {
visitor->Trace(child_);
visitor->Trace(token_);
visitor->Trace(layout_worklet_world_v8_data_);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h
index bc9cb8ee03e..29adc05f5a9 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h
@@ -39,6 +39,7 @@ class CustomLayoutFragment : public ScriptWrappable {
CustomLayoutToken*,
scoped_refptr<const NGLayoutResult>,
const LogicalSize& size,
+ const base::Optional<LayoutUnit> baseline,
v8::Isolate*);
~CustomLayoutFragment() override = default;
@@ -51,6 +52,10 @@ class CustomLayoutFragment : public ScriptWrappable {
void setInlineOffset(double inline_offset) { inline_offset_ = inline_offset; }
void setBlockOffset(double block_offset) { block_offset_ = block_offset; }
+ base::Optional<double> baseline() const { return baseline_; }
+ // TODO(crbug.com/1060971): Remove |is_null| version.
+ double baseline(bool& is_null) const; // DEPRECATED
+
ScriptValue data(ScriptState*) const;
const NGLayoutResult& GetLayoutResult() const;
@@ -58,7 +63,7 @@ class CustomLayoutFragment : public ScriptWrappable {
bool IsValid() const { return token_->IsValid(); }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
Member<CustomLayoutChild> child_;
@@ -88,6 +93,9 @@ class CustomLayoutFragment : public ScriptWrappable {
double inline_offset_ = 0;
double block_offset_ = 0;
+ // The first-line baseline.
+ const base::Optional<double> baseline_;
+
TraceWrapperV8Reference<v8::Value> layout_worklet_world_v8_data_;
DISALLOW_COPY_AND_ASSIGN(CustomLayoutFragment);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_scope.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_scope.h
index 319ea6b778b..3cc70061f06 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_scope.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_scope.h
@@ -64,7 +64,7 @@ class CustomLayoutScope {
CustomLayoutScope* prev_scope_;
CustomLayoutWorkQueue queue_;
- Member<CustomLayoutToken> token_;
+ CustomLayoutToken* token_;
};
inline bool CustomLayoutToken::IsValid() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.cc
index b23852b8139..3e9dc834b29 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.cc
@@ -5,37 +5,68 @@
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
+#include "third_party/blink/renderer/core/layout/ng/custom/custom_intrinsic_sizes.h"
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_child.h"
-#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints_options.h"
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
namespace blink {
+CustomLayoutWorkTask::CustomLayoutWorkTask(CustomLayoutChild* child,
+ CustomLayoutToken* token,
+ ScriptPromiseResolver* resolver,
+ const TaskType type)
+ : CustomLayoutWorkTask(child, token, resolver, nullptr, nullptr, type) {}
+
CustomLayoutWorkTask::CustomLayoutWorkTask(
CustomLayoutChild* child,
CustomLayoutToken* token,
ScriptPromiseResolver* resolver,
const CustomLayoutConstraintsOptions* options,
- scoped_refptr<SerializedScriptValue> constraint_data)
+ scoped_refptr<SerializedScriptValue> constraint_data,
+ const TaskType type)
: child_(child),
token_(token),
resolver_(resolver),
options_(options),
- constraint_data_(std::move(constraint_data)) {}
+ constraint_data_(std::move(constraint_data)),
+ type_(type) {}
CustomLayoutWorkTask::~CustomLayoutWorkTask() = default;
-void CustomLayoutWorkTask::Run(const NGConstraintSpace& parent_space,
- const ComputedStyle& parent_style) {
+void CustomLayoutWorkTask::Run(
+ const NGConstraintSpace& parent_space,
+ const ComputedStyle& parent_style,
+ const LayoutUnit child_percentage_resolution_block_size_for_min_max) {
DCHECK(token_->IsValid());
- NGLayoutInputNode node = child_->GetLayoutNode();
- NGConstraintSpaceBuilder builder(parent_space, node.Style().GetWritingMode(),
+ NGLayoutInputNode child = child_->GetLayoutNode();
+
+ if (type_ == CustomLayoutWorkTask::TaskType::kIntrinsicSizes) {
+ RunIntrinsicSizesTask(parent_style,
+ child_percentage_resolution_block_size_for_min_max,
+ child);
+ } else {
+ DCHECK_EQ(type_, CustomLayoutWorkTask::TaskType::kLayoutFragment);
+ RunLayoutFragmentTask(parent_space, parent_style, child);
+ }
+}
+
+void CustomLayoutWorkTask::RunLayoutFragmentTask(
+ const NGConstraintSpace& parent_space,
+ const ComputedStyle& parent_style,
+ NGLayoutInputNode child) {
+ DCHECK_EQ(type_, CustomLayoutWorkTask::TaskType::kLayoutFragment);
+ DCHECK(options_ && resolver_);
+
+ NGConstraintSpaceBuilder builder(parent_space, child.Style().GetWritingMode(),
/* is_new_fc */ true);
- SetOrthogonalFallbackInlineSizeIfNeeded(parent_style, node, &builder);
+ SetOrthogonalFallbackInlineSizeIfNeeded(parent_style, child, &builder);
bool is_fixed_inline_size = false;
bool is_fixed_block_size = false;
@@ -88,24 +119,40 @@ void CustomLayoutWorkTask::Run(const NGConstraintSpace& parent_space,
percentage_size.block_size = kIndefiniteSize;
}
- builder.SetTextDirection(node.Style().Direction());
+ builder.SetTextDirection(child.Style().Direction());
builder.SetAvailableSize(available_size);
builder.SetPercentageResolutionSize(percentage_size);
builder.SetReplacedPercentageResolutionSize(percentage_size);
- builder.SetIsShrinkToFit(node.Style().LogicalWidth().IsAuto());
+ builder.SetIsShrinkToFit(child.Style().LogicalWidth().IsAuto());
builder.SetIsFixedInlineSize(is_fixed_inline_size);
builder.SetIsFixedBlockSize(is_fixed_block_size);
- if (node.IsLayoutNGCustom())
+ builder.SetNeedsBaseline(true);
+ if (child.IsLayoutNGCustom())
builder.SetCustomLayoutData(std::move(constraint_data_));
auto space = builder.ToConstraintSpace();
- auto result = To<NGBlockNode>(node).Layout(space, nullptr /* break_token */);
+ auto result = To<NGBlockNode>(child).Layout(space, nullptr /* break_token */);
- LogicalSize size = result->PhysicalFragment().Size().ConvertToLogical(
- parent_space.GetWritingMode());
+ NGBoxFragment fragment(parent_space.GetWritingMode(),
+ parent_space.Direction(),
+ To<NGPhysicalBoxFragment>(result->PhysicalFragment()));
resolver_->Resolve(MakeGarbageCollected<CustomLayoutFragment>(
- child_, token_, std::move(result), size,
+ child_, token_, std::move(result), fragment.Size(), fragment.Baseline(),
resolver_->GetScriptState()->GetIsolate()));
}
+void CustomLayoutWorkTask::RunIntrinsicSizesTask(
+ const ComputedStyle& parent_style,
+ const LayoutUnit child_percentage_resolution_block_size_for_min_max,
+ NGLayoutInputNode child) {
+ DCHECK_EQ(type_, CustomLayoutWorkTask::TaskType::kIntrinsicSizes);
+ DCHECK(resolver_);
+
+ MinMaxSizesInput input(child_percentage_resolution_block_size_for_min_max);
+ MinMaxSizes sizes =
+ ComputeMinAndMaxContentContribution(parent_style, child, input);
+ resolver_->Resolve(MakeGarbageCollected<CustomIntrinsicSizes>(
+ child_, token_, sizes.min_size, sizes.max_size));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.h
index 5038048ed31..7aacc7fce5c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/custom_layout_work_task.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_CUSTOM_CUSTOM_LAYOUT_WORK_TASK_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_CUSTOM_CUSTOM_LAYOUT_WORK_TASK_H_
-#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_constraints_options.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_custom_layout_constraints_options.h"
#include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
@@ -14,7 +14,9 @@ namespace blink {
class ComputedStyle;
class CustomLayoutChild;
class CustomLayoutToken;
+class LayoutUnit;
class NGConstraintSpace;
+class NGLayoutInputNode;
class SerializedScriptValue;
class ScriptPromiseResolver;
@@ -22,16 +24,30 @@ class ScriptPromiseResolver;
// intrinsic-sizes.
class CustomLayoutWorkTask {
public:
+ enum TaskType {
+ kLayoutFragment,
+ kIntrinsicSizes,
+ };
+
+ // Used when resolving a promise with intrinsic-sizes.
+ CustomLayoutWorkTask(CustomLayoutChild*,
+ CustomLayoutToken*,
+ ScriptPromiseResolver*,
+ const TaskType type);
+
+ // Used when resolving a promise with a fragment.
CustomLayoutWorkTask(CustomLayoutChild*,
CustomLayoutToken*,
ScriptPromiseResolver*,
const CustomLayoutConstraintsOptions*,
- scoped_refptr<SerializedScriptValue> constraint_data);
+ scoped_refptr<SerializedScriptValue> constraint_data,
+ const TaskType type);
~CustomLayoutWorkTask();
// Runs this work task.
void Run(const NGConstraintSpace& parent_space,
- const ComputedStyle& parent_style);
+ const ComputedStyle& parent_style,
+ const LayoutUnit child_percentage_resolution_block_size_for_min_max);
private:
Persistent<CustomLayoutChild> child_;
@@ -39,6 +55,15 @@ class CustomLayoutWorkTask {
Persistent<ScriptPromiseResolver> resolver_;
Persistent<const CustomLayoutConstraintsOptions> options_;
scoped_refptr<SerializedScriptValue> constraint_data_;
+ TaskType type_;
+
+ void RunLayoutFragmentTask(const NGConstraintSpace& parent_space,
+ const ComputedStyle& parent_style,
+ NGLayoutInputNode child);
+ void RunIntrinsicSizesTask(
+ const ComputedStyle& parent_style,
+ const LayoutUnit child_percentage_resolution_block_size_for_min_max,
+ NGLayoutInputNode child);
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/document_layout_definition.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/document_layout_definition.cc
index 3d60b887d1c..c68765b9107 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/document_layout_definition.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/document_layout_definition.cc
@@ -33,7 +33,7 @@ bool DocumentLayoutDefinition::IsEqual(const CSSLayoutDefinition& other) {
other.ChildCustomInvalidationProperties();
}
-void DocumentLayoutDefinition::Trace(blink::Visitor* visitor) {
+void DocumentLayoutDefinition::Trace(Visitor* visitor) {
visitor->Trace(layout_definition_);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/document_layout_definition.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/document_layout_definition.h
index 2a8e359b1cf..0c2d8bce246 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/document_layout_definition.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/document_layout_definition.h
@@ -37,7 +37,7 @@ class DocumentLayoutDefinition final
return registered_definitions_count_;
}
- virtual void Trace(blink::Visitor*);
+ virtual void Trace(Visitor*);
private:
bool IsEqual(const CSSLayoutDefinition&);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/fragment_result_options.idl b/chromium/third_party/blink/renderer/core/layout/ng/custom/fragment_result_options.idl
index 376cc5be01c..28867d89dc6 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/fragment_result_options.idl
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/fragment_result_options.idl
@@ -6,6 +6,7 @@
dictionary FragmentResultOptions {
double autoBlockSize = 0;
+ double baseline;
sequence<LayoutFragment> childFragments = [];
any data = null;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/intrinsic_sizes.idl b/chromium/third_party/blink/renderer/core/layout/ng/custom/intrinsic_sizes.idl
new file mode 100644
index 00000000000..5864a0720a0
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/intrinsic_sizes.idl
@@ -0,0 +1,15 @@
+// Copyright 2019 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.
+
+// https://drafts.css-houdini.org/css-layout-api/#intrinsicsizes
+
+[
+ Exposed=LayoutWorklet,
+ ImplementedAs=CustomIntrinsicSizes,
+ RuntimeEnabled=CSSLayoutAPI
+]
+interface IntrinsicSizes {
+ readonly attribute double minContentSize;
+ readonly attribute double maxContentSize;
+};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/intrinsic_sizes_result_options.idl b/chromium/third_party/blink/renderer/core/layout/ng/custom/intrinsic_sizes_result_options.idl
new file mode 100644
index 00000000000..aa3ae7d453b
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/intrinsic_sizes_result_options.idl
@@ -0,0 +1,10 @@
+// Copyright 2019 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.
+
+// https://drafts.css-houdini.org/css-layout-api/#dictdef-intrinsicsizesresultoptions
+
+dictionary IntrinsicSizesResultOptions {
+ double minContentSize = 0;
+ double maxContentSize = 0;
+};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_child.idl b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_child.idl
index 3940849802c..76ba3c49d42 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_child.idl
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_child.idl
@@ -12,7 +12,7 @@
interface LayoutChild {
readonly attribute StylePropertyMapReadOnly styleMap;
- // IntrinsicSizesRequest intrinsicSizes();
- [CallWith=ScriptState, RaisesException] Promise<LayoutFragment> layoutNextFragment(optional CustomLayoutConstraintsOptions options);
+ [CallWith=ScriptState, RaisesException] Promise<IntrinsicSizes> intrinsicSizes();
+ [CallWith=ScriptState, RaisesException] Promise<LayoutFragment> layoutNextFragment(optional CustomLayoutConstraintsOptions options = {});
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_fragment.idl b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_fragment.idl
index e142bcd24b3..110744df579 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_fragment.idl
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_fragment.idl
@@ -16,5 +16,7 @@ interface LayoutFragment {
attribute double inlineOffset;
attribute double blockOffset;
+ readonly attribute double? baseline;
+
[CallWith=ScriptState] readonly attribute any data;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.cc
index 254c5354891..b49d3c51ad4 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.cc
@@ -15,6 +15,27 @@ LayoutNGCustom::LayoutNGCustom(Element* element)
DCHECK(element);
}
+void LayoutNGCustom::AddChild(LayoutObject* new_child,
+ LayoutObject* before_child) {
+ // Only use the block-flow AddChild logic when we are unloaded, i.e. we
+ // should behave exactly like a block-flow.
+ if (state_ == kUnloaded) {
+ LayoutNGBlockFlow::AddChild(new_child, before_child);
+ return;
+ }
+ LayoutBlock::AddChild(new_child, before_child);
+}
+
+void LayoutNGCustom::RemoveChild(LayoutObject* child) {
+ // Only use the block-flow RemoveChild logic when we are unloaded, i.e. we
+ // should behave exactly like a block-flow.
+ if (state_ == kUnloaded) {
+ LayoutNGBlockFlow::RemoveChild(child);
+ return;
+ }
+ LayoutBlock::RemoveChild(child);
+}
+
void LayoutNGCustom::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) {
if (state_ == kUnloaded) {
@@ -35,6 +56,11 @@ void LayoutNGCustom::StyleDidChange(StyleDifference diff,
}
}
+ // Make our children "block-level" before invoking StyleDidChange. As the
+ // current multi-col logic may invoke a call to AddChild, failing a DCHECK.
+ if (state_ != kUnloaded)
+ SetChildrenInline(false);
+
// TODO(ikilpatrick): Investigate reducing the properties which
// LayoutNGBlockFlow::StyleDidChange invalidates upon. (For example margins).
LayoutNGBlockFlow::StyleDidChange(diff, old_style);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.h
index 3b80651d205..95f0f3d0dae 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.h
@@ -30,6 +30,9 @@ class LayoutNGCustom final : public LayoutNGBlockFlow {
bool IsLoaded() { return state_ != kUnloaded; }
+ void AddChild(LayoutObject* new_child, LayoutObject* before_child) override;
+ void RemoveChild(LayoutObject* child) override;
+
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
private:
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.cc
index 6986d303d97..71e6bb85888 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.cc
@@ -45,7 +45,7 @@ LayoutWorkletGlobalScopeProxy* LayoutWorklet::Proxy() {
return LayoutWorkletGlobalScopeProxy::From(FindAvailableGlobalScope());
}
-void LayoutWorklet::Trace(blink::Visitor* visitor) {
+void LayoutWorklet::Trace(Visitor* visitor) {
visitor->Trace(document_definition_map_);
visitor->Trace(pending_layout_registry_);
Worklet::Trace(visitor);
@@ -59,8 +59,9 @@ bool LayoutWorklet::NeedsToCreateGlobalScope() {
WorkletGlobalScopeProxy* LayoutWorklet::CreateGlobalScope() {
DCHECK(NeedsToCreateGlobalScope());
return MakeGarbageCollected<LayoutWorkletGlobalScopeProxy>(
- To<Document>(GetExecutionContext())->GetFrame(), ModuleResponsesMap(),
- pending_layout_registry_, GetNumberOfGlobalScopes() + 1);
+ To<LocalDOMWindow>(GetExecutionContext())->GetFrame(),
+ ModuleResponsesMap(), pending_layout_registry_,
+ GetNumberOfGlobalScopes() + 1);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h
index 3c433e4920b..19d91dd9a97 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h"
#include "third_party/blink/renderer/core/workers/worklet.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/supplementable.h"
namespace blink {
@@ -46,7 +47,7 @@ class CORE_EXPORT LayoutWorklet : public Worklet,
void AddPendingLayout(const AtomicString& name, Node*);
LayoutWorkletGlobalScopeProxy* Proxy();
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
protected:
// TODO(ikilpatrick): Make selection of the global scope non-deterministic.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.cc
index a953e2ef0e8..77870594359 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_function.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_intrinsic_sizes_callback.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_layout_callback.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_no_argument_constructor.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_object_parser.h"
@@ -36,12 +37,12 @@ LayoutWorkletGlobalScope* LayoutWorkletGlobalScope::Create(
auto* isolate = ToIsolate(frame);
auto microtask_queue =
v8::MicrotaskQueue::New(isolate, v8::MicrotasksPolicy::kScoped);
- auto* agent = Agent::CreateForWorkerOrWorklet(
- isolate,
- creation_params->agent_cluster_id.is_empty()
- ? base::UnguessableToken::Create()
- : creation_params->agent_cluster_id,
- std::move(microtask_queue));
+ auto* agent =
+ MakeGarbageCollected<Agent>(isolate,
+ creation_params->agent_cluster_id.is_empty()
+ ? base::UnguessableToken::Create()
+ : creation_params->agent_cluster_id,
+ std::move(microtask_queue));
auto* global_scope = MakeGarbageCollected<LayoutWorkletGlobalScope>(
frame, std::move(creation_params), reporting_proxy,
pending_layout_registry, agent);
@@ -103,7 +104,8 @@ void LayoutWorkletGlobalScope::registerLayout(
Vector<AtomicString> custom_invalidation_properties;
if (!V8ObjectParser::ParseCSSPropertyList(
- current_context, layout_ctor->CallbackObject(), "inputProperties",
+ current_context, GetFrame()->DomWindow(),
+ layout_ctor->CallbackObject(), "inputProperties",
&native_invalidation_properties, &custom_invalidation_properties,
&exception_state))
return;
@@ -112,8 +114,9 @@ void LayoutWorkletGlobalScope::registerLayout(
Vector<AtomicString> child_custom_invalidation_properties;
if (!V8ObjectParser::ParseCSSPropertyList(
- current_context, layout_ctor->CallbackObject(),
- "childInputProperties", &child_native_invalidation_properties,
+ current_context, GetFrame()->DomWindow(),
+ layout_ctor->CallbackObject(), "childInputProperties",
+ &child_native_invalidation_properties,
&child_custom_invalidation_properties, &exception_state))
return;
@@ -126,7 +129,8 @@ void LayoutWorkletGlobalScope::registerLayout(
retriever.GetMethodOrThrow("intrinsicSizes", exception_state);
if (exception_state.HadException())
return;
- V8Function* intrinsic_sizes = V8Function::Create(v8_intrinsic_sizes);
+ V8IntrinsicSizesCallback* intrinsic_sizes =
+ V8IntrinsicSizesCallback::Create(v8_intrinsic_sizes);
v8::Local<v8::Function> v8_layout =
retriever.GetMethodOrThrow("layout", exception_state);
@@ -141,8 +145,7 @@ void LayoutWorkletGlobalScope::registerLayout(
child_custom_invalidation_properties);
layout_definitions_.Set(name, definition);
- LayoutWorklet* layout_worklet =
- LayoutWorklet::From(*GetFrame()->GetDocument()->domWindow());
+ LayoutWorklet* layout_worklet = LayoutWorklet::From(*GetFrame()->DomWindow());
LayoutWorklet::DocumentDefinitionMap* document_definition_map =
layout_worklet->GetDocumentDefinitionMap();
if (document_definition_map->Contains(name)) {
@@ -177,7 +180,7 @@ CSSLayoutDefinition* LayoutWorkletGlobalScope::FindDefinition(
return layout_definitions_.at(name);
}
-void LayoutWorkletGlobalScope::Trace(blink::Visitor* visitor) {
+void LayoutWorkletGlobalScope::Trace(Visitor* visitor) {
visitor->Trace(layout_definitions_);
visitor->Trace(pending_layout_registry_);
WorkletGlobalScope::Trace(visitor);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.h
index 642e9af4527..d920e67f8d3 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.h
@@ -45,7 +45,7 @@ class CORE_EXPORT LayoutWorkletGlobalScope final : public WorkletGlobalScope {
CSSLayoutDefinition* FindDefinition(const AtomicString& name);
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
// https://drafts.css-houdini.org/css-layout-api/#layout-definitions
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.idl b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.idl
index 5ce4982e351..63a233f5461 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.idl
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope.idl
@@ -15,3 +15,7 @@
// Blink-specific type for layout function
// https://drafts.css-houdini.org/css-layout-api/#layout-definition-layout-function
callback LayoutCallback = any (sequence<LayoutChild> children, LayoutEdges edges, LayoutConstraints constraints, StylePropertyMapReadOnly styleMap);
+
+// Blink-specific type for intrinsicSizes function
+// https://drafts.css-houdini.org/css-layout-api/#layout-definition-intrinsic-sizes-function
+callback IntrinsicSizesCallback = any (sequence<LayoutChild> children, LayoutEdges edges, StylePropertyMapReadOnly styleMap);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc
index 781452633d4..b71ceac3b78 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/loader/worker_fetch_context.h"
@@ -40,15 +41,16 @@ LayoutWorkletGlobalScopeProxy::LayoutWorkletGlobalScopeProxy(
StringView("LayoutWorklet #") + String::Number(global_scope_number);
auto creation_params = std::make_unique<GlobalScopeCreationParams>(
- document->Url(), mojom::ScriptType::kModule,
- OffMainThreadWorkerScriptFetchOption::kEnabled, global_scope_name,
- document->UserAgent(), frame->Client()->CreateWorkerFetchContext(),
+ document->Url(), mojom::blink::ScriptType::kModule, global_scope_name,
+ document->UserAgent(), frame->Client()->UserAgentMetadata(),
+ frame->Client()->CreateWorkerFetchContext(),
document->GetContentSecurityPolicy()->Headers(),
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
document->IsSecureContext(), document->GetHttpsState(),
nullptr /* worker_clients */,
frame->Client()->CreateWorkerContentSettingsClient(),
- document->AddressSpace(), OriginTrialContext::GetTokens(document).get(),
+ document->GetSecurityContext().AddressSpace(),
+ OriginTrialContext::GetTokens(frame->DomWindow()).get(),
base::UnguessableToken::Create(), nullptr /* worker_settings */,
kV8CacheOptionsDefault, module_responses_map,
mojo::NullRemote() /* browser_interface_broker */,
@@ -92,7 +94,7 @@ CSSLayoutDefinition* LayoutWorkletGlobalScopeProxy::FindDefinition(
return global_scope_->FindDefinition(name);
}
-void LayoutWorkletGlobalScopeProxy::Trace(blink::Visitor* visitor) {
+void LayoutWorkletGlobalScopeProxy::Trace(Visitor* visitor) {
visitor->Trace(global_scope_);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.h
index 46837b1ea3a..de993758af3 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.h
@@ -46,7 +46,7 @@ class CORE_EXPORT LayoutWorkletGlobalScopeProxy
LayoutWorkletGlobalScope* global_scope() const { return global_scope_.Get(); }
- void Trace(blink::Visitor*) override;
+ void Trace(Visitor*) override;
private:
std::unique_ptr<MainThreadWorkletReportingProxy> reporting_proxy_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.cc
index 2e7297a2fd7..c763349959b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.cc
@@ -5,11 +5,12 @@
#include "third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.h"
#include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_fragment_result_options.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_intrinsic_sizes_result_options.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/custom/custom_layout_scope.h"
-#include "third_party/blink/renderer/core/layout/ng/custom/fragment_result_options.h"
#include "third_party/blink/renderer/core/layout/ng/custom/layout_worklet.h"
#include "third_party/blink/renderer/core/layout/ng/custom/layout_worklet_global_scope_proxy.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h"
@@ -30,13 +31,55 @@ NGCustomLayoutAlgorithm::NGCustomLayoutAlgorithm(
container_builder_.SetIsNewFormattingContext(
params.space.IsNewFormattingContext());
container_builder_.SetInitialFragmentGeometry(params.fragment_geometry);
+ const NGConstraintSpace& space = ConstraintSpace();
+ child_percentage_resolution_block_size_for_min_max_ =
+ CalculateChildPercentageBlockSizeForMinMax(
+ space, Node(), border_padding_,
+ space.PercentageResolutionBlockSize());
}
-base::Optional<MinMaxSize> NGCustomLayoutAlgorithm::ComputeMinMaxSize(
- const MinMaxSizeInput& input) const {
- // TODO(ikilpatrick): Invoke the web-developer defined "intrinsicSizes"
- // method.
- return FallbackMinMaxSize(input);
+base::Optional<MinMaxSizes> NGCustomLayoutAlgorithm::ComputeMinMaxSizes(
+ const MinMaxSizesInput& input) const {
+ if (!Node().IsCustomLayoutLoaded())
+ return FallbackMinMaxSizes(input);
+
+ ScriptForbiddenScope::AllowUserAgentScript allow_script;
+ CustomLayoutScope scope;
+
+ const AtomicString& name = Style().DisplayLayoutCustomName();
+ const Document& document = Node().GetDocument();
+ LayoutWorklet* worklet = LayoutWorklet::From(*document.domWindow());
+ CSSLayoutDefinition* definition = worklet->Proxy()->FindDefinition(name);
+
+ // TODO(ikilpatrick): Cache the instance of the layout class.
+ CSSLayoutDefinition::Instance* instance = definition->CreateInstance();
+
+ if (!instance) {
+ // TODO(ikilpatrick): Report this error to the developer.
+ return FallbackMinMaxSizes(input);
+ }
+
+ IntrinsicSizesResultOptions* intrinsic_sizes_result_options = nullptr;
+ if (!instance->IntrinsicSizes(
+ ConstraintSpace(), document, Node(),
+ container_builder_.InitialBorderBoxSize(), border_scrollbar_padding_,
+ child_percentage_resolution_block_size_for_min_max_, &scope,
+ intrinsic_sizes_result_options)) {
+ // TODO(ikilpatrick): Report this error to the developer.
+ return FallbackMinMaxSizes(input);
+ }
+
+ MinMaxSizes sizes;
+ sizes.max_size = LayoutUnit::FromDoubleRound(
+ intrinsic_sizes_result_options->maxContentSize());
+ sizes.min_size = std::min(
+ sizes.max_size, LayoutUnit::FromDoubleRound(
+ intrinsic_sizes_result_options->minContentSize()));
+
+ sizes.min_size.ClampNegativeToZero();
+ sizes.max_size.ClampNegativeToZero();
+
+ return sizes;
}
scoped_refptr<const NGLayoutResult> NGCustomLayoutAlgorithm::Layout() {
@@ -61,13 +104,13 @@ scoped_refptr<const NGLayoutResult> NGCustomLayoutAlgorithm::Layout() {
return FallbackLayout();
}
- FragmentResultOptions* fragment_result_options =
- FragmentResultOptions::Create();
+ FragmentResultOptions* fragment_result_options = nullptr;
scoped_refptr<SerializedScriptValue> fragment_result_data;
- if (!instance->Layout(ConstraintSpace(), document, Node(),
- container_builder_.InitialBorderBoxSize(),
- border_scrollbar_padding_, &scope,
- fragment_result_options, &fragment_result_data)) {
+ if (!instance->Layout(
+ ConstraintSpace(), document, Node(),
+ container_builder_.InitialBorderBoxSize(), border_scrollbar_padding_,
+ child_percentage_resolution_block_size_for_min_max_, &scope,
+ fragment_result_options, &fragment_result_data)) {
// TODO(ikilpatrick): Report this error to the developer.
return FallbackLayout();
}
@@ -123,6 +166,12 @@ scoped_refptr<const NGLayoutResult> NGCustomLayoutAlgorithm::Layout() {
LayoutUnit block_size = ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), border_padding_, auto_block_size);
+ if (fragment_result_options->hasBaseline()) {
+ LayoutUnit baseline =
+ LayoutUnit::FromDoubleRound(fragment_result_options->baseline());
+ container_builder_.SetBaseline(baseline);
+ }
+
container_builder_.SetCustomLayoutData(std::move(fragment_result_data));
container_builder_.SetIntrinsicBlockSize(auto_block_size);
container_builder_.SetBlockSize(block_size);
@@ -151,10 +200,10 @@ void NGCustomLayoutAlgorithm::AddAnyOutOfFlowPositionedChildren(
}
}
-base::Optional<MinMaxSize> NGCustomLayoutAlgorithm::FallbackMinMaxSize(
- const MinMaxSizeInput& input) const {
+base::Optional<MinMaxSizes> NGCustomLayoutAlgorithm::FallbackMinMaxSizes(
+ const MinMaxSizesInput& input) const {
NGBlockLayoutAlgorithm algorithm(params_);
- return algorithm.ComputeMinMaxSize(input);
+ return algorithm.ComputeMinMaxSizes(input);
}
scoped_refptr<const NGLayoutResult> NGCustomLayoutAlgorithm::FallbackLayout() {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.h
index 7725387252a..5a43340b4a0 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.h
@@ -20,18 +20,20 @@ class CORE_EXPORT NGCustomLayoutAlgorithm
public:
NGCustomLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
- base::Optional<MinMaxSize> ComputeMinMaxSize(
- const MinMaxSizeInput&) const override;
+ base::Optional<MinMaxSizes> ComputeMinMaxSizes(
+ const MinMaxSizesInput&) const override;
scoped_refptr<const NGLayoutResult> Layout() override;
private:
void AddAnyOutOfFlowPositionedChildren(NGLayoutInputNode* child);
- base::Optional<MinMaxSize> FallbackMinMaxSize(const MinMaxSizeInput&) const;
+ base::Optional<MinMaxSizes> FallbackMinMaxSizes(
+ const MinMaxSizesInput&) const;
scoped_refptr<const NGLayoutResult> FallbackLayout();
const NGLayoutAlgorithmParams& params_;
const NGBoxStrut border_padding_;
const NGBoxStrut border_scrollbar_padding_;
+ LayoutUnit child_percentage_resolution_block_size_for_min_max_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.cc b/chromium/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.cc
index 4239b4da920..644f324ac9c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.cc
@@ -42,7 +42,7 @@ void PendingLayoutRegistry::AddPendingLayout(const AtomicString& name,
set->insert(node);
}
-void PendingLayoutRegistry::Trace(blink::Visitor* visitor) {
+void PendingLayoutRegistry::Trace(Visitor* visitor) {
visitor->Trace(pending_layouts_);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h b/chromium/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h
index ba74e988d1b..8afe379befd 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/custom/pending_layout_registry.h
@@ -23,7 +23,7 @@ class PendingLayoutRegistry : public GarbageCollected<PendingLayoutRegistry> {
void NotifyLayoutReady(const AtomicString& name);
void AddPendingLayout(const AtomicString& name, Node*);
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
private:
// This is a map of Nodes which are waiting for a CSSLayoutDefinition to be
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.cc b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.cc
index 0672d751fc4..250278fdfba 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.cc
@@ -96,17 +96,6 @@ bool NGLayoutOpportunity::IsBlockDeltaBelowShapes(
return true;
}
-NGLineLayoutOpportunity NGLayoutOpportunity::ComputeLineLayoutOpportunity(
- const NGConstraintSpace& space,
- LayoutUnit line_block_size,
- LayoutUnit block_delta) const {
- return NGLineLayoutOpportunity(
- ComputeLineLeftOffset(space, line_block_size, block_delta),
- ComputeLineRightOffset(space, line_block_size, block_delta),
- rect.LineStartOffset(), rect.LineEndOffset(),
- rect.BlockStartOffset() + block_delta, line_block_size);
-}
-
LayoutUnit NGLayoutOpportunity::ComputeLineLeftOffset(
const NGConstraintSpace& space,
LayoutUnit line_block_size,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h
index abf46f88fff..58734340c0b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h
@@ -47,9 +47,15 @@ struct CORE_EXPORT NGLayoutOpportunity {
// Calculates a line layout opportunity which takes into account any shapes
// which may affect the available inline size for the line breaker.
NGLineLayoutOpportunity ComputeLineLayoutOpportunity(
- const NGConstraintSpace&,
+ const NGConstraintSpace& space,
LayoutUnit line_block_size,
- LayoutUnit block_delta) const;
+ LayoutUnit block_delta) const {
+ return NGLineLayoutOpportunity(
+ ComputeLineLeftOffset(space, line_block_size, block_delta),
+ ComputeLineRightOffset(space, line_block_size, block_delta),
+ rect.LineStartOffset(), rect.LineEndOffset(),
+ rect.BlockStartOffset() + block_delta, line_block_size);
+ }
private:
LayoutUnit ComputeLineLeftOffset(const NGConstraintSpace&,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
index f5c78a92dad..3c01e9f6085 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h
@@ -118,6 +118,10 @@ struct CORE_EXPORT NGLineBoxStrut {
LayoutUnit InlineSum() const { return inline_start + inline_end; }
LayoutUnit BlockSum() const { return line_over + line_under; }
+ bool IsEmpty() const {
+ return !inline_start && !inline_end && !line_over && !line_under;
+ }
+
bool operator==(const NGLineBoxStrut& other) const {
return inline_start == other.inline_start &&
inline_end == other.inline_end && line_over == other.line_over &&
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h
index 8236afa14ee..759d7091b66 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h
@@ -26,8 +26,7 @@ struct CORE_EXPORT NGMarginStrut {
// See comment inside NGBlockLayoutAlgorithm for when this occurs.
bool is_quirky_container_start = false;
- // If set, we will discard all adjoining margins, which is the
- // effect of -webkit-margin-collapse:discard.
+ // If set, we will discard all adjoining margins.
bool discard_margins = false;
// Appends negative or positive value to the current margin strut.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_test.cc
index bd55b43700a..da28e31bfcf 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text_test.cc
@@ -47,6 +47,20 @@ class LayoutNGTextTest : public PageTestBase {
}
};
+TEST_F(LayoutNGTextTest, SetTextWithOffsetAppendBidi) {
+ if (!RuntimeEnabledFeatures::LayoutNGEnabled())
+ return;
+
+ SetBodyInnerHTML(u"<div dir=rtl id=target>\u05D0\u05D1\u05BC\u05D2</div>");
+ Text& text = To<Text>(*GetElementById("target")->firstChild());
+ text.appendData(u"\u05D0\u05D1\u05BC\u05D2");
+
+ EXPECT_EQ(String(u"*{'\u05D0\u05D1\u05BC\u05D2\u05D0\u05D1\u05BC\u05D2', "
+ u"ShapeResult=0+8}\n")
+ .Utf8(),
+ GetItemsAsString(*text.GetLayoutObject()));
+}
+
TEST_F(LayoutNGTextTest, SetTextWithOffsetAppendControl) {
if (!RuntimeEnabledFeatures::LayoutNGEnabled())
return;
@@ -136,8 +150,11 @@ TEST_F(LayoutNGTextTest, SetTextWithOffsetDeleteRTL) {
Text& text = To<Text>(*GetElementById("target")->firstChild());
text.deleteData(2, 2, ASSERT_NO_EXCEPTION); // remove "23"
- EXPECT_EQ("*{'0 4', ShapeResult=0+3}\n",
- GetItemsAsString(*text.GetLayoutObject()));
+ EXPECT_EQ(
+ "*{'0', ShapeResult=0+1}\n"
+ "*{' ', ShapeResult=1+1}\n"
+ "*{'4', ShapeResult=2+1}\n",
+ GetItemsAsString(*text.GetLayoutObject()));
}
// http://crbug.com/1000685
@@ -149,7 +166,26 @@ TEST_F(LayoutNGTextTest, SetTextWithOffsetDeleteRTL2) {
Text& text = To<Text>(*GetElementById("target")->firstChild());
text.deleteData(0, 1, ASSERT_NO_EXCEPTION); // remove "0"
- EXPECT_EQ("*{'(xy)5', ShapeResult=0+5}\n",
+ EXPECT_EQ(
+ "*{'(', ShapeResult=0+1}\n"
+ "*{'xy', ShapeResult=1+2}\n"
+ "*{')', ShapeResult=3+1}\n"
+ "*{'5', ShapeResult=4+1}\n",
+ GetItemsAsString(*text.GetLayoutObject()));
+}
+
+// http://crbug.com/1039143
+TEST_F(LayoutNGTextTest, SetTextWithOffsetDeleteWithBidiControl) {
+ if (!RuntimeEnabledFeatures::LayoutNGEnabled())
+ return;
+
+ // In text content, we have bidi control codes:
+ // U+2066 U+2069 \n U+2066 abc U+2066
+ SetBodyInnerHTML(u"<pre><b id=target dir=ltr>\nabc</b></pre>");
+ Text& text = To<Text>(*GetElementById("target")->firstChild());
+ text.deleteData(0, 1, ASSERT_NO_EXCEPTION); // remove "\n"
+
+ EXPECT_EQ("LayoutText has NeedsCollectInlines",
GetItemsAsString(*text.GetLayoutObject()));
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
index 8a5f0a7201d..34643cd55f2 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.cc
@@ -5,7 +5,10 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h"
#include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
@@ -16,38 +19,90 @@
namespace blink {
-NGAbstractInlineTextBox::FragmentToNGAbstractInlineTextBoxHashMap*
- NGAbstractInlineTextBox::g_abstract_inline_text_box_map_ = nullptr;
+namespace {
+
+// Mapping from NGFragmentItem/NGPaintFragment to NGAbstractInlineTextBox
+// TODO(yosin): Once we get rid of |NGPaintFragment|, we should not use
+// template class for |NGAbstractInlineTextBoxCache|.
+template <typename Fragment>
+class NGAbstractInlineTextBoxCache final {
+ public:
+ static scoped_refptr<AbstractInlineTextBox> GetOrCreate(
+ const Fragment& fragment) {
+ if (!s_instance_)
+ s_instance_ = new NGAbstractInlineTextBoxCache();
+ return s_instance_->GetOrCreateInternal(fragment);
+ }
+
+ static void WillDestroy(const Fragment* fragment) {
+ if (!s_instance_)
+ return;
+ s_instance_->WillDestroyInternal(fragment);
+ }
+
+ private:
+ scoped_refptr<AbstractInlineTextBox> GetOrCreateInternal(
+ const Fragment& fragment) {
+ const auto it = map_.find(&fragment);
+ LayoutText* const layout_text =
+ ToLayoutText(fragment.GetMutableLayoutObject());
+ if (it != map_.end()) {
+ CHECK(layout_text->HasAbstractInlineTextBox());
+ return it->value;
+ }
+ scoped_refptr<AbstractInlineTextBox> obj = base::AdoptRef(
+ new NGAbstractInlineTextBox(LineLayoutText(layout_text), fragment));
+ map_.Set(&fragment, obj);
+ layout_text->SetHasAbstractInlineTextBox();
+ return obj;
+ }
+
+ void WillDestroyInternal(const Fragment* fragment) {
+ const auto it = map_.find(fragment);
+ if (it == map_.end())
+ return;
+ it->value->Detach();
+ map_.erase(fragment);
+ }
+
+ static NGAbstractInlineTextBoxCache* s_instance_;
+
+ HashMap<const Fragment*, scoped_refptr<AbstractInlineTextBox>> map_;
+};
+
+template <typename Fragment>
+NGAbstractInlineTextBoxCache<Fragment>*
+ NGAbstractInlineTextBoxCache<Fragment>::s_instance_ = nullptr;
+
+} // namespace
scoped_refptr<AbstractInlineTextBox> NGAbstractInlineTextBox::GetOrCreate(
- const NGPaintFragment& fragment) {
- DCHECK(fragment.GetLayoutObject()->IsText()) << fragment.GetLayoutObject();
- if (!g_abstract_inline_text_box_map_) {
- g_abstract_inline_text_box_map_ =
- new FragmentToNGAbstractInlineTextBoxHashMap();
+ const NGInlineCursor& cursor) {
+ if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) {
+ return NGAbstractInlineTextBoxCache<NGPaintFragment>::GetOrCreate(
+ *paint_fragment);
}
- const auto it = g_abstract_inline_text_box_map_->find(&fragment);
- LayoutText* const layout_text =
- ToLayoutText(fragment.GetMutableLayoutObject());
- if (it != g_abstract_inline_text_box_map_->end()) {
- CHECK(layout_text->HasAbstractInlineTextBox());
- return it->value;
+ if (const NGFragmentItem* fragment_item = cursor.CurrentItem()) {
+ return NGAbstractInlineTextBoxCache<NGFragmentItem>::GetOrCreate(
+ *fragment_item);
}
- scoped_refptr<AbstractInlineTextBox> obj = base::AdoptRef(
- new NGAbstractInlineTextBox(LineLayoutText(layout_text), fragment));
- g_abstract_inline_text_box_map_->Set(&fragment, obj);
- layout_text->SetHasAbstractInlineTextBox();
- return obj;
+ return nullptr;
}
-void NGAbstractInlineTextBox::WillDestroy(NGPaintFragment* fragment) {
- if (!g_abstract_inline_text_box_map_)
- return;
- const auto it = g_abstract_inline_text_box_map_->find(fragment);
- if (it != g_abstract_inline_text_box_map_->end()) {
- it->value->Detach();
- g_abstract_inline_text_box_map_->erase(fragment);
+void NGAbstractInlineTextBox::WillDestroy(const NGInlineCursor& cursor) {
+ if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) {
+ return NGAbstractInlineTextBoxCache<NGPaintFragment>::WillDestroy(
+ paint_fragment);
+ }
+ if (const NGFragmentItem* fragment_item = cursor.CurrentItem()) {
+ return NGAbstractInlineTextBoxCache<NGFragmentItem>::WillDestroy(
+ fragment_item);
}
+ NOTREACHED();
+}
+
+void NGAbstractInlineTextBox::WillDestroy(const NGPaintFragment* fragment) {
+ NGAbstractInlineTextBoxCache<NGPaintFragment>::WillDestroy(fragment);
}
NGAbstractInlineTextBox::NGAbstractInlineTextBox(
@@ -57,6 +112,13 @@ NGAbstractInlineTextBox::NGAbstractInlineTextBox(
DCHECK(fragment_->PhysicalFragment().IsText()) << fragment_;
}
+NGAbstractInlineTextBox::NGAbstractInlineTextBox(
+ LineLayoutText line_layout_item,
+ const NGFragmentItem& fragment_item)
+ : AbstractInlineTextBox(line_layout_item), fragment_item_(&fragment_item) {
+ DCHECK(fragment_item_->IsText()) << fragment_item_;
+}
+
NGAbstractInlineTextBox::~NGAbstractInlineTextBox() {
DCHECK(!fragment_);
}
@@ -70,107 +132,128 @@ void NGAbstractInlineTextBox::Detach() {
fragment_ = nullptr;
}
-const NGPhysicalTextFragment& NGAbstractInlineTextBox::PhysicalTextFragment()
- const {
- return To<NGPhysicalTextFragment>(fragment_->PhysicalFragment());
+NGInlineCursor NGAbstractInlineTextBox::GetCursor() const {
+ if (!fragment_item_)
+ return NGInlineCursor();
+ NGInlineCursor cursor;
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ cursor.MoveTo(*fragment_item_);
+ else
+ cursor.MoveTo(*fragment_);
+ DCHECK(!cursor.Current().GetLayoutObject()->NeedsLayout());
+ return cursor;
+}
+
+NGInlineCursor NGAbstractInlineTextBox::GetCursorOnLine() const {
+ NGInlineCursor current = GetCursor();
+ NGInlineCursor line_box = current;
+ line_box.MoveToContainingLine();
+ NGInlineCursor cursor = line_box.CursorForDescendants();
+ cursor.MoveTo(current);
+ return cursor;
}
-bool NGAbstractInlineTextBox::NeedsLayout() const {
- return fragment_->GetLayoutObject()->NeedsLayout();
+String NGAbstractInlineTextBox::GetTextContent() const {
+ const NGInlineCursor& cursor = GetCursor();
+ if (cursor.Current().IsGeneratedTextType())
+ return cursor.Current().Text(cursor).ToString();
+ if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) {
+ return To<NGPhysicalTextFragment>(paint_fragment->PhysicalFragment())
+ .TextContent();
+ }
+ return cursor.Items().Text(cursor.Current().UsesFirstLineStyle());
}
bool NGAbstractInlineTextBox::NeedsTrailingSpace() const {
- if (!fragment_->Style().CollapseWhiteSpace())
+ const NGInlineCursor& cursor = GetCursor();
+ if (!cursor.Current().Style().CollapseWhiteSpace())
return false;
- const NGPaintFragment& line_box = *fragment_->ContainerLineBox();
- if (!To<NGPhysicalLineBoxFragment>(line_box.PhysicalFragment())
- .HasSoftWrapToNextLine())
+ NGInlineCursor line_box = cursor;
+ line_box.MoveToContainingLine();
+ if (!line_box.HasSoftWrapToNextLine())
return false;
- const NGPhysicalTextFragment& text_fragment = PhysicalTextFragment();
- if (text_fragment.EndOffset() >= text_fragment.TextContent().length())
+ const String text_content = GetTextContent();
+ const unsigned end_offset = cursor.Current().TextEndOffset();
+ if (end_offset >= text_content.length())
return false;
- if (text_fragment.TextContent()[text_fragment.EndOffset()] != ' ')
+ if (text_content[end_offset] != ' ')
return false;
- const NGInlineBreakToken& break_token = *To<NGInlineBreakToken>(
- To<NGPhysicalLineBoxFragment>(line_box.PhysicalFragment()).BreakToken());
+ const NGInlineBreakToken* break_token = line_box.Current().InlineBreakToken();
+ DCHECK(break_token);
// TODO(yosin): We should support OOF fragments between |fragment_| and
// break token.
- if (break_token.TextOffset() != text_fragment.EndOffset() + 1)
+ if (break_token->TextOffset() != end_offset + 1)
return false;
// Check a character in text content after |fragment_| comes from same
// layout text of |fragment_|.
- const NGOffsetMapping* mapping =
- NGOffsetMapping::GetFor(fragment_->GetLayoutObject());
+ const LayoutObject* const layout_object = cursor.Current().GetLayoutObject();
+ const NGOffsetMapping* mapping = NGOffsetMapping::GetFor(layout_object);
// TODO(kojii): There's not much we can do for dirty-tree. crbug.com/946004
if (!mapping)
return false;
const base::span<const NGOffsetMappingUnit> mapping_units =
- mapping->GetMappingUnitsForTextContentOffsetRange(
- text_fragment.EndOffset(), text_fragment.EndOffset() + 1);
+ mapping->GetMappingUnitsForTextContentOffsetRange(end_offset,
+ end_offset + 1);
if (mapping_units.begin() == mapping_units.end())
return false;
const NGOffsetMappingUnit& mapping_unit = mapping_units.front();
- return mapping_unit.GetLayoutObject() == fragment_->GetLayoutObject();
-}
-
-const NGPaintFragment*
-NGAbstractInlineTextBox::NextTextFragmentForSameLayoutObject() const {
- const auto fragments =
- NGPaintFragment::InlineFragmentsFor(fragment_->GetLayoutObject());
- const auto it =
- std::find_if(fragments.begin(), fragments.end(),
- [&](const auto& sibling) { return fragment_ == sibling; });
- DCHECK(it != fragments.end());
- const auto next_it = std::next(it);
- return next_it == fragments.end() ? nullptr : *next_it;
+ return mapping_unit.GetLayoutObject() == layout_object;
}
scoped_refptr<AbstractInlineTextBox>
NGAbstractInlineTextBox::NextInlineTextBox() const {
- if (!fragment_)
+ const NGInlineCursor& cursor = GetCursor();
+ if (!cursor)
return nullptr;
- DCHECK(!NeedsLayout());
- const NGPaintFragment* next_fragment = NextTextFragmentForSameLayoutObject();
- if (!next_fragment)
+ NGInlineCursor next;
+ next.MoveTo(*cursor.Current().GetLayoutObject());
+ while (next != cursor)
+ next.MoveToNextForSameLayoutObject();
+ next.MoveToNextForSameLayoutObject();
+ if (!next)
return nullptr;
- return GetOrCreate(*next_fragment);
+ return GetOrCreate(next);
}
LayoutRect NGAbstractInlineTextBox::LocalBounds() const {
- if (!fragment_ || !GetLineLayoutItem())
+ const NGInlineCursor& cursor = GetCursor();
+ if (!cursor)
return LayoutRect();
- return LayoutRect(fragment_->InlineOffsetToContainerBox().ToLayoutPoint(),
- fragment_->Size().ToLayoutSize());
+ return cursor.Current().RectInContainerBlock().ToLayoutRect();
}
unsigned NGAbstractInlineTextBox::Len() const {
- if (!fragment_)
+ const NGInlineCursor& cursor = GetCursor();
+ if (!cursor)
return 0;
if (NeedsTrailingSpace())
- return PhysicalTextFragment().TextLength() + 1;
- return PhysicalTextFragment().TextLength();
+ return cursor.Current().Text(cursor).length() + 1;
+ return cursor.Current().Text(cursor).length();
}
unsigned NGAbstractInlineTextBox::TextOffsetInContainer(unsigned offset) const {
- if (!fragment_)
+ const NGInlineCursor& cursor = GetCursor();
+ if (!cursor)
return 0;
- return PhysicalTextFragment().StartOffset() + offset;
+ return cursor.Current().TextStartOffset() + offset;
}
AbstractInlineTextBox::Direction NGAbstractInlineTextBox::GetDirection() const {
- if (!fragment_ || !GetLineLayoutItem())
+ const NGInlineCursor& cursor = GetCursor();
+ if (!cursor)
return kLeftToRight;
- const TextDirection text_direction =
- PhysicalTextFragment().ResolvedDirection();
+ const TextDirection text_direction = cursor.Current().ResolvedDirection();
if (GetLineLayoutItem().Style()->IsHorizontalWritingMode())
return IsLtr(text_direction) ? kLeftToRight : kRightToLeft;
return IsLtr(text_direction) ? kTopToBottom : kBottomToTop;
}
void NGAbstractInlineTextBox::CharacterWidths(Vector<float>& widths) const {
- if (!fragment_)
+ const NGInlineCursor& cursor = GetCursor();
+ if (!cursor)
return;
- if (!PhysicalTextFragment().TextShapeResult()) {
+ const ShapeResultView* shape_result_view = cursor.Current().TextShapeResult();
+ if (!shape_result_view) {
// When |fragment_| for BR, we don't have shape result.
// "aom-computed-boolean-properties.html" reaches here.
widths.resize(Len());
@@ -178,8 +261,8 @@ void NGAbstractInlineTextBox::CharacterWidths(Vector<float>& widths) const {
}
// TODO(layout-dev): Add support for IndividualCharacterRanges to
// ShapeResultView to avoid the copy below.
- auto shape_result =
- PhysicalTextFragment().TextShapeResult()->CreateShapeResult();
+ scoped_refptr<ShapeResult> shape_result =
+ shape_result_view->CreateShapeResult();
Vector<CharacterRange> ranges;
shape_result->IndividualCharacterRanges(&ranges);
widths.ReserveCapacity(ranges.size());
@@ -193,10 +276,11 @@ void NGAbstractInlineTextBox::CharacterWidths(Vector<float>& widths) const {
}
String NGAbstractInlineTextBox::GetText() const {
- if (!fragment_ || !GetLineLayoutItem())
- return String();
+ const NGInlineCursor& cursor = GetCursor();
+ if (!cursor)
+ return g_empty_string;
- String result = PhysicalTextFragment().Text().ToString();
+ String result = cursor.Current().Text(cursor).ToString();
// For compatibility with |InlineTextBox|, we should have a space character
// for soft line break.
@@ -217,56 +301,51 @@ String NGAbstractInlineTextBox::GetText() const {
}
bool NGAbstractInlineTextBox::IsFirst() const {
- if (!fragment_)
+ const NGInlineCursor& cursor = GetCursor();
+ if (!cursor)
return true;
- DCHECK(!NeedsLayout());
- const auto fragments =
- NGPaintFragment::InlineFragmentsFor(fragment_->GetLayoutObject());
- return fragment_ == &fragments.front();
+ NGInlineCursor first_fragment;
+ first_fragment.MoveTo(*cursor.Current().GetLayoutObject());
+ return cursor == first_fragment;
}
bool NGAbstractInlineTextBox::IsLast() const {
- if (!fragment_)
+ const NGInlineCursor& cursor = GetCursor();
+ if (!cursor)
return true;
- DCHECK(!NeedsLayout());
- const auto fragments =
- NGPaintFragment::InlineFragmentsFor(fragment_->GetLayoutObject());
- return fragment_ == &fragments.back();
+ NGInlineCursor last_fragment;
+ last_fragment.MoveTo(*cursor.Current().GetLayoutObject());
+ last_fragment.MoveToLastForSameLayoutObject();
+ return cursor == last_fragment;
}
scoped_refptr<AbstractInlineTextBox> NGAbstractInlineTextBox::NextOnLine()
const {
- if (!fragment_)
+ NGInlineCursor cursor = GetCursorOnLine();
+ if (!cursor)
return nullptr;
- DCHECK(!NeedsLayout());
- DCHECK(fragment_->ContainerLineBox());
- NGPaintFragmentTraversal cursor(*fragment_->ContainerLineBox(), *fragment_);
- for (cursor.MoveToNext(); !cursor.IsAtEnd(); cursor.MoveToNext()) {
- if (cursor->GetLayoutObject()->IsText())
- return GetOrCreate(*cursor);
+ for (cursor.MoveToNext(); cursor; cursor.MoveToNext()) {
+ if (cursor.Current().GetLayoutObject()->IsText())
+ return GetOrCreate(cursor);
}
return nullptr;
}
scoped_refptr<AbstractInlineTextBox> NGAbstractInlineTextBox::PreviousOnLine()
const {
- if (!fragment_)
+ NGInlineCursor cursor = GetCursorOnLine();
+ if (!cursor)
return nullptr;
- DCHECK(!NeedsLayout());
- DCHECK(fragment_->ContainerLineBox());
- NGPaintFragmentTraversal cursor(*fragment_->ContainerLineBox(), *fragment_);
- for (cursor.MoveToPrevious(); !cursor.IsAtEnd(); cursor.MoveToPrevious()) {
- if (cursor->GetLayoutObject()->IsText())
- return GetOrCreate(*cursor);
+ for (cursor.MoveToPrevious(); cursor; cursor.MoveToPrevious()) {
+ if (cursor.Current().GetLayoutObject()->IsText())
+ return GetOrCreate(cursor);
}
return nullptr;
}
bool NGAbstractInlineTextBox::IsLineBreak() const {
- if (!fragment_)
- return false;
- DCHECK(!NeedsLayout());
- return PhysicalTextFragment().IsLineBreak();
+ const NGInlineCursor& cursor = GetCursor();
+ return cursor && cursor.Current().IsLineBreak();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h
index 1f1d57dcef5..85fec4b6631 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_abstract_inline_text_box.h
@@ -9,34 +9,36 @@
namespace blink {
+class NGFragmentItem;
+class NGInlineCursor;
class NGPaintFragment;
-class NGPhysicalTextFragment;
// The implementation of |AbstractInlineTextBox| for LayoutNG.
// See also |LegacyAbstractInlineTextBox| for legacy layout.
class CORE_EXPORT NGAbstractInlineTextBox final : public AbstractInlineTextBox {
private:
// Returns existing or newly created |NGAbstractInlineTextBox|.
- // * |fragment| should be attached to |NGPhysicalTextFragment|.
+ // * |cursor| should be attached to |NGPhysicalTextFragment|.
static scoped_refptr<AbstractInlineTextBox> GetOrCreate(
- const NGPaintFragment& fragment);
- static void WillDestroy(NGPaintFragment*);
+ const NGInlineCursor& cursor);
+ static void WillDestroy(const NGInlineCursor& cursor);
+ static void WillDestroy(const NGPaintFragment* fragment);
friend class LayoutText;
- friend class NGPaintFragment;
public:
- ~NGAbstractInlineTextBox() final;
-
- private:
NGAbstractInlineTextBox(LineLayoutText line_layout_item,
const NGPaintFragment& fragment);
+ NGAbstractInlineTextBox(LineLayoutText line_layout_item,
+ const NGFragmentItem& fragment);
- const NGPhysicalTextFragment& PhysicalTextFragment() const;
- bool NeedsLayout() const;
+ ~NGAbstractInlineTextBox() final;
+
+ private:
+ NGInlineCursor GetCursor() const;
+ NGInlineCursor GetCursorOnLine() const;
+ String GetTextContent() const;
bool NeedsTrailingSpace() const;
- // Returns next fragment associated to |LayoutText|.
- const NGPaintFragment* NextTextFragmentForSameLayoutObject() const;
// Implementations of AbstractInlineTextBox member functions.
void Detach() final;
@@ -53,12 +55,10 @@ class CORE_EXPORT NGAbstractInlineTextBox final : public AbstractInlineTextBox {
scoped_refptr<AbstractInlineTextBox> PreviousOnLine() const final;
bool IsLineBreak() const final;
- const NGPaintFragment* fragment_;
-
- using FragmentToNGAbstractInlineTextBoxHashMap =
- HashMap<const NGPaintFragment*, scoped_refptr<AbstractInlineTextBox>>;
- static FragmentToNGAbstractInlineTextBoxHashMap*
- g_abstract_inline_text_box_map_;
+ union {
+ const NGPaintFragment* fragment_;
+ const NGFragmentItem* fragment_item_;
+ };
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.cc
deleted file mode 100644
index f9059f05c5f..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.cc
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright 2017 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/ng/inline/ng_baseline.h"
-
-#include "third_party/blink/renderer/core/layout/layout_block.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
-
-namespace blink {
-
-const unsigned NGBaselineRequest::kTypeIdCount;
-const LayoutUnit NGBaselineList::kEmptyOffset;
-
-bool NGBaselineRequest::operator==(const NGBaselineRequest& other) const {
- return algorithm_type_ == other.algorithm_type_ &&
- baseline_type_ == other.baseline_type_;
-}
-
-bool NGBaselineRequestList::operator==(
- const NGBaselineRequestList& other) const {
- return type_id_mask_ == other.type_id_mask_;
-}
-
-void NGBaselineRequestList::push_back(const NGBaselineRequest& request) {
- type_id_mask_ |= 1 << request.TypeId();
-}
-
-void NGBaselineRequestList::AppendVector(
- const NGBaselineRequestList& requests) {
- type_id_mask_ |= requests.type_id_mask_;
-}
-
-bool NGBaseline::ShouldPropagateBaselines(const NGLayoutInputNode node) {
- if (node.IsInline())
- return true;
-
- return ShouldPropagateBaselines(node.GetLayoutBox());
-}
-
-bool NGBaseline::ShouldPropagateBaselines(LayoutBox* layout_box) {
- // Test if this node should use its own box to synthesize the baseline.
- if (!layout_box->IsLayoutBlock() ||
- layout_box->IsFloatingOrOutOfFlowPositioned() ||
- layout_box->IsWritingModeRoot())
- return false;
-
- // If this node is LayoutBlock that uses old layout, this may be a subclass
- // that overrides baseline functions. Propagate baseline requests so that we
- // call virtual functions.
- if (!NGBlockNode(layout_box).CanUseNewLayout())
- return true;
-
- return true;
-}
-
-NGBaselineList::NGBaselineList() {
- std::fill(std::begin(offsets_), std::end(offsets_), kEmptyOffset);
-}
-
-bool NGBaselineList::IsEmpty() const {
- for (LayoutUnit offset : offsets_) {
- if (offset != kEmptyOffset)
- return false;
- }
- return true;
-}
-
-base::Optional<LayoutUnit> NGBaselineList::Offset(
- const NGBaselineRequest request) const {
- LayoutUnit offset = offsets_[request.TypeId()];
- if (offset != kEmptyOffset)
- return offset;
- return base::nullopt;
-}
-
-void NGBaselineList::emplace_back(NGBaselineRequest request,
- LayoutUnit offset) {
- // Round LayoutUnit::Min() because we use it for an empty value.
- DCHECK_EQ(kEmptyOffset, LayoutUnit::Min())
- << "Change the rounding if kEmptyOffset was changed";
- if (UNLIKELY(offset == LayoutUnit::Min()))
- offset = LayoutUnit::NearlyMin();
- DCHECK_NE(offset, kEmptyOffset);
- offsets_[request.TypeId()] = offset;
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h
deleted file mode 100644
index 64426201e06..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2017 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.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_BASELINE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_BASELINE_H_
-
-#include "base/optional.h"
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/fonts/font_baseline.h"
-#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
-#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
-
-namespace blink {
-
-class LayoutBox;
-class NGLayoutInputNode;
-
-enum class NGBaselineAlgorithmType {
- // Compute baselines for atomic inlines.
- kAtomicInline,
- // Compute baseline of first line box.
- kFirstLine
-};
-
-// Baselines are products of layout.
-// To compute baseline, add requests to NGConstraintSpace and run Layout().
-class CORE_EXPORT NGBaselineRequest {
- DISALLOW_NEW();
-
- public:
- NGBaselineRequest(NGBaselineAlgorithmType algorithm_type,
- FontBaseline baseline_type)
- : algorithm_type_(static_cast<unsigned>(algorithm_type)),
- baseline_type_(static_cast<unsigned>(baseline_type)) {}
-
- NGBaselineAlgorithmType AlgorithmType() const {
- return static_cast<NGBaselineAlgorithmType>(algorithm_type_);
- }
-
- FontBaseline BaselineType() const {
- return static_cast<FontBaseline>(baseline_type_);
- }
-
- bool operator==(const NGBaselineRequest& other) const;
- bool operator!=(const NGBaselineRequest& other) const {
- return !(*this == other);
- }
-
- private:
- // TypeId is an integer that identifies all combinations of
- // |NGBaselineRequest|. Visible only to |NGBaselineRequestList| and
- // |NGBaselineList|.
- static constexpr unsigned kTypeIdCount = 4;
- unsigned TypeId() const { return algorithm_type_ | (baseline_type_ << 1); }
- static NGBaselineRequest FromTypeId(unsigned type_id) {
- DCHECK_LE(type_id, kTypeIdCount);
- return NGBaselineRequest(static_cast<NGBaselineAlgorithmType>(type_id & 1),
- static_cast<FontBaseline>((type_id >> 1) & 1));
- }
- friend class NGBaselineList;
- friend class NGBaselineRequestList;
- friend class NGBaselineTest;
-
- unsigned algorithm_type_ : 1; // NGBaselineAlgorithmType
- unsigned baseline_type_ : 1; // FontBaseline
-};
-
-// A list of |NGBaselineRequest| in a packed format, with similar interface as
-// |Vector|.
-class CORE_EXPORT NGBaselineRequestList {
- DISALLOW_NEW();
-
- public:
- NGBaselineRequestList() = default;
-
- bool IsEmpty() const { return !type_id_mask_; }
-
- bool operator==(const NGBaselineRequestList& other) const;
-
- void push_back(const NGBaselineRequest& request);
- void AppendVector(const NGBaselineRequestList& requests);
-
- class const_iterator {
- DISALLOW_NEW();
-
- public:
- const_iterator() : type_id_(NGBaselineRequest::kTypeIdCount), mask_(0) {}
- explicit const_iterator(unsigned mask) : type_id_(0), mask_(mask) {
- if (!(mask_ & 1))
- ++(*this);
- }
-
- const NGBaselineRequest operator*() const {
- return NGBaselineRequest::FromTypeId(type_id_);
- }
- bool operator!=(const const_iterator& other) const {
- return type_id_ != other.type_id_;
- }
- void operator++() {
- while (type_id_ < NGBaselineRequest::kTypeIdCount) {
- ++type_id_;
- mask_ >>= 1;
- if (mask_ & 1)
- break;
- }
- }
-
- private:
- unsigned type_id_;
- unsigned mask_;
- };
-
- const_iterator begin() const { return const_iterator(type_id_mask_); }
- const_iterator end() const { return const_iterator(); }
-
- private:
- // Serialize/deserialize to a bit fields.
- static constexpr unsigned kSerializedBits = NGBaselineRequest::kTypeIdCount;
- unsigned Serialize() const { return type_id_mask_; }
- explicit NGBaselineRequestList(unsigned serialized)
- : type_id_mask_(serialized) {}
- friend class NGConstraintSpace;
- friend class NGConstraintSpaceBuilder;
-
- unsigned type_id_mask_ = 0;
-};
-
-// Represents a computed baseline position.
-struct CORE_EXPORT NGBaseline {
- NGBaselineRequest request;
- LayoutUnit offset;
-
- // @return if the node needs to propagate baseline requests/results.
- static bool ShouldPropagateBaselines(const NGLayoutInputNode);
- static bool ShouldPropagateBaselines(LayoutBox*);
-};
-
-// A list of |NGBaseline| in a packed format, with similar interface as
-// |Vector|.
-class CORE_EXPORT NGBaselineList {
- DISALLOW_NEW();
-
- public:
- NGBaselineList();
-
- bool IsEmpty() const;
-
- base::Optional<LayoutUnit> Offset(const NGBaselineRequest request) const;
-
- void emplace_back(NGBaselineRequest request, LayoutUnit offset);
-
-#if DCHECK_IS_ON()
- bool operator==(const NGBaselineList& other) const {
- for (wtf_size_t i = 0; i < NGBaselineRequest::kTypeIdCount; ++i) {
- if (offsets_[i] != other.offsets_[i])
- return false;
- }
-
- return true;
- }
-#endif
-
- class const_iterator {
- public:
- explicit const_iterator(unsigned type_id, const LayoutUnit* offset)
- : type_id_(type_id), offset_(offset) {
- DCHECK(offset);
- if (*offset == kEmptyOffset)
- ++(*this);
- }
- const_iterator()
- : type_id_(NGBaselineRequest::kTypeIdCount), offset_(nullptr) {}
-
- const NGBaseline operator*() const {
- return NGBaseline{NGBaselineRequest::FromTypeId(type_id_), *offset_};
- }
- bool operator!=(const const_iterator& other) const {
- return type_id_ != other.type_id_;
- }
- void operator++() {
- while (type_id_ < NGBaselineRequest::kTypeIdCount) {
- ++type_id_;
- ++offset_;
- if (type_id_ < NGBaselineRequest::kTypeIdCount &&
- *offset_ != kEmptyOffset)
- break;
- }
- }
-
- private:
- unsigned type_id_;
- const LayoutUnit* offset_;
- };
-
- const_iterator begin() const { return const_iterator(0, offsets_); }
- const_iterator end() const { return const_iterator(); }
-
- private:
- static constexpr LayoutUnit kEmptyOffset = LayoutUnit::Min();
-
- LayoutUnit offsets_[NGBaselineRequest::kTypeIdCount];
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_BASELINE_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_baseline_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_baseline_test.cc
deleted file mode 100644
index 5278637e097..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_baseline_test.cc
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright 2018 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/ng/inline/ng_baseline.h"
-
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/renderer/platform/wtf/vector.h"
-
-namespace blink {
-
-using ::testing::ElementsAre;
-using ::testing::ElementsAreArray;
-
-class NGBaselineTest : public testing::Test {
- public:
- static NGBaselineRequest RequestFromTypeId(unsigned type_id) {
- return NGBaselineRequest::FromTypeId(type_id);
- }
-
- static Vector<NGBaselineRequest> ToList(NGBaselineRequestList requests) {
- Vector<NGBaselineRequest> list;
- for (const NGBaselineRequest request : requests)
- list.push_back(request);
- return list;
- }
-};
-
-struct NGBaselineRequestListTestData {
- unsigned count;
- unsigned type_ids[4];
-} baseline_request_list_test_data[] = {
- {0, {}}, {1, {0}}, {1, {1}}, {1, {2}},
- {1, {3}}, {2, {0, 1}}, {2, {0, 2}}, {2, {1, 3}},
- {3, {0, 1, 2}}, {3, {0, 2, 3}}, {3, {1, 2, 3}}, {4, {0, 1, 2, 3}},
-};
-
-class NGBaselineRequestListDataTest
- : public NGBaselineTest,
- public testing::WithParamInterface<NGBaselineRequestListTestData> {};
-
-INSTANTIATE_TEST_SUITE_P(NGBaselineTest,
- NGBaselineRequestListDataTest,
- testing::ValuesIn(baseline_request_list_test_data));
-
-TEST_P(NGBaselineRequestListDataTest, Data) {
- const auto& data = GetParam();
- NGBaselineRequestList requests;
- Vector<NGBaselineRequest> expected;
- for (unsigned i = 0; i < data.count; i++) {
- NGBaselineRequest request = RequestFromTypeId(data.type_ids[i]);
- requests.push_back(request);
- expected.push_back(request);
- }
-
- EXPECT_EQ(requests.IsEmpty(), !data.count);
-
- Vector<NGBaselineRequest> actual = ToList(requests);
- EXPECT_THAT(actual, expected);
-}
-
-TEST_F(NGBaselineTest, BaselineList) {
- NGBaselineList list;
- EXPECT_TRUE(list.IsEmpty());
-
- NGBaselineRequest request(NGBaselineAlgorithmType::kFirstLine,
- FontBaseline::kAlphabeticBaseline);
- list.emplace_back(request, LayoutUnit(123));
- EXPECT_FALSE(list.IsEmpty());
- EXPECT_EQ(list.Offset(request), LayoutUnit(123));
- EXPECT_FALSE(list.Offset({NGBaselineAlgorithmType::kFirstLine,
- FontBaseline::kIdeographicBaseline}));
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc
index b01d591bf48..ed88fbe192b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc
@@ -90,11 +90,11 @@ CaretPositionResolution TryResolveCaretPositionInTextFragment(
const NGInlineCursor& cursor,
unsigned offset,
TextAffinity affinity) {
- if (cursor.IsGeneratedText())
+ if (cursor.Current().IsGeneratedText())
return CaretPositionResolution();
const NGOffsetMapping& mapping =
- *NGOffsetMapping::GetFor(cursor.CurrentLayoutObject());
+ *NGOffsetMapping::GetFor(cursor.Current().GetLayoutObject());
// A text fragment natually allows caret placement in offset range
// [StartOffset(), EndOffset()], i.e., from before the first character to
@@ -106,12 +106,13 @@ CaretPositionResolution TryResolveCaretPositionInTextFragment(
// Note that we don't ignore other characters that are not in fragments. For
// example, a trailing space of a line is not in any fragment, but its two
// sides are still different caret positions, so we don't ignore it.
- const unsigned start_offset = cursor.CurrentTextStartOffset();
- const unsigned end_offset = cursor.CurrentTextEndOffset();
+ const NGTextOffset current_offset = cursor.Current().TextOffset();
+ const unsigned start_offset = current_offset.start;
+ const unsigned end_offset = current_offset.end;
if (offset < start_offset &&
!mapping.HasBidiControlCharactersOnly(offset, start_offset))
return CaretPositionResolution();
- if (offset > cursor.CurrentTextEndOffset() &&
+ if (offset > current_offset.end &&
!mapping.HasBidiControlCharactersOnly(end_offset, offset))
return CaretPositionResolution();
@@ -129,7 +130,7 @@ CaretPositionResolution TryResolveCaretPositionInTextFragment(
return {ResolutionType::kResolved, candidate};
}
- if (offset == end_offset && !cursor.IsLineBreak() &&
+ if (offset == end_offset && !cursor.Current().IsLineBreak() &&
CanResolveCaretPositionAfterFragment(cursor, affinity)) {
return {ResolutionType::kResolved, candidate};
}
@@ -157,7 +158,7 @@ CaretPositionResolution TryResolveCaretPositionByBoxFragmentSide(
const NGInlineCursor& cursor,
unsigned offset,
TextAffinity affinity) {
- const Node* const node = cursor.CurrentNode();
+ const Node* const node = cursor.Current().GetNode();
// There is no caret position at a pseudo or generated box side.
if (!node || node->IsPseudoElement()) {
// TODO(xiaochengh): This leads to false negatives for, e.g., RUBY, where an
@@ -192,9 +193,9 @@ CaretPositionResolution TryResolveCaretPositionWithFragment(
const NGInlineCursor& cursor,
unsigned offset,
TextAffinity affinity) {
- if (cursor.IsText())
+ if (cursor.Current().IsText())
return TryResolveCaretPositionInTextFragment(cursor, offset, affinity);
- if (cursor.IsAtomicInline())
+ if (cursor.Current().IsAtomicInline())
return TryResolveCaretPositionByBoxFragmentSide(cursor, offset, affinity);
return CaretPositionResolution();
}
@@ -207,8 +208,9 @@ bool NeedsBidiAdjustment(const NGCaretPosition& caret_position) {
if (caret_position.position_type != NGCaretPositionType::kAtTextOffset)
return true;
DCHECK(caret_position.text_offset.has_value());
- const unsigned start_offset = caret_position.cursor.CurrentTextStartOffset();
- const unsigned end_offset = caret_position.cursor.CurrentTextEndOffset();
+ const NGTextOffset offset = caret_position.cursor.Current().TextOffset();
+ const unsigned start_offset = offset.start;
+ const unsigned end_offset = offset.end;
DCHECK_GE(*caret_position.text_offset, start_offset);
DCHECK_LE(*caret_position.text_offset, end_offset);
// Bidi adjustment is needed only for caret positions at bidi boundaries.
@@ -232,10 +234,10 @@ bool IsUpstreamAfterLineBreak(const NGCaretPosition& caret_position) {
DCHECK(caret_position.cursor.IsNotNull());
DCHECK(caret_position.text_offset.has_value());
- if (!caret_position.cursor.IsLineBreak())
+ if (!caret_position.cursor.Current().IsLineBreak())
return false;
return *caret_position.text_offset ==
- caret_position.cursor.CurrentTextEndOffset();
+ caret_position.cursor.Current().TextEndOffset();
}
NGCaretPosition BetterCandidateBetween(const NGCaretPosition& current,
@@ -320,22 +322,24 @@ PositionWithAffinity NGCaretPosition::ToPositionInDOMTreeWithAffinity() const {
return PositionWithAffinity();
switch (position_type) {
case NGCaretPositionType::kBeforeBox:
- if (cursor.CurrentNode())
+ if (cursor.Current().GetNode())
return PositionWithAffinity();
- return PositionWithAffinity(Position::BeforeNode(*cursor.CurrentNode()),
- TextAffinity::kDownstream);
+ return PositionWithAffinity(
+ Position::BeforeNode(*cursor.Current().GetNode()),
+ TextAffinity::kDownstream);
case NGCaretPositionType::kAfterBox:
- if (cursor.CurrentNode())
+ if (cursor.Current().GetNode())
return PositionWithAffinity();
- return PositionWithAffinity(Position::AfterNode(*cursor.CurrentNode()),
- TextAffinity::kUpstreamIfPossible);
+ return PositionWithAffinity(
+ Position::AfterNode(*cursor.Current().GetNode()),
+ TextAffinity::kUpstreamIfPossible);
case NGCaretPositionType::kAtTextOffset:
- // In case of ::first-letter, |cursor.CurrentNode()| is null.
+ // In case of ::first-letter, |cursor.Current().GetNode()| is null.
DCHECK(text_offset.has_value());
const NGOffsetMapping* mapping =
- NGOffsetMapping::GetFor(cursor.CurrentLayoutObject());
+ NGOffsetMapping::GetFor(cursor.Current().GetLayoutObject());
const TextAffinity affinity =
- *text_offset == cursor.CurrentTextEndOffset()
+ *text_offset == cursor.Current().TextEndOffset()
? TextAffinity::kUpstreamIfPossible
: TextAffinity::kDownstream;
const Position position = affinity == TextAffinity::kDownstream
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc
index 7977e5227cf..bccd83f3551 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc
@@ -17,28 +17,29 @@ namespace {
PhysicalRect ComputeLocalCaretRectByBoxSide(const NGInlineCursor& cursor,
NGCaretPositionType position_type) {
- const bool is_horizontal = cursor.CurrentStyle().IsHorizontalWritingMode();
+ const bool is_horizontal = cursor.Current().Style().IsHorizontalWritingMode();
NGInlineCursor line_box(cursor);
line_box.MoveToContainingLine();
DCHECK(line_box);
const PhysicalOffset offset_to_line_box =
- cursor.CurrentOffset() - line_box.CurrentOffset();
- LayoutUnit caret_height = is_horizontal ? line_box.CurrentSize().height
- : line_box.CurrentSize().width;
+ cursor.Current().OffsetInContainerBlock() -
+ line_box.Current().OffsetInContainerBlock();
+ LayoutUnit caret_height = is_horizontal ? line_box.Current().Size().height
+ : line_box.Current().Size().width;
LayoutUnit caret_top =
is_horizontal ? -offset_to_line_box.top : -offset_to_line_box.left;
const LocalFrameView* frame_view =
- cursor.CurrentLayoutObject()->GetDocument().View();
+ cursor.Current().GetLayoutObject()->GetDocument().View();
LayoutUnit caret_width = frame_view->CaretWidth();
- const bool is_ltr = IsLtr(cursor.CurrentResolvedDirection());
+ const bool is_ltr = IsLtr(cursor.Current().ResolvedDirection());
LayoutUnit caret_left;
if (is_ltr != (position_type == NGCaretPositionType::kBeforeBox)) {
if (is_horizontal)
- caret_left = cursor.CurrentSize().width - caret_width;
+ caret_left = cursor.Current().Size().width - caret_width;
else
- caret_left = cursor.CurrentSize().height - caret_width;
+ caret_left = cursor.Current().Size().height - caret_width;
}
if (!is_horizontal) {
@@ -53,22 +54,22 @@ PhysicalRect ComputeLocalCaretRectByBoxSide(const NGInlineCursor& cursor,
PhysicalRect ComputeLocalCaretRectAtTextOffset(const NGInlineCursor& cursor,
unsigned offset) {
- DCHECK(cursor.IsText());
- DCHECK_GE(offset, cursor.CurrentTextStartOffset());
- DCHECK_LE(offset, cursor.CurrentTextEndOffset());
+ DCHECK(cursor.Current().IsText());
+ DCHECK_GE(offset, cursor.Current().TextStartOffset());
+ DCHECK_LE(offset, cursor.Current().TextEndOffset());
const LocalFrameView* frame_view =
- cursor.CurrentLayoutObject()->GetDocument().View();
+ cursor.Current().GetLayoutObject()->GetDocument().View();
LayoutUnit caret_width = frame_view->CaretWidth();
- const bool is_horizontal = cursor.CurrentStyle().IsHorizontalWritingMode();
+ const bool is_horizontal = cursor.Current().Style().IsHorizontalWritingMode();
- LayoutUnit caret_height =
- is_horizontal ? cursor.CurrentSize().height : cursor.CurrentSize().width;
+ LayoutUnit caret_height = is_horizontal ? cursor.Current().Size().height
+ : cursor.Current().Size().width;
LayoutUnit caret_top;
LayoutUnit caret_left = cursor.InlinePositionForOffset(offset);
- if (!cursor.IsLineBreak())
+ if (!cursor.Current().IsLineBreak())
caret_left -= caret_width / 2;
if (!is_horizontal) {
@@ -77,16 +78,17 @@ PhysicalRect ComputeLocalCaretRectAtTextOffset(const NGInlineCursor& cursor,
}
// Adjust the location to be relative to the inline formatting context.
- PhysicalOffset caret_location =
- PhysicalOffset(caret_left, caret_top) + cursor.CurrentOffset();
+ PhysicalOffset caret_location = PhysicalOffset(caret_left, caret_top) +
+ cursor.Current().OffsetInContainerBlock();
const PhysicalSize caret_size(caret_width, caret_height);
const NGPhysicalBoxFragment& fragmentainer =
- *cursor.CurrentLayoutObject()->ContainingBlockFlowFragment();
+ *cursor.Current().GetLayoutObject()->ContainingBlockFlowFragment();
NGInlineCursor line_box(cursor);
line_box.MoveToContainingLine();
- const PhysicalOffset line_box_offset = line_box.CurrentOffset();
- const PhysicalRect line_box_rect(line_box_offset, line_box.CurrentSize());
+ const PhysicalOffset line_box_offset =
+ line_box.Current().OffsetInContainerBlock();
+ const PhysicalRect line_box_rect(line_box_offset, line_box.Current().Size());
// For horizontal text, adjust the location in the x direction to ensure that
// it completely falls in the union of line box and containing block, and
@@ -116,17 +118,17 @@ LocalCaretRect ComputeLocalCaretRect(const NGCaretPosition& caret_position) {
return LocalCaretRect();
const LayoutObject* layout_object =
- caret_position.cursor.CurrentLayoutObject();
+ caret_position.cursor.Current().GetLayoutObject();
switch (caret_position.position_type) {
case NGCaretPositionType::kBeforeBox:
case NGCaretPositionType::kAfterBox: {
- DCHECK(!caret_position.cursor.IsText());
+ DCHECK(!caret_position.cursor.Current().IsText());
const PhysicalRect fragment_local_rect = ComputeLocalCaretRectByBoxSide(
caret_position.cursor, caret_position.position_type);
return {layout_object, fragment_local_rect};
}
case NGCaretPositionType::kAtTextOffset: {
- DCHECK(caret_position.cursor.IsText());
+ DCHECK(caret_position.cursor.Current().IsText());
DCHECK(caret_position.text_offset.has_value());
const PhysicalRect caret_rect = ComputeLocalCaretRectAtTextOffset(
caret_position.cursor, *caret_position.text_offset);
@@ -151,12 +153,12 @@ LocalCaretRect ComputeLocalSelectionRect(
DCHECK(line_box);
PhysicalRect rect = caret_rect.rect;
- if (caret_position.cursor.CurrentStyle().IsHorizontalWritingMode()) {
- rect.SetY(line_box.CurrentOffset().top);
- rect.SetHeight(line_box.CurrentSize().height);
+ if (caret_position.cursor.Current().Style().IsHorizontalWritingMode()) {
+ rect.SetY(line_box.Current().OffsetInContainerBlock().top);
+ rect.SetHeight(line_box.Current().Size().height);
} else {
- rect.SetX(line_box.CurrentOffset().left);
- rect.SetHeight(line_box.CurrentSize().width);
+ rect.SetX(line_box.Current().OffsetInContainerBlock().left);
+ rect.SetHeight(line_box.Current().Size().width);
}
return {caret_rect.layout_object, rect};
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
index c184209b8f2..63a23dff82b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.cc
@@ -9,13 +9,14 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
namespace blink {
NGFragmentItem::NGFragmentItem(const NGPhysicalTextFragment& text)
: layout_object_(text.GetLayoutObject()),
- text_({text.TextShapeResult(), text.StartOffset(), text.EndOffset()}),
+ text_({text.TextShapeResult(), text.TextOffset()}),
rect_({PhysicalOffset(), text.Size()}),
type_(kText),
sub_type_(static_cast<unsigned>(text.TextType())),
@@ -23,12 +24,12 @@ NGFragmentItem::NGFragmentItem(const NGPhysicalTextFragment& text)
is_generated_text_(text.IsGeneratedText()),
is_hidden_for_paint_(text.IsHiddenForPaint()),
text_direction_(static_cast<unsigned>(text.ResolvedDirection())),
- ink_overflow_computed_(false) {
- DCHECK_LE(text_.start_offset, text_.end_offset);
+ ink_overflow_computed_(false),
+ is_first_for_node_(text.IsFirstForNode()) {
#if DCHECK_IS_ON()
if (text_.shape_result) {
- DCHECK_EQ(text_.shape_result->StartIndex(), text_.start_offset);
- DCHECK_EQ(text_.shape_result->EndIndex(), text_.end_offset);
+ DCHECK_EQ(text_.shape_result->StartIndex(), StartOffset());
+ DCHECK_EQ(text_.shape_result->EndIndex(), EndOffset());
}
#endif
if (text.TextType() == NGPhysicalTextFragment::kGeneratedText) {
@@ -38,6 +39,7 @@ NGFragmentItem::NGFragmentItem(const NGPhysicalTextFragment& text)
// |generated_text_.text_| instead copying, |generated_text_.text = ...|.
new (&generated_text_.text) String(text.Text().ToString());
}
+ DCHECK(!IsFormattingContextRoot());
}
NGFragmentItem::NGFragmentItem(const NGPhysicalLineBoxFragment& line,
@@ -46,22 +48,45 @@ NGFragmentItem::NGFragmentItem(const NGPhysicalLineBoxFragment& line,
line_({&line, item_count}),
rect_({PhysicalOffset(), line.Size()}),
type_(kLine),
+ sub_type_(static_cast<unsigned>(line.LineBoxType())),
style_variant_(static_cast<unsigned>(line.StyleVariant())),
is_hidden_for_paint_(false),
text_direction_(static_cast<unsigned>(line.BaseDirection())),
- ink_overflow_computed_(false) {}
+ ink_overflow_computed_(false),
+ is_first_for_node_(true) {
+ DCHECK(!IsFormattingContextRoot());
+}
NGFragmentItem::NGFragmentItem(const NGPhysicalBoxFragment& box,
- wtf_size_t item_count,
TextDirection resolved_direction)
: layout_object_(box.GetLayoutObject()),
- box_({&box, item_count}),
+ box_({&box, 1}),
rect_({PhysicalOffset(), box.Size()}),
type_(kBox),
style_variant_(static_cast<unsigned>(box.StyleVariant())),
is_hidden_for_paint_(box.IsHiddenForPaint()),
text_direction_(static_cast<unsigned>(resolved_direction)),
- ink_overflow_computed_(false) {}
+ ink_overflow_computed_(false),
+ is_first_for_node_(box.IsFirstForNode()) {
+ DCHECK_EQ(IsFormattingContextRoot(), box.IsFormattingContextRoot());
+}
+
+NGFragmentItem::NGFragmentItem(const NGInlineItem& inline_item,
+ const PhysicalSize& size)
+ : layout_object_(inline_item.GetLayoutObject()),
+ box_({nullptr, 1}),
+ rect_({PhysicalOffset(), size}),
+ type_(kBox),
+ style_variant_(static_cast<unsigned>(inline_item.StyleVariant())),
+ is_hidden_for_paint_(false),
+ text_direction_(static_cast<unsigned>(TextDirection::kLtr)),
+ ink_overflow_computed_(false),
+ is_first_for_node_(true) {
+ DCHECK_EQ(inline_item.Type(), NGInlineItem::kOpenTag);
+ DCHECK(layout_object_);
+ DCHECK(layout_object_->IsLayoutInline());
+ DCHECK(!IsFormattingContextRoot());
+}
NGFragmentItem::~NGFragmentItem() {
switch (Type()) {
@@ -80,12 +105,32 @@ NGFragmentItem::~NGFragmentItem() {
}
}
-bool NGFragmentItem::HasSameParent(const NGFragmentItem& other) const {
+bool NGFragmentItem::IsSiblingOf(const NGFragmentItem& other) const {
if (!GetLayoutObject())
return !other.GetLayoutObject();
if (!other.GetLayoutObject())
return false;
- return GetLayoutObject()->Parent() == other.GetLayoutObject()->Parent();
+ if (GetLayoutObject()->Parent() == other.GetLayoutObject()->Parent())
+ return true;
+ // To traverse list marker and line box of <li> with |MoveToNextSibling()|,
+ // we think list marker and <li> are sibling.
+ // See hittesting/culled-inline-crash.html (skip list marker)
+ // See fast/events/onclick-list-marker.html (hit on list marker)
+ if (IsListMarker())
+ return GetLayoutObject()->Parent() == other.GetLayoutObject();
+ if (other.IsListMarker())
+ return other.GetLayoutObject()->Parent() == GetLayoutObject();
+ return false;
+}
+
+bool NGFragmentItem::IsInlineBox() const {
+ if (Type() == kBox) {
+ if (const NGPhysicalBoxFragment* box = BoxFragment())
+ return box->IsInlineBox();
+ DCHECK(GetLayoutObject()->IsLayoutInline());
+ return true;
+ }
+ return false;
}
bool NGFragmentItem::IsAtomicInline() const {
@@ -96,11 +141,16 @@ bool NGFragmentItem::IsAtomicInline() const {
return false;
}
-bool NGFragmentItem::IsEmptyLineBox() const {
- // TODO(yosin): Implement |NGFragmentItem::IsEmptyLineBox()|.
+bool NGFragmentItem::IsFloating() const {
+ if (const NGPhysicalBoxFragment* box = BoxFragment())
+ return box->IsFloating();
return false;
}
+bool NGFragmentItem::IsEmptyLineBox() const {
+ return LineBoxType() == NGLineBoxType::kEmptyLineBox;
+}
+
bool NGFragmentItem::IsGeneratedText() const {
if (Type() == kText || Type() == kGeneratedText)
return is_generated_text_;
@@ -109,8 +159,7 @@ bool NGFragmentItem::IsGeneratedText() const {
}
bool NGFragmentItem::IsListMarker() const {
- // TODO(yosin): Implement |NGFragmentItem::IsListMarker()|.
- return false;
+ return layout_object_ && layout_object_->IsLayoutNGOutsideListMarker();
}
bool NGFragmentItem::HasOverflowClip() const {
@@ -162,11 +211,6 @@ PhysicalRect NGFragmentItem::InkOverflow() const {
return container_ink_overflow.SelfAndContentsInkOverflow();
}
-PositionWithAffinity NGFragmentItem::PositionForPoint(
- const PhysicalOffset&) const {
- return PositionWithAffinity();
-}
-
const ShapeResultView* NGFragmentItem::TextShapeResult() const {
if (Type() == kText)
return text_.shape_result.get();
@@ -176,29 +220,19 @@ const ShapeResultView* NGFragmentItem::TextShapeResult() const {
return nullptr;
}
-unsigned NGFragmentItem::StartOffset() const {
+NGTextOffset NGFragmentItem::TextOffset() const {
if (Type() == kText)
- return text_.start_offset;
+ return text_.text_offset;
if (Type() == kGeneratedText)
- return 0;
+ return {0, generated_text_.text.length()};
NOTREACHED();
- return 0;
-}
-
-unsigned NGFragmentItem::EndOffset() const {
- if (Type() == kText)
- return text_.end_offset;
- if (Type() == kGeneratedText)
- return generated_text_.text.length();
- NOTREACHED();
- return 0;
+ return {};
}
StringView NGFragmentItem::Text(const NGFragmentItems& items) const {
if (Type() == kText) {
- DCHECK_LE(text_.start_offset, text_.end_offset);
- return StringView(items.Text(UsesFirstLineStyle()), text_.start_offset,
- text_.end_offset - text_.start_offset);
+ return StringView(items.Text(UsesFirstLineStyle()), text_.text_offset.start,
+ text_.text_offset.Length());
}
if (Type() == kGeneratedText)
return GeneratedText();
@@ -209,8 +243,8 @@ StringView NGFragmentItem::Text(const NGFragmentItems& items) const {
NGTextFragmentPaintInfo NGFragmentItem::TextPaintInfo(
const NGFragmentItems& items) const {
if (Type() == kText) {
- return {items.Text(UsesFirstLineStyle()), text_.start_offset,
- text_.end_offset, text_.shape_result.get()};
+ return {items.Text(UsesFirstLineStyle()), text_.text_offset.start,
+ text_.text_offset.end, text_.shape_result.get()};
}
if (Type() == kGeneratedText) {
return {generated_text_.text, 0, generated_text_.text.length(),
@@ -231,6 +265,24 @@ TextDirection NGFragmentItem::ResolvedDirection() const {
}
String NGFragmentItem::DebugName() const {
+ // TODO(yosin): Once |NGPaintFragment| is removed, we should get rid of
+ // following if-statements.
+ // For ease of rebasing, we use same |DebugName()| as |NGPaintFrgment|.
+ if (Type() == NGFragmentItem::kBox) {
+ StringBuilder name;
+ name.Append("NGPhysicalBoxFragment ");
+ name.Append(layout_object_->DebugName());
+ return name.ToString();
+ }
+ if (Type() == NGFragmentItem::kText) {
+ StringBuilder name;
+ name.Append("NGPhysicalTextFragment '");
+ name.Append(Text(*layout_object_->ContainingBlockFlowFragment()->Items()));
+ name.Append('\'');
+ return name.ToString();
+ }
+ if (Type() == NGFragmentItem::kLine)
+ return "NGPhysicalLineBoxFragment";
return "NGFragmentItem";
}
@@ -241,17 +293,28 @@ IntRect NGFragmentItem::VisualRect() const {
return GetLayoutObject()->VisualRectForInlineBox();
}
+IntRect NGFragmentItem::PartialInvalidationVisualRect() const {
+ // TODO(yosin): Need to reconsider the storage of |VisualRect|, to integrate
+ // better with |FragmentData| and to avoid dependency to |LayoutObject|.
+ DCHECK(GetLayoutObject());
+ return GetLayoutObject()->PartialInvalidationVisualRectForInlineBox();
+}
+
PhysicalRect NGFragmentItem::LocalVisualRectFor(
const LayoutObject& layout_object) {
DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
DCHECK(layout_object.IsInLayoutNGInlineFormattingContext());
PhysicalRect visual_rect;
- for (const NGFragmentItem& item : ItemsFor(layout_object)) {
+ NGInlineCursor cursor;
+ for (cursor.MoveTo(layout_object); cursor;
+ cursor.MoveToNextForSameLayoutObject()) {
+ DCHECK(cursor.Current().Item());
+ const NGFragmentItem& item = *cursor.Current().Item();
if (UNLIKELY(item.IsHiddenForPaint()))
continue;
PhysicalRect child_visual_rect = item.SelfInkOverflow();
- child_visual_rect.offset += item.Offset();
+ child_visual_rect.offset += item.OffsetInContainerBlock();
visual_rect.Unite(child_visual_rect);
}
return visual_rect;
@@ -269,7 +332,7 @@ PhysicalRect NGFragmentItem::RecalcInkOverflowForCursor(
if (item->HasSelfPaintingLayer())
continue;
if (!child_rect.IsEmpty()) {
- child_rect.offset += item->Offset();
+ child_rect.offset += item->OffsetInContainerBlock();
contents_ink_overflow.Unite(child_rect);
}
}
@@ -322,14 +385,22 @@ void NGFragmentItem::RecalcInkOverflow(
cursor->MoveToNextSibling();
PhysicalRect contents_rect = RecalcInkOverflowForCursor(&descendants_cursor);
+ // |contents_rect| is relative to the inline formatting context. Make it
+ // relative to |this|.
+ contents_rect.offset -= OffsetInContainerBlock();
+
// Compute the self ink overflow.
PhysicalRect self_rect;
if (Type() == kLine) {
// Line boxes don't have self overflow. Compute content overflow only.
*self_and_contents_rect_out = contents_rect;
- } else if (const NGPhysicalBoxFragment* box_fragment = BoxFragment()) {
- DCHECK(box_fragment->IsInlineBox());
- self_rect = box_fragment->ComputeSelfInkOverflow();
+ } else if (Type() == kBox) {
+ if (const NGPhysicalBoxFragment* box_fragment = BoxFragment()) {
+ DCHECK(box_fragment->IsInlineBox());
+ self_rect = box_fragment->ComputeSelfInkOverflow();
+ } else {
+ self_rect = LocalRect();
+ }
*self_and_contents_rect_out = UnionRect(self_rect, contents_rect);
} else {
NOTREACHED();
@@ -403,49 +474,6 @@ unsigned NGFragmentItem::TextOffsetForPoint(
return inline_offset <= size.inline_size / 2 ? StartOffset() : EndOffset();
}
-NGFragmentItem::ItemsForLayoutObject NGFragmentItem::ItemsFor(
- const LayoutObject& layout_object) {
- DCHECK(layout_object.IsInLayoutNGInlineFormattingContext());
- DCHECK(layout_object.IsText() || layout_object.IsLayoutInline() ||
- (layout_object.IsBox() && layout_object.IsInline()));
-
- if (const LayoutBlockFlow* block_flow =
- layout_object.RootInlineFormattingContext()) {
- if (const NGPhysicalBoxFragment* fragment = block_flow->CurrentFragment()) {
- if (wtf_size_t index = layout_object.FirstInlineFragmentItemIndex()) {
- const auto& items = fragment->Items()->Items();
- return ItemsForLayoutObject(items, index, items[index].get());
- }
- // TODO(yosin): Once we update all usages of |FirstInlineFragment()|,
- // we should get rid of below code.
- if (const NGFragmentItems* items = fragment->Items()) {
- for (unsigned i = 0; i < items->Items().size(); ++i) {
- const NGFragmentItem* item = items->Items()[i].get();
- if (item->GetLayoutObject() == &layout_object)
- return ItemsForLayoutObject(items->Items(), i, item);
- }
- }
- }
- }
-
- return ItemsForLayoutObject();
-}
-
-NGFragmentItem::ItemsForLayoutObject::Iterator&
-NGFragmentItem::ItemsForLayoutObject::Iterator::operator++() {
- // TODO(kojii): This is a hot function needed by paint and several other
- // operations. Make this fast, by not iterating.
- if (!current_)
- return *this;
- if (!current_->delta_to_next_for_same_layout_object_) {
- current_ = nullptr;
- return *this;
- }
- index_ += current_->delta_to_next_for_same_layout_object_;
- current_ = (*items_)[index_].get();
- return *this;
-}
-
std::ostream& operator<<(std::ostream& ostream, const NGFragmentItem& item) {
ostream << "{";
switch (item.Type()) {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
index 112464bdc50..c07af90d3d8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h"
#include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h"
#include "third_party/blink/renderer/platform/graphics/paint/display_item_client.h"
@@ -18,6 +19,7 @@ namespace blink {
class NGFragmentItems;
class NGInlineBreakToken;
+class NGInlineItem;
struct NGTextFragmentPaintInfo;
// This class represents a text run or a box in an inline formatting context.
@@ -32,8 +34,7 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
// TODO(kojii): |start_offset| and |end_offset| should match to the offset
// in |shape_result|. Consider if we should remove them, or if keeping them
// is easier.
- const unsigned start_offset;
- const unsigned end_offset;
+ const NGTextOffset text_offset;
};
// Represents text generated by the layout engine, e.g., hyphen or ellipsis.
struct GeneratedTextItem {
@@ -64,8 +65,8 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
// TODO(kojii): Should be able to create without once creating fragments.
NGFragmentItem(const NGPhysicalTextFragment& text);
NGFragmentItem(const NGPhysicalBoxFragment& box,
- wtf_size_t item_count,
TextDirection resolved_direction);
+ NGFragmentItem(const NGInlineItem& inline_item, const PhysicalSize& size);
NGFragmentItem(const NGPhysicalLineBoxFragment& line, wtf_size_t item_count);
~NGFragmentItem() final;
@@ -74,11 +75,29 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
bool IsText() const { return Type() == kText || Type() == kGeneratedText; }
bool IsContainer() const { return Type() == kBox || Type() == kLine; }
+ bool IsInlineBox() const;
bool IsAtomicInline() const;
+ bool IsFloating() const;
bool IsEmptyLineBox() const;
bool IsHiddenForPaint() const { return is_hidden_for_paint_; }
bool IsListMarker() const;
+ // Return true if this is the first fragment generated from a node.
+ bool IsFirstForNode() const {
+ DCHECK(Type() != kLine);
+ DCHECK(!IsInlineBox() || BoxFragment());
+ return is_first_for_node_;
+ }
+
+ // Return true if this is the last fragment generated from a node.
+ bool IsLastForNode() const {
+ // TODO(layout-dev): This doesn't work if the LayoutObject continues in a
+ // next fragmentainer (we get a false negative here then).
+ DCHECK(Type() != kLine);
+ DCHECK(!IsInlineBox() || BoxFragment());
+ return !DeltaToNextForSameLayoutObject();
+ }
+
NGStyleVariant StyleVariant() const {
return static_cast<NGStyleVariant>(style_variant_);
}
@@ -100,15 +119,15 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
}
Node* GetNode() const { return layout_object_->GetNode(); }
Node* NodeForHitTest() const { return layout_object_->NodeForHitTest(); }
- bool HasSameParent(const NGFragmentItem& other) const;
+ bool IsSiblingOf(const NGFragmentItem& other) const;
wtf_size_t DeltaToNextForSameLayoutObject() const {
return delta_to_next_for_same_layout_object_;
}
void SetDeltaToNextForSameLayoutObject(wtf_size_t delta);
- const PhysicalRect& Rect() const { return rect_; }
- const PhysicalOffset& Offset() const { return rect_.offset; }
+ const PhysicalRect& RectInContainerBlock() const { return rect_; }
+ const PhysicalOffset& OffsetInContainerBlock() const { return rect_.offset; }
const PhysicalSize& Size() const { return rect_.size; }
PhysicalRect LocalRect() const { return {PhysicalOffset(), Size()}; }
void SetOffset(const PhysicalOffset& offset) { rect_.offset = offset; }
@@ -128,6 +147,10 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
return 0;
}
bool HasChildren() const { return DescendantsCount() > 1; }
+ void SetDescendantsCount(wtf_size_t count) {
+ CHECK_EQ(Type(), kBox);
+ box_.descendants_count = count;
+ }
// Returns |NGPhysicalBoxFragment| if one is associated with this item.
const NGPhysicalBoxFragment* BoxFragment() const {
@@ -158,58 +181,19 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
return nullptr;
}
- NGTextFragmentPaintInfo TextPaintInfo(const NGFragmentItems& items) const;
+ using NGLineBoxType = NGPhysicalLineBoxFragment::NGLineBoxType;
+ NGLineBoxType LineBoxType() const {
+ if (Type() == kLine)
+ return static_cast<NGLineBoxType>(sub_type_);
+ NOTREACHED() << this;
+ return NGLineBoxType::kNormalLineBox;
+ }
// DisplayItemClient overrides
String DebugName() const override;
IntRect VisualRect() const override;
+ IntRect PartialInvalidationVisualRect() const override;
- // Find |NGFragmentItem|s that are associated with a |LayoutObject|.
- class CORE_EXPORT ItemsForLayoutObject {
- STACK_ALLOCATED();
-
- public:
- ItemsForLayoutObject() = default;
- ItemsForLayoutObject(const Vector<std::unique_ptr<NGFragmentItem>>& items,
- unsigned first_index,
- const NGFragmentItem* first_item)
- : items_(&items), first_item_(first_item), first_index_(first_index) {}
-
- bool IsEmpty() const { return !items_; }
-
- class CORE_EXPORT Iterator {
- public:
- Iterator(const Vector<std::unique_ptr<NGFragmentItem>>* items,
- unsigned index,
- const NGFragmentItem* item)
- : current_(item), items_(items), index_(index) {}
- const NGFragmentItem& operator*() const { return *current_; }
- const NGFragmentItem& operator->() const { return *current_; }
- Iterator& operator++();
- bool operator==(const Iterator& other) const {
- return current_ == other.current_;
- }
- bool operator!=(const Iterator& other) const {
- return current_ != other.current_;
- }
-
- private:
- const NGFragmentItem* current_;
- const Vector<std::unique_ptr<NGFragmentItem>>* items_;
- unsigned index_;
- };
- using iterator = Iterator;
- iterator begin() const {
- return Iterator(items_, first_index_, first_item_);
- }
- iterator end() const { return Iterator(nullptr, 0, nullptr); }
-
- private:
- const Vector<std::unique_ptr<NGFragmentItem>>* items_;
- const NGFragmentItem* first_item_;
- unsigned first_index_;
- };
- static ItemsForLayoutObject ItemsFor(const LayoutObject& layout_object);
static PhysicalRect LocalVisualRectFor(const LayoutObject& layout_object);
// Re-compute the ink overflow for the |cursor| until its end.
@@ -292,16 +276,21 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
return TextType() == NGTextType::kSymbolMarker;
}
- const ShapeResultView* TextShapeResult() const;
+ bool IsFormattingContextRoot() const {
+ return BoxFragment() && !IsInlineBox();
+ }
- unsigned StartOffset() const;
- unsigned EndOffset() const;
- unsigned TextLength() const { return EndOffset() - StartOffset(); }
+ const ShapeResultView* TextShapeResult() const;
+ NGTextOffset TextOffset() const;
+ unsigned StartOffset() const { return TextOffset().start; }
+ unsigned EndOffset() const { return TextOffset().end; }
+ unsigned TextLength() const { return TextOffset().Length(); }
StringView Text(const NGFragmentItems& items) const;
String GeneratedText() const {
DCHECK_EQ(Type(), kGeneratedText);
return generated_text_.text;
}
+ NGTextFragmentPaintInfo TextPaintInfo(const NGFragmentItems& items) const;
// Compute the inline position from text offset, in logical coordinate
// relative to this fragment.
@@ -338,7 +327,6 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
// Converts the given point, relative to the fragment itself, into a position
// in DOM tree.
- PositionWithAffinity PositionForPoint(const PhysicalOffset&) const;
PositionWithAffinity PositionForPointInText(
const PhysicalOffset& point,
const NGInlineCursor& cursor) const;
@@ -370,7 +358,7 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
// Note: We should not add |bidi_level_| because it is used only for layout.
unsigned type_ : 2; // ItemType
- unsigned sub_type_ : 3; // NGTextType
+ unsigned sub_type_ : 3; // NGTextType or NGLineBoxType
unsigned style_variant_ : 2; // NGStyleVariant
// TODO(yosin): We'll remove |is_generated_text_| field when we construct
// |NGFragmentItem| without |NGPhysicalTextFragment| because usage of this
@@ -383,6 +371,8 @@ class CORE_EXPORT NGFragmentItem : public DisplayItemClient {
// Used only when |IsText()| to avoid re-computing ink overflow.
unsigned ink_overflow_computed_ : 1;
+
+ unsigned is_first_for_node_ : 1;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc
index bc573b0d0d1..3e8f4853a6b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item_test.cc
@@ -8,6 +8,7 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
@@ -22,9 +23,12 @@ class NGFragmentItemTest : public NGLayoutTest,
Vector<const NGFragmentItem*> ItemsForAsVector(
const LayoutObject& layout_object) {
- const auto items = NGFragmentItem::ItemsFor(layout_object);
Vector<const NGFragmentItem*> list;
- for (const NGFragmentItem& item : items) {
+ NGInlineCursor cursor;
+ for (cursor.MoveTo(layout_object); cursor;
+ cursor.MoveToNextForSameLayoutObject()) {
+ DCHECK(cursor.Current().Item());
+ const NGFragmentItem& item = *cursor.Current().Item();
EXPECT_EQ(item.GetLayoutObject(), &layout_object);
list.push_back(&item);
}
@@ -67,12 +71,12 @@ TEST_F(NGFragmentItemTest, BasicText) {
const NGFragmentItem& text1 = *items_for_text[0];
EXPECT_EQ(text1.Type(), NGFragmentItem::kText);
EXPECT_EQ(text1.GetLayoutObject(), layout_text);
- EXPECT_EQ(text1.Offset(), PhysicalOffset());
+ EXPECT_EQ(text1.OffsetInContainerBlock(), PhysicalOffset());
const NGFragmentItem& text2 = *items_for_text[1];
EXPECT_EQ(text2.Type(), NGFragmentItem::kText);
EXPECT_EQ(text2.GetLayoutObject(), layout_text);
- EXPECT_EQ(text2.Offset(), PhysicalOffset(0, 10));
+ EXPECT_EQ(text2.OffsetInContainerBlock(), PhysicalOffset(0, 10));
EXPECT_EQ(IntRect(0, 0, 70, 20),
layout_text->FragmentsVisualRectBoundingBox());
@@ -108,7 +112,6 @@ TEST_F(NGFragmentItemTest, BasicInlineBox) {
ASSERT_NE(span1, nullptr);
Vector<const NGFragmentItem*> items_for_span1 = ItemsForAsVector(*span1);
EXPECT_EQ(items_for_span1.size(), 2u);
-
EXPECT_EQ(IntRect(0, 0, 80, 20), span1->FragmentsVisualRectBoundingBox());
// "span2" doesn't wrap, produces only one fragment.
@@ -116,8 +119,52 @@ TEST_F(NGFragmentItemTest, BasicInlineBox) {
ASSERT_NE(span2, nullptr);
Vector<const NGFragmentItem*> items_for_span2 = ItemsForAsVector(*span2);
EXPECT_EQ(items_for_span2.size(), 1u);
+ EXPECT_EQ(IntRect(0, 20, 80, 10), span2->FragmentsVisualRectBoundingBox());
+}
+// Same as |BasicInlineBox| but `<span>`s do not have background.
+// They will not need box fragments, but all operations should work the same.
+TEST_F(NGFragmentItemTest, CulledInlineBox) {
+ LoadAhem();
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ html, body {
+ margin: 0;
+ font-family: Ahem;
+ font-size: 10px;
+ line-height: 1;
+ }
+ #container {
+ width: 10ch;
+ }
+ </style>
+ <div id="container">
+ 000
+ <span id="span1">1234 5678</span>
+ 999
+ <span id="span2">12345678</span>
+ </div>
+ )HTML");
+
+ // "span1" wraps, produces two fragments.
+ const LayoutObject* span1 = GetLayoutObjectByElementId("span1");
+ ASSERT_NE(span1, nullptr);
+ Vector<const NGFragmentItem*> items_for_span1 = ItemsForAsVector(*span1);
+ EXPECT_EQ(items_for_span1.size(), 2u);
+ EXPECT_EQ(IntRect(0, 0, 80, 20), span1->FragmentsVisualRectBoundingBox());
+
+ // "span2" doesn't wrap, produces only one fragment.
+ const LayoutObject* span2 = GetLayoutObjectByElementId("span2");
+ ASSERT_NE(span2, nullptr);
+ Vector<const NGFragmentItem*> items_for_span2 = ItemsForAsVector(*span2);
+ EXPECT_EQ(items_for_span2.size(), 1u);
EXPECT_EQ(IntRect(0, 20, 80, 10), span2->FragmentsVisualRectBoundingBox());
+
+ // Except that they do not produce box fragments.
+ for (const NGFragmentItem* item : items_for_span1)
+ EXPECT_EQ(item->BoxFragment(), nullptr);
+ for (const NGFragmentItem* item : items_for_span2)
+ EXPECT_EQ(item->BoxFragment(), nullptr);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc
index 87aba81920f..794995bd7bc 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.cc
@@ -13,4 +13,35 @@ NGFragmentItems::NGFragmentItems(NGFragmentItemsBuilder* builder)
text_content_(std::move(builder->text_content_)),
first_line_text_content_(std::move(builder->first_line_text_content_)) {}
+// static
+void NGFragmentItems::AssociateWithLayoutObject(
+ Vector<std::unique_ptr<NGFragmentItem>>* items) {
+ // items_[0] can be:
+ // - kBox for list marker, e.g. <li>abc</li>
+ // - kLine for line, e.g. <div>abc</div>
+ // Calling get() is necessary below because operator<< in std::unique_ptr is
+ // a C++20 feature.
+ // TODO(https://crbug.com/980914): Drop .get() once we move to C++20.
+ DCHECK(items->IsEmpty() || (*items)[0]->IsContainer()) << (*items)[0].get();
+ HashMap<const LayoutObject*, wtf_size_t> last_fragment_map;
+ for (wtf_size_t index = 1u; index < items->size(); ++index) {
+ const NGFragmentItem& item = *(*items)[index];
+ if (item.Type() == NGFragmentItem::kLine)
+ continue;
+ LayoutObject* const layout_object = item.GetMutableLayoutObject();
+ DCHECK(layout_object->IsInLayoutNGInlineFormattingContext()) << item;
+ auto insert_result = last_fragment_map.insert(layout_object, index);
+ if (insert_result.is_new_entry) {
+ layout_object->SetFirstInlineFragmentItemIndex(index);
+ continue;
+ }
+ const wtf_size_t last_index = insert_result.stored_value->value;
+ insert_result.stored_value->value = index;
+ DCHECK_GT(last_index, 0u) << item;
+ DCHECK_LT(last_index, items->size());
+ DCHECK_LT(last_index, index);
+ (*items)[last_index]->SetDeltaToNextForSameLayoutObject(index - last_index);
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h
index fe62f758e81..76c95f180a5 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h
@@ -28,6 +28,9 @@ class CORE_EXPORT NGFragmentItems {
return UNLIKELY(first_line) ? first_line_text_content_ : text_content_;
}
+ static void AssociateWithLayoutObject(
+ Vector<std::unique_ptr<NGFragmentItem>>* items);
+
private:
// TODO(kojii): inline capacity TBD.
Vector<std::unique_ptr<NGFragmentItem>> items_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
index fd54d34056f..243c9d3622c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.cc
@@ -30,8 +30,8 @@ void NGFragmentItemsBuilder::SetCurrentLine(
void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line,
const LogicalOffset& offset) {
DCHECK_EQ(items_.size(), offsets_.size());
-#if DCHECK_IS_ON()
DCHECK(!is_converted_to_physical_);
+#if DCHECK_IS_ON()
DCHECK_EQ(current_line_fragment_, &line);
#endif
@@ -65,36 +65,40 @@ void NGFragmentItemsBuilder::AddLine(const NGPhysicalLineBoxFragment& line,
void NGFragmentItemsBuilder::AddItems(Child* child_begin, Child* child_end) {
DCHECK_EQ(items_.size(), offsets_.size());
+ DCHECK(!is_converted_to_physical_);
for (Child* child_iter = child_begin; child_iter != child_end;) {
Child& child = *child_iter;
if (const NGPhysicalTextFragment* text = child.fragment.get()) {
items_.push_back(std::make_unique<NGFragmentItem>(*text));
- offsets_.push_back(child.offset);
+ offsets_.push_back(child.rect.offset);
++child_iter;
continue;
}
- if (child.layout_result) {
+ if (child.layout_result || child.inline_item) {
// Create an item if this box has no inline children.
- const NGPhysicalBoxFragment& box =
- To<NGPhysicalBoxFragment>(child.layout_result->PhysicalFragment());
- // Floats are in the fragment tree, not in the fragment item list.
- DCHECK(!box.IsFloating());
+ std::unique_ptr<NGFragmentItem> item;
+ if (child.layout_result) {
+ const NGPhysicalBoxFragment& box =
+ To<NGPhysicalBoxFragment>(child.layout_result->PhysicalFragment());
+ item = std::make_unique<NGFragmentItem>(box, child.ResolvedDirection());
+ } else {
+ DCHECK(child.inline_item);
+ item = std::make_unique<NGFragmentItem>(
+ *child.inline_item,
+ ToPhysicalSize(child.rect.size,
+ child.inline_item->Style()->GetWritingMode()));
+ }
+ // Take the fast path when we know |child| does not have child items.
if (child.children_count <= 1) {
- // Compute |has_floating_descendants_for_paint_| to optimize tree
- // traversal in paint.
- if (!has_floating_descendants_for_paint_ && box.IsFloating())
- has_floating_descendants_for_paint_ = true;
-
- DCHECK(child.HasBidiLevel());
- items_.push_back(std::make_unique<NGFragmentItem>(
- box, 1, DirectionFromLevel(child.bidi_level)));
- offsets_.push_back(child.offset);
+ items_.push_back(std::move(item));
+ offsets_.push_back(child.rect.offset);
++child_iter;
continue;
}
+ DCHECK(!item->IsFloating());
// Children of inline boxes are flattened and added to |items_|, with the
// count of descendant items to preserve the tree structure.
@@ -102,7 +106,7 @@ void NGFragmentItemsBuilder::AddItems(Child* child_begin, Child* child_end) {
// Add an empty item so that the start of the box can be set later.
wtf_size_t box_start_index = items_.size();
items_.Grow(box_start_index + 1);
- offsets_.push_back(child.offset);
+ offsets_.push_back(child.rect.offset);
// Add all children, including their desendants, skipping this item.
CHECK_GE(child.children_count, 1u); // 0 will loop infinitely.
@@ -116,9 +120,8 @@ void NGFragmentItemsBuilder::AddItems(Child* child_begin, Child* child_end) {
wtf_size_t item_count = items_.size() - box_start_index;
// Create an item for the start of the box.
- DCHECK(child.HasBidiLevel());
- items_[box_start_index] = std::make_unique<NGFragmentItem>(
- box, item_count, DirectionFromLevel(child.bidi_level));
+ item->SetDescendantsCount(item_count);
+ items_[box_start_index] = std::move(item);
continue;
}
@@ -132,23 +135,36 @@ void NGFragmentItemsBuilder::AddItems(Child* child_begin, Child* child_end) {
void NGFragmentItemsBuilder::AddListMarker(
const NGPhysicalBoxFragment& marker_fragment,
const LogicalOffset& offset) {
+ DCHECK(!is_converted_to_physical_);
+
// Resolved direction matters only for inline items, and outside list markers
// are not inline.
const TextDirection resolved_direction = TextDirection::kLtr;
items_.push_back(
- std::make_unique<NGFragmentItem>(marker_fragment, 1, resolved_direction));
+ std::make_unique<NGFragmentItem>(marker_fragment, resolved_direction));
offsets_.push_back(offset);
}
+const Vector<std::unique_ptr<NGFragmentItem>>& NGFragmentItemsBuilder::Items(
+ WritingMode writing_mode,
+ TextDirection direction,
+ const PhysicalSize& outer_size) {
+ ConvertToPhysical(writing_mode, direction, outer_size);
+ return items_;
+}
+
// Convert internal logical offsets to physical. Items are kept with logical
// offset until outer box size is determined.
void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode,
TextDirection direction,
const PhysicalSize& outer_size) {
CHECK_EQ(items_.size(), offsets_.size());
-#if DCHECK_IS_ON()
- DCHECK(!is_converted_to_physical_);
-#endif
+ if (is_converted_to_physical_)
+ return;
+
+ // Children of lines have line-relative offsets. Use line-writing mode to
+ // convert their logical offsets.
+ const WritingMode line_writing_mode = ToLineWritingMode(writing_mode);
std::unique_ptr<NGFragmentItem>* item_iter = items_.begin();
const LogicalOffset* offset = offsets_.begin();
@@ -165,7 +181,7 @@ void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode,
unsigned descendants_count = item->DescendantsCount();
DCHECK(descendants_count);
if (descendants_count) {
- const PhysicalRect line_box_bounds = item->Rect();
+ const PhysicalRect line_box_bounds = item->RectInContainerBlock();
while (--descendants_count) {
++offset;
++item_iter;
@@ -175,7 +191,7 @@ void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode,
// Use `kLtr` because inline items are after bidi-reoder, and that
// their offset is visual, not logical.
item->SetOffset(
- offset->ConvertToPhysical(writing_mode, TextDirection::kLtr,
+ offset->ConvertToPhysical(line_writing_mode, TextDirection::kLtr,
line_box_bounds.size, item->Size()) +
line_box_bounds.offset);
}
@@ -183,9 +199,17 @@ void NGFragmentItemsBuilder::ConvertToPhysical(WritingMode writing_mode,
}
}
-#if DCHECK_IS_ON()
is_converted_to_physical_ = true;
-#endif
+}
+
+base::Optional<LogicalOffset> NGFragmentItemsBuilder::LogicalOffsetFor(
+ const LayoutObject& layout_object) const {
+ DCHECK_EQ(items_.size(), offsets_.size());
+ for (const std::unique_ptr<NGFragmentItem>& item : items_) {
+ if (item->GetLayoutObject() == &layout_object)
+ return offsets_[&item - items_.begin()];
+ }
+ return base::nullopt;
}
void NGFragmentItemsBuilder::ToFragmentItems(WritingMode writing_mode,
@@ -193,39 +217,8 @@ void NGFragmentItemsBuilder::ToFragmentItems(WritingMode writing_mode,
const PhysicalSize& outer_size,
void* data) {
ConvertToPhysical(writing_mode, direction, outer_size);
- AssociateNextForSameLayoutObject();
+ NGFragmentItems::AssociateWithLayoutObject(&items_);
new (data) NGFragmentItems(this);
}
-void NGFragmentItemsBuilder::AssociateNextForSameLayoutObject() {
- // items_[0] can be:
- // - kBox for list marker, e.g. <li>abc</li>
- // - kLine for line, e.g. <div>abc</div>
- // Calling get() is necessary below because operator<< in std::unique_ptr is
- // a C++20 feature.
- // TODO(https://crbug.com/980914): Drop .get() once we move to C++20.
- DCHECK(items_.IsEmpty() || items_[0]->IsContainer()) << items_[0].get();
- HashMap<const LayoutObject*, wtf_size_t> last_fragment_map;
- for (wtf_size_t index = 1u; index < items_.size(); ++index) {
- const NGFragmentItem& item = *items_[index];
- if (item.Type() == NGFragmentItem::kLine)
- continue;
- LayoutObject* const layout_object = item.GetMutableLayoutObject();
- DCHECK(layout_object->IsInLayoutNGInlineFormattingContext()) << item;
- auto insert_result = last_fragment_map.insert(layout_object, index);
- if (insert_result.is_new_entry) {
- // TDOO(yosin): Once we update all |LayoutObject::FirstInlineFragment()|,
- // we should enable below.
- // layout_object->SetFirstInlineFragmentItemIndex(index);
- continue;
- }
- const wtf_size_t last_index = insert_result.stored_value->value;
- insert_result.stored_value->value = index;
- DCHECK_GT(last_index, 0u) << item;
- DCHECK_LT(last_index, items_.size());
- DCHECK_LT(last_index, index);
- items_[last_index]->SetDeltaToNextForSameLayoutObject(index - last_index);
- }
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h
index eef2fc77231..84be85e4132 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h
@@ -59,10 +59,21 @@ class CORE_EXPORT NGFragmentItemsBuilder {
void AddListMarker(const NGPhysicalBoxFragment& marker_fragment,
const LogicalOffset& offset);
+ // Find |LogicalOffset| of the first |NGFragmentItem| for |LayoutObject|.
+ base::Optional<LogicalOffset> LogicalOffsetFor(const LayoutObject&) const;
+
+ // Converts the |NGFragmentItem| vector to the physical coordinate space and
+ // returns the result. This should only be used for determining the inline
+ // containing block geometry for OOF-positioned nodes.
+ //
+ // Once this method has been called, new items cannot be added.
+ const Vector<std::unique_ptr<NGFragmentItem>>&
+ Items(WritingMode, TextDirection, const PhysicalSize& outer_size);
+
// Build a |NGFragmentItems|. The builder cannot build twice because data set
// to this builder may be cleared.
- void ToFragmentItems(WritingMode writing_mode,
- TextDirection direction,
+ void ToFragmentItems(WritingMode,
+ TextDirection,
const PhysicalSize& outer_size,
void* data);
@@ -73,8 +84,6 @@ class CORE_EXPORT NGFragmentItemsBuilder {
TextDirection direction,
const PhysicalSize& outer_size);
- void AssociateNextForSameLayoutObject();
-
Vector<std::unique_ptr<NGFragmentItem>> items_;
Vector<LogicalOffset> offsets_;
String text_content_;
@@ -84,10 +93,10 @@ class CORE_EXPORT NGFragmentItemsBuilder {
ChildList current_line_;
bool has_floating_descendants_for_paint_ = false;
+ bool is_converted_to_physical_ = false;
#if DCHECK_IS_ON()
const NGPhysicalLineBoxFragment* current_line_fragment_ = nullptr;
- bool is_converted_to_physical_ = false;
#endif
friend class NGFragmentItems;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
index f2c2f03927e..cc0d8d8d3b4 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc
@@ -105,7 +105,8 @@ bool NGInlineBoxState::CanAddTextOfStyle(
NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
const ComputedStyle& line_style,
FontBaseline baseline_type,
- bool line_height_quirk) {
+ bool line_height_quirk,
+ NGLineBoxFragmentBuilder::ChildList* line_box) {
if (stack_.IsEmpty()) {
// For the first line, push a box state for the line itself.
stack_.resize(1);
@@ -114,7 +115,9 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
} else {
// For the following lines, clear states that are not shared across lines.
for (NGInlineBoxState& box : stack_) {
- box.fragment_start = 0;
+ box.fragment_start = line_box->size();
+ if (&box != stack_.begin())
+ AddBoxFragmentPlaceholder(&box, line_box, baseline_type);
if (!line_height_quirk)
box.metrics = box.text_metrics;
else
@@ -133,15 +136,15 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
DCHECK(box_data_list_.IsEmpty());
// Initialize the box state for the line box.
- NGInlineBoxState& line_box = LineBoxState();
- if (line_box.style != &line_style) {
- line_box.style = &line_style;
+ NGInlineBoxState& line_box_state = LineBoxState();
+ if (line_box_state.style != &line_style) {
+ line_box_state.style = &line_style;
// Use a "strut" (a zero-width inline box with the element's font and
// line height properties) as the initial metrics for the line box.
// https://drafts.csswg.org/css2/visudet.html#strut
if (!line_height_quirk)
- line_box.ComputeTextMetrics(line_style, baseline_type);
+ line_box_state.ComputeTextMetrics(line_style, baseline_type);
}
return &stack_.back();
@@ -150,31 +153,32 @@ NGInlineBoxState* NGInlineLayoutStateStack::OnBeginPlaceItems(
NGInlineBoxState* NGInlineLayoutStateStack::OnOpenTag(
const NGInlineItem& item,
const NGInlineItemResult& item_result,
- const NGLineBoxFragmentBuilder::ChildList& line_box) {
- DCHECK(item.Style());
- NGInlineBoxState* box = OnOpenTag(*item.Style(), line_box);
- box->item = &item;
-
- if (item.ShouldCreateBoxFragment())
- box->SetNeedsBoxFragment();
-
- // Compute box properties regardless of needs_box_fragment since close tag may
- // also set needs_box_fragment.
- box->has_start_edge = item_result.has_edge;
- box->margin_inline_start = item_result.margins.inline_start;
- box->margin_inline_end = item_result.margins.inline_end;
- box->borders = item_result.borders;
- box->padding = item_result.padding;
+ FontBaseline baseline_type,
+ NGLineBoxFragmentBuilder::ChildList* line_box) {
+ NGInlineBoxState* box =
+ OnOpenTag(item, item_result, baseline_type, *line_box);
+ box->needs_box_fragment = item.ShouldCreateBoxFragment();
+ AddBoxFragmentPlaceholder(box, line_box, baseline_type);
return box;
}
NGInlineBoxState* NGInlineLayoutStateStack::OnOpenTag(
- const ComputedStyle& style,
+ const NGInlineItem& item,
+ const NGInlineItemResult& item_result,
+ FontBaseline baseline_type,
const NGLineBoxFragmentBuilder::ChildList& line_box) {
+ DCHECK(item.Style());
+ const ComputedStyle& style = *item.Style();
stack_.resize(stack_.size() + 1);
NGInlineBoxState* box = &stack_.back();
box->fragment_start = line_box.size();
box->style = &style;
+ box->item = &item;
+ box->has_start_edge = item_result.has_edge;
+ box->margin_inline_start = item_result.margins.inline_start;
+ box->margin_inline_end = item_result.margins.inline_end;
+ box->borders = item_result.borders;
+ box->padding = item_result.padding;
return box;
}
@@ -209,9 +213,9 @@ void NGInlineLayoutStateStack::OnEndPlaceItems(
// Copy the final offset to |box_data_list_|.
for (BoxData& box_data : box_data_list_) {
const NGLineBoxFragmentBuilder::Child& placeholder =
- (*line_box)[box_data.fragment_end];
- DCHECK(!placeholder.HasFragment());
- box_data.offset = placeholder.offset;
+ (*line_box)[box_data.fragment_start];
+ DCHECK(placeholder.IsPlaceholder());
+ box_data.rect.offset = placeholder.rect.offset;
}
}
@@ -219,8 +223,13 @@ void NGInlineLayoutStateStack::EndBoxState(
NGInlineBoxState* box,
NGLineBoxFragmentBuilder::ChildList* line_box,
FontBaseline baseline_type) {
- if (box->needs_box_fragment)
- AddBoxFragmentPlaceholder(box, line_box, baseline_type);
+ if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (box->needs_box_fragment)
+ AddBoxData(box, line_box);
+ } else {
+ if (box->has_box_placeholder)
+ AddBoxData(box, line_box);
+ }
PositionPending position_pending =
ApplyBaselineShift(box, line_box, baseline_type);
@@ -237,12 +246,6 @@ void NGInlineLayoutStateStack::EndBoxState(
parent_box.metrics.Unite(box->metrics);
}
-void NGInlineBoxState::SetNeedsBoxFragment() {
- DCHECK(item);
- DCHECK(!needs_box_fragment);
- needs_box_fragment = true;
-}
-
// Crete a placeholder for a box fragment.
// We keep a flat list of fragments because it is more suitable for operations
// such as ApplyBaselineShift. Later, CreateBoxFragments() creates box fragments
@@ -251,12 +254,14 @@ void NGInlineLayoutStateStack::AddBoxFragmentPlaceholder(
NGInlineBoxState* box,
NGLineBoxFragmentBuilder::ChildList* line_box,
FontBaseline baseline_type) {
- DCHECK(box->needs_box_fragment);
+ DCHECK(box != stack_.begin() &&
+ box->item->Type() != NGInlineItem::kAtomicInline);
+ box->has_box_placeholder = true;
DCHECK(box->style);
const ComputedStyle& style = *box->style;
- LogicalOffset offset;
- LogicalSize size;
+ LayoutUnit block_offset;
+ LayoutUnit block_size;
if (!is_empty_line_) {
// The inline box should have the height of the font metrics without the
// line-height property. Compute from style because |box->metrics| includes
@@ -265,63 +270,78 @@ void NGInlineLayoutStateStack::AddBoxFragmentPlaceholder(
// Extend the block direction of the box by borders and paddings. Inline
// direction is already included into positions in NGLineBreaker.
- offset.block_offset =
+ block_offset =
-metrics.ascent - (box->borders.line_over + box->padding.line_over);
- size.block_size = metrics.LineHeight() + box->borders.BlockSum() +
- box->padding.BlockSum();
+ block_size = metrics.LineHeight() + box->borders.BlockSum() +
+ box->padding.BlockSum();
}
+ line_box->AddChild(block_offset, block_size);
+ DCHECK((*line_box)[line_box->size() - 1].IsPlaceholder());
+}
- unsigned fragment_end = line_box->size();
+// Add a |BoxData|, for each close-tag that needs a box fragment.
+void NGInlineLayoutStateStack::AddBoxData(
+ NGInlineBoxState* box,
+ NGLineBoxFragmentBuilder::ChildList* line_box) {
+ DCHECK(box->needs_box_fragment ||
+ (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled() &&
+ box->has_box_placeholder && box != stack_.begin() &&
+ box->item->Type() != NGInlineItem::kAtomicInline));
+ DCHECK(box->style);
+ const ComputedStyle& style = *box->style;
+ NGLineBoxFragmentBuilder::Child& placeholder =
+ (*line_box)[box->fragment_start];
+ DCHECK(placeholder.IsPlaceholder());
+ const unsigned fragment_end = line_box->size();
DCHECK(box->item);
BoxData& box_data = box_data_list_.emplace_back(
- box->fragment_start, fragment_end, box->item, size);
- box_data.padding = box->padding;
- if (box->has_start_edge) {
- box_data.has_line_left_edge = true;
- box_data.margin_line_left = box->margin_inline_start;
- box_data.margin_border_padding_line_left = box->margin_inline_start +
- box->borders.inline_start +
- box->padding.inline_start;
- }
- if (box->has_end_edge) {
- box_data.has_line_right_edge = true;
- box_data.margin_line_right = box->margin_inline_end;
- box_data.margin_border_padding_line_right = box->margin_inline_end +
- box->borders.inline_end +
- box->padding.inline_end;
- }
- if (IsRtl(style.Direction())) {
- std::swap(box_data.has_line_left_edge, box_data.has_line_right_edge);
- std::swap(box_data.margin_line_left, box_data.margin_line_right);
- std::swap(box_data.margin_border_padding_line_left,
- box_data.margin_border_padding_line_right);
- }
-
- if (fragment_end > box->fragment_start) {
- // The start is marked only in BoxData, while end is marked
- // in both BoxData and the list itself.
- // With a list of 4 text fragments:
- // | 0 | 1 | 2 | 3 |
- // |text0|text1|text2|text3|
- // By adding a BoxData(2,4) (end is exclusive), it becomes:
- // | 0 | 1 | 2 | 3 | 4 |
- // |text0|text1|text2|text3|null |
- // The "null" is added to the list to compute baseline shift of the box
- // separately from text fragments.
- line_box->AddChild(offset);
+ box->fragment_start, fragment_end, box->item, placeholder.Size());
+ if (box->needs_box_fragment) {
+ box_data.padding = box->padding;
+ if (box->has_start_edge) {
+ box_data.has_line_left_edge = true;
+ box_data.margin_line_left = box->margin_inline_start;
+ box_data.margin_border_padding_line_left = box->margin_inline_start +
+ box->borders.inline_start +
+ box->padding.inline_start;
+ }
+ if (box->has_end_edge) {
+ box_data.has_line_right_edge = true;
+ box_data.margin_line_right = box->margin_inline_end;
+ box_data.margin_border_padding_line_right = box->margin_inline_end +
+ box->borders.inline_end +
+ box->padding.inline_end;
+ }
+ if (IsRtl(style.Direction())) {
+ std::swap(box_data.has_line_left_edge, box_data.has_line_right_edge);
+ std::swap(box_data.margin_line_left, box_data.margin_line_right);
+ std::swap(box_data.margin_border_padding_line_left,
+ box_data.margin_border_padding_line_right);
+ }
} else {
- // Do not defer creating a box fragment if this is an empty inline box.
- // An empty box fragment is still flat that we do not have to defer.
- // Also, placeholders cannot be reordred if empty.
- offset.inline_offset += box_data.margin_line_left;
- LayoutUnit advance = box_data.margin_border_padding_line_left +
- box_data.margin_border_padding_line_right;
- box_data.size.inline_size =
- advance - box_data.margin_line_left - box_data.margin_line_right;
- line_box->AddChild(box_data.CreateBoxFragment(line_box), offset, advance,
- /* bidi_level */ 0);
- box_data_list_.pop_back();
+ DCHECK_EQ(box->margin_inline_start, 0);
+ DCHECK_EQ(box->margin_inline_end, 0);
+ DCHECK(box->padding.IsEmpty());
+ DCHECK(box->borders.IsEmpty());
}
+
+ DCHECK((*line_box)[box->fragment_start].IsPlaceholder());
+ DCHECK_GT(fragment_end, box->fragment_start);
+ if (fragment_end > box->fragment_start + 1)
+ return;
+
+ // Do not defer creating a box fragment if this is an empty inline box.
+ // An empty box fragment is still flat that we do not have to defer.
+ // Also, placeholders cannot be reordred if empty.
+ placeholder.rect.offset.inline_offset += box_data.margin_line_left;
+ LayoutUnit advance = box_data.margin_border_padding_line_left +
+ box_data.margin_border_padding_line_right;
+ box_data.rect.size.inline_size =
+ advance - box_data.margin_line_left - box_data.margin_line_right;
+ placeholder.layout_result = box_data.CreateBoxFragment(line_box);
+ placeholder.inline_size = advance;
+ DCHECK(!placeholder.children_count);
+ box_data_list_.pop_back();
}
void NGInlineLayoutStateStack::ChildInserted(unsigned index) {
@@ -348,20 +368,26 @@ void NGInlineLayoutStateStack::PrepareForReorder(
unsigned box_data_index = 0;
for (const BoxData& box_data : box_data_list_) {
box_data_index++;
+ DCHECK((*line_box)[box_data.fragment_start].IsPlaceholder());
for (unsigned i = box_data.fragment_start; i < box_data.fragment_end; i++) {
NGLineBoxFragmentBuilder::Child& child = (*line_box)[i];
- if (!child.box_data_index)
+ unsigned child_box_data_index = child.box_data_index;
+ if (!child_box_data_index) {
child.box_data_index = box_data_index;
- }
- }
+ continue;
+ }
- // When boxes are nested, placeholders have indexes to which box it should be
- // added. Copy them to BoxData.
- for (BoxData& box_data : box_data_list_) {
- const NGLineBoxFragmentBuilder::Child& placeholder =
- (*line_box)[box_data.fragment_end];
- DCHECK(!placeholder.HasFragment());
- box_data.parent_box_data_index = placeholder.box_data_index;
+ // This |box_data| has child boxes. Set up |parent_box_data_index| to
+ // represent the box nesting structure.
+ while (child_box_data_index != box_data_index) {
+ BoxData* child_box_data = &box_data_list_[child_box_data_index - 1];
+ child_box_data_index = child_box_data->parent_box_data_index;
+ if (!child_box_data_index) {
+ child_box_data->parent_box_data_index = box_data_index;
+ break;
+ }
+ }
+ }
}
}
@@ -491,8 +517,8 @@ LayoutUnit NGInlineLayoutStateStack::ComputeInlinePositions(
// origins at (0, 0). Accumulate inline offset from left to right.
LayoutUnit position;
for (NGLineBoxFragmentBuilder::Child& child : *line_box) {
- child.margin_line_left = child.offset.inline_offset;
- child.offset.inline_offset += position;
+ child.margin_line_left = child.rect.offset.inline_offset;
+ child.rect.offset.inline_offset += position;
// Box margins/boders/paddings will be processed later.
// TODO(kojii): we could optimize this if the reordering did not occur.
if (!child.HasFragment())
@@ -538,7 +564,7 @@ LayoutUnit NGInlineLayoutStateStack::ComputeInlinePositions(
unsigned start = box_data.fragment_start;
NGLineBoxFragmentBuilder::Child& start_child = (*line_box)[start];
LayoutUnit line_left_offset =
- start_child.offset.inline_offset - start_child.margin_line_left;
+ start_child.rect.offset.inline_offset - start_child.margin_line_left;
LinePadding& start_padding = accumulated_padding[start];
start_padding.line_left += box_data.margin_border_padding_line_left;
line_left_offset -= start_padding.line_left - box_data.margin_line_left;
@@ -546,15 +572,15 @@ LayoutUnit NGInlineLayoutStateStack::ComputeInlinePositions(
DCHECK_GT(box_data.fragment_end, start);
unsigned last = box_data.fragment_end - 1;
NGLineBoxFragmentBuilder::Child& last_child = (*line_box)[last];
- LayoutUnit line_right_offset = last_child.offset.inline_offset -
+ LayoutUnit line_right_offset = last_child.rect.offset.inline_offset -
last_child.margin_line_left +
last_child.inline_size;
LinePadding& last_padding = accumulated_padding[last];
last_padding.line_right += box_data.margin_border_padding_line_right;
line_right_offset += last_padding.line_right - box_data.margin_line_right;
- box_data.offset.inline_offset = line_left_offset;
- box_data.size.inline_size = line_right_offset - line_left_offset;
+ box_data.rect.offset.inline_offset = line_left_offset;
+ box_data.rect.size.inline_size = line_right_offset - line_left_offset;
}
return position;
@@ -569,24 +595,38 @@ void NGInlineLayoutStateStack::CreateBoxFragments(
unsigned end = box_data.fragment_end;
DCHECK_GT(end, start);
NGLineBoxFragmentBuilder::Child* child = &(*line_box)[start];
+ if (box_data.item->ShouldCreateBoxFragment()) {
+ scoped_refptr<const NGLayoutResult> box_fragment =
+ box_data.CreateBoxFragment(line_box);
+ if (child->IsPlaceholder()) {
+ child->layout_result = std::move(box_fragment);
+ child->rect = box_data.rect;
+ child->children_count = end - start;
+ continue;
+ }
- scoped_refptr<const NGLayoutResult> box_fragment =
- box_data.CreateBoxFragment(line_box);
- if (!child->HasFragment()) {
- child->layout_result = std::move(box_fragment);
- child->offset = box_data.offset;
- child->children_count = end - start;
- } else {
- // In most cases, |start_child| is moved to the children of the box, and
- // is empty. It's not empty when it's out-of-flow. Insert in such case.
- // TODO(kojii): With |NGFragmentItem|, all cases hit this code. Consider
- // creating an empty item beforehand to avoid inserting.
- line_box->InsertChild(start, std::move(box_fragment), box_data.offset,
- LayoutUnit(), 0);
+ // |AddBoxFragmentPlaceholder| adds a placeholder at |fragment_start|, but
+ // bidi reordering may move it. Insert in such case.
+ line_box->InsertChild(start, std::move(box_fragment), box_data.rect,
+ end - start + 1);
ChildInserted(start + 1);
- child = &(*line_box)[start];
- child->children_count = end - start + 1;
+ continue;
+ }
+
+ DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
+ DCHECK(box_data.item);
+ if (child->IsPlaceholder()) {
+ child->inline_item = box_data.item;
+ child->rect = box_data.rect;
+ child->children_count = end - start;
+ continue;
}
+
+ // |AddBoxFragmentPlaceholder| adds a placeholder at |fragment_start|, but
+ // bidi reordering may move it. Insert in such case.
+ line_box->InsertChild(start, *box_data.item, box_data.rect,
+ end - start + 1);
+ ChildInserted(start + 1);
}
box_data_list_.clear();
@@ -600,8 +640,8 @@ NGInlineLayoutStateStack::BoxData::CreateBoxFragment(
const ComputedStyle& style = *item->Style();
NGFragmentGeometry fragment_geometry;
- fragment_geometry.border_box_size = {size.inline_size.ClampNegativeToZero(),
- size.block_size};
+ fragment_geometry.border_box_size = {
+ rect.size.inline_size.ClampNegativeToZero(), rect.size.block_size};
fragment_geometry.padding =
NGBoxStrut(padding, IsFlippedLinesWritingMode(style.GetWritingMode()));
@@ -618,6 +658,8 @@ NGInlineLayoutStateStack::BoxData::CreateBoxFragment(
// supported today.
box.SetBorderEdges({true, has_line_right_edge, true, has_line_left_edge});
+ box.SetIsFirstForNode(has_line_left_edge);
+
for (unsigned i = fragment_start; i < fragment_end; i++) {
NGLineBoxFragmentBuilder::Child& child = (*line_box)[i];
if (child.out_of_flow_positioned_box) {
@@ -627,7 +669,7 @@ NGInlineLayoutStateStack::BoxData::CreateBoxFragment(
// child.offset is the static position wrt. the linebox. As we are adding
// this as a child of an inline level fragment, we adjust the static
// position to be relative to this fragment.
- LogicalOffset static_offset = child.offset - offset;
+ LogicalOffset static_offset = child.rect.offset - rect.offset;
box.AddOutOfFlowInlineChildCandidate(oof_box, static_offset,
child.container_direction);
@@ -636,24 +678,33 @@ NGInlineLayoutStateStack::BoxData::CreateBoxFragment(
}
if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
- // |NGFragmentItems| has a flat list of all descendants, except OOF
- // objects. Still creates |NGPhysicalBoxFragment|, but don't add children
- // to it and keep them in the flat list.
+ // Propagate any OOF-positioned descendants from any atomic-inlines, etc.
+ if (child.layout_result) {
+ box.PropagateChildData(child.layout_result->PhysicalFragment(),
+ child.rect.offset - rect.offset);
+ }
+
+ // |NGFragmentItems| has a flat list of all descendants, except
+ // OOF-positioned descendants.
+ // We still create a |NGPhysicalBoxFragment|, but don't add children to
+ // it and keep them in the flat list.
continue;
}
if (child.layout_result) {
box.AddChild(child.layout_result->PhysicalFragment(),
- child.offset - offset);
+ child.rect.offset - rect.offset);
child.layout_result.reset();
} else if (child.fragment) {
- box.AddChild(std::move(child.fragment), child.offset - offset);
+ box.AddChild(std::move(child.fragment), child.rect.offset - rect.offset);
}
}
- // Inline boxes that produce DisplayItemClient should do full paint
- // invalidations.
- item->GetLayoutObject()->SetShouldDoFullPaintInvalidation();
+ if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ // Inline boxes that produce DisplayItemClient should do full paint
+ // invalidations.
+ item->GetLayoutObject()->SetShouldDoFullPaintInvalidation();
+ }
box.MoveOutOfFlowDescendantCandidatesToDescendants();
return box.ToInlineBoxFragment();
@@ -826,10 +877,12 @@ NGLineHeightMetrics NGInlineLayoutStateStack::MetricsForTopAndBottomAlign(
continue;
// |block_offset| is the top position when the baseline is at 0.
- LayoutUnit box_ascent =
- -line_box[box_data.fragment_end].offset.block_offset;
+ const NGLineBoxFragmentBuilder::Child& placeholder =
+ line_box[box_data.fragment_start];
+ DCHECK(placeholder.IsPlaceholder());
+ LayoutUnit box_ascent = -placeholder.rect.offset.block_offset;
NGLineHeightMetrics box_metrics(box_ascent,
- box_data.size.block_size - box_ascent);
+ box_data.rect.size.block_size - box_ascent);
// The top/bottom of inline boxes should not include their paddings.
box_metrics.ascent -= box_data.padding.line_over;
box_metrics.descent -= box_data.padding.line_under;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
index 066225e80ec..2431f010067 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_BOX_STATE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_BOX_STATE_H_
-#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
+#include "third_party/blink/renderer/core/layout/geometry/logical_rect.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
@@ -67,6 +67,7 @@ struct NGInlineBoxState {
Vector<NGPendingPositions> pending_descendants;
bool include_used_fonts = false;
+ bool has_box_placeholder = false;
bool needs_box_fragment = false;
// True if this box has a metrics, including pending ones. Pending metrics
@@ -88,9 +89,6 @@ struct NGInlineBoxState {
// 'text-top' offset for 'vertical-align'.
LayoutUnit TextTop(FontBaseline baseline_type) const;
- // Create a box fragment for this box.
- void SetNeedsBoxFragment();
-
// Returns if the text style can be added without open-tag.
// Text with different font or vertical-align needs to be wrapped with an
// inline box.
@@ -116,14 +114,22 @@ class CORE_EXPORT NGInlineLayoutStateStack {
// Initialize the box state stack for a new line.
// @return The initial box state for the line.
- NGInlineBoxState* OnBeginPlaceItems(const ComputedStyle&, FontBaseline, bool);
+ NGInlineBoxState* OnBeginPlaceItems(
+ const ComputedStyle&,
+ FontBaseline,
+ bool line_height_quirk,
+ NGLineBoxFragmentBuilder::ChildList* line_box);
// Push a box state stack.
NGInlineBoxState* OnOpenTag(const NGInlineItem&,
const NGInlineItemResult&,
+ FontBaseline baseline_type,
const NGLineBoxFragmentBuilder::ChildList&);
- NGInlineBoxState* OnOpenTag(const ComputedStyle&,
- const NGLineBoxFragmentBuilder::ChildList&);
+ // This variation adds a box placeholder to |line_box|.
+ NGInlineBoxState* OnOpenTag(const NGInlineItem&,
+ const NGInlineItemResult&,
+ FontBaseline baseline_type,
+ NGLineBoxFragmentBuilder::ChildList* line_box);
// Pop a box state stack.
NGInlineBoxState* OnCloseTag(NGLineBoxFragmentBuilder::ChildList*,
@@ -182,6 +188,7 @@ class CORE_EXPORT NGInlineLayoutStateStack {
void AddBoxFragmentPlaceholder(NGInlineBoxState*,
NGLineBoxFragmentBuilder::ChildList*,
FontBaseline);
+ void AddBoxData(NGInlineBoxState*, NGLineBoxFragmentBuilder::ChildList*);
enum PositionPending { kPositionNotPending, kPositionPending };
@@ -208,14 +215,16 @@ class CORE_EXPORT NGInlineLayoutStateStack {
unsigned end,
const NGInlineItem* item,
LogicalSize size)
- : fragment_start(start), fragment_end(end), item(item), size(size) {}
+ : fragment_start(start),
+ fragment_end(end),
+ item(item),
+ rect(LogicalOffset(), size) {}
BoxData(const BoxData& other, unsigned start, unsigned end)
: fragment_start(start),
fragment_end(end),
item(other.item),
- size(other.size),
- offset(other.offset) {}
+ rect(other.rect) {}
void SetFragmentRange(unsigned start_index, unsigned end_index) {
fragment_start = start_index;
@@ -227,7 +236,7 @@ class CORE_EXPORT NGInlineLayoutStateStack {
unsigned fragment_end;
const NGInlineItem* item;
- LogicalSize size;
+ LogicalRect rect;
bool has_line_left_edge = false;
bool has_line_right_edge = false;
@@ -238,7 +247,6 @@ class CORE_EXPORT NGInlineLayoutStateStack {
LayoutUnit margin_border_padding_line_left;
LayoutUnit margin_border_padding_line_right;
- LogicalOffset offset;
unsigned parent_box_data_index = 0;
unsigned fragmented_box_data_index = 0;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc
index 3a9b6f7814d..0485ed7dbb4 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.cc
@@ -22,6 +22,7 @@ static_assert(sizeof(NGInlineBreakToken) ==
} // namespace
NGInlineBreakToken::NGInlineBreakToken(
+ PassKey key,
NGInlineNode node,
const ComputedStyle* style,
unsigned item_index,
@@ -34,7 +35,7 @@ NGInlineBreakToken::NGInlineBreakToken(
flags_ = flags;
}
-NGInlineBreakToken::NGInlineBreakToken(NGLayoutInputNode node)
+NGInlineBreakToken::NGInlineBreakToken(PassKey key, NGLayoutInputNode node)
: NGBreakToken(kInlineBreakToken, kFinished, node),
item_index_(0),
text_offset_(0) {}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h
index fdf2ebdccde..6558270e9cd 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h
@@ -31,13 +31,13 @@ class CORE_EXPORT NGInlineBreakToken final : public NGBreakToken {
unsigned item_index,
unsigned text_offset,
unsigned flags /* NGInlineBreakTokenFlags */) {
- return base::AdoptRef(
- new NGInlineBreakToken(node, style, item_index, text_offset, flags));
+ return base::AdoptRef(new NGInlineBreakToken(
+ PassKey(), node, style, item_index, text_offset, flags));
}
// Creates a break token for a node which cannot produce any more fragments.
static scoped_refptr<NGInlineBreakToken> Create(NGLayoutInputNode node) {
- return base::AdoptRef(new NGInlineBreakToken(node));
+ return base::AdoptRef(new NGInlineBreakToken(PassKey(), node));
}
~NGInlineBreakToken() override;
@@ -69,19 +69,21 @@ class CORE_EXPORT NGInlineBreakToken final : public NGBreakToken {
return flags_ & kIsForcedBreak;
}
-#if DCHECK_IS_ON()
- String ToString() const override;
-#endif
-
- private:
- NGInlineBreakToken(NGInlineNode node,
+ using PassKey = util::PassKey<NGInlineBreakToken>;
+ NGInlineBreakToken(PassKey,
+ NGInlineNode node,
const ComputedStyle*,
unsigned item_index,
unsigned text_offset,
unsigned flags /* NGInlineBreakTokenFlags */);
- explicit NGInlineBreakToken(NGLayoutInputNode node);
+ explicit NGInlineBreakToken(PassKey, NGLayoutInputNode node);
+#if DCHECK_IS_ON()
+ String ToString() const override;
+#endif
+
+ private:
scoped_refptr<const ComputedStyle> style_;
unsigned item_index_;
unsigned text_offset_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
index df7664e661e..bb39e1b44f1 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.cc
@@ -18,8 +18,8 @@ namespace blink {
void NGInlineCursor::MoveToItem(const ItemsSpan::iterator& iter) {
DCHECK(IsItemCursor());
DCHECK(iter >= items_.begin() && iter <= items_.end());
- item_iter_ = iter;
- current_item_ = iter == items_.end() ? nullptr : iter->get();
+ current_.item_iter_ = iter;
+ current_.item_ = iter == items_.end() ? nullptr : iter->get();
}
void NGInlineCursor::SetRoot(const NGFragmentItems& fragment_items,
@@ -28,6 +28,8 @@ void NGInlineCursor::SetRoot(const NGFragmentItems& fragment_items,
DCHECK(!HasRoot());
fragment_items_ = &fragment_items;
items_ = items;
+ DCHECK(items_.empty() || (items_.data() >= fragment_items_->Items().data() &&
+ items_.data() < fragment_items_->Items().end()));
MoveToItem(items_.begin());
}
@@ -39,7 +41,7 @@ void NGInlineCursor::SetRoot(const NGPaintFragment& root_paint_fragment) {
DCHECK(&root_paint_fragment);
DCHECK(!HasRoot());
root_paint_fragment_ = &root_paint_fragment;
- current_paint_fragment_ = root_paint_fragment.FirstChild();
+ current_.paint_fragment_ = root_paint_fragment.FirstChild();
}
void NGInlineCursor::SetRoot(const LayoutBlockFlow& block_flow) {
@@ -80,28 +82,22 @@ NGInlineCursor::NGInlineCursor(const NGPaintFragment& root_paint_fragment) {
SetRoot(root_paint_fragment);
}
-NGInlineCursor::NGInlineCursor(const NGInlineCursor& other)
- : items_(other.items_),
- item_iter_(other.item_iter_),
- current_item_(other.current_item_),
- fragment_items_(other.fragment_items_),
- root_paint_fragment_(other.root_paint_fragment_),
- current_paint_fragment_(other.current_paint_fragment_),
- layout_inline_(other.layout_inline_) {}
-
-NGInlineCursor::NGInlineCursor() = default;
+NGInlineCursor::NGInlineCursor(const NGInlineBackwardCursor& backward_cursor)
+ : NGInlineCursor(backward_cursor.cursor_) {
+ MoveTo(backward_cursor.Current());
+}
bool NGInlineCursor::operator==(const NGInlineCursor& other) const {
if (root_paint_fragment_) {
return root_paint_fragment_ == other.root_paint_fragment_ &&
- current_paint_fragment_ == other.current_paint_fragment_;
+ current_.paint_fragment_ == other.current_.paint_fragment_;
}
- if (current_item_ != other.current_item_)
+ if (current_.item_ != other.current_.item_)
return false;
DCHECK_EQ(items_.data(), other.items_.data());
DCHECK_EQ(items_.size(), other.items_.size());
DCHECK_EQ(fragment_items_, other.fragment_items_);
- DCHECK(item_iter_ == other.item_iter_);
+ DCHECK(current_.item_iter_ == other.current_.item_iter_);
return true;
}
@@ -122,34 +118,35 @@ const LayoutBlockFlow* NGInlineCursor::GetLayoutBlockFlow() const {
return layout_object->RootInlineFormattingContext();
}
if (IsItemCursor()) {
- for (const auto& item : items_) {
- const LayoutObject* layout_object = item->GetLayoutObject();
- if (layout_object && layout_object->IsInline())
- return layout_object->RootInlineFormattingContext();
- }
+ const NGFragmentItem& item = *fragment_items_->Items().front();
+ const LayoutObject* layout_object = item.GetLayoutObject();
+ if (item.Type() == NGFragmentItem::kLine)
+ return To<LayoutBlockFlow>(layout_object);
+ return layout_object->RootInlineFormattingContext();
}
NOTREACHED();
return nullptr;
}
bool NGInlineCursor::HasChildren() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->FirstChild();
- if (current_item_)
- return current_item_->HasChildren();
+ if (current_.paint_fragment_)
+ return current_.paint_fragment_->FirstChild();
+ if (current_.item_)
+ return current_.item_->HasChildren();
NOTREACHED();
return false;
}
NGInlineCursor NGInlineCursor::CursorForDescendants() const {
- if (current_paint_fragment_)
- return NGInlineCursor(*current_paint_fragment_);
- if (current_item_) {
- unsigned descendants_count = current_item_->DescendantsCount();
+ if (current_.paint_fragment_)
+ return NGInlineCursor(*current_.paint_fragment_);
+ if (current_.item_) {
+ unsigned descendants_count = current_.item_->DescendantsCount();
if (descendants_count > 1) {
DCHECK(fragment_items_);
- return NGInlineCursor(*fragment_items_, ItemsSpan(&*(item_iter_ + 1),
- descendants_count - 1));
+ return NGInlineCursor(
+ *fragment_items_,
+ ItemsSpan(&*(current_.item_iter_ + 1), descendants_count - 1));
}
return NGInlineCursor();
}
@@ -157,96 +154,119 @@ NGInlineCursor NGInlineCursor::CursorForDescendants() const {
return NGInlineCursor();
}
+void NGInlineCursor::ExpandRootToContainingBlock() {
+ if (root_paint_fragment_) {
+ root_paint_fragment_ = root_paint_fragment_->Root();
+ return;
+ }
+ if (fragment_items_) {
+ const unsigned index_diff = items_.data() - fragment_items_->Items().data();
+ DCHECK_LT(index_diff, fragment_items_->Items().size());
+ const unsigned item_index = current_.item_iter_ - items_.begin();
+ items_ = fragment_items_->Items();
+ // Update the iterator to the one for the new span.
+ MoveToItem(items_.begin() + item_index + index_diff);
+ return;
+ }
+ NOTREACHED();
+}
+
bool NGInlineCursor::HasSoftWrapToNextLine() const {
- DCHECK(IsLineBox());
- const NGInlineBreakToken& break_token = CurrentInlineBreakToken();
- return !break_token.IsFinished() && !break_token.IsForcedBreak();
+ DCHECK(Current().IsLineBox());
+ const NGInlineBreakToken* break_token = Current().InlineBreakToken();
+ DCHECK(break_token);
+ return !break_token->IsFinished() && !break_token->IsForcedBreak();
}
-bool NGInlineCursor::IsAtomicInline() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->PhysicalFragment().IsAtomicInline();
- if (current_item_)
- return current_item_->IsAtomicInline();
+bool NGInlineCursorPosition::IsInlineBox() const {
+ if (paint_fragment_)
+ return paint_fragment_->PhysicalFragment().IsInlineBox();
+ if (item_)
+ return item_->IsInlineBox();
NOTREACHED();
return false;
}
-bool NGInlineCursor::IsEllipsis() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->IsEllipsis();
- if (current_item_)
- return current_item_->IsEllipsis();
+bool NGInlineCursorPosition::IsAtomicInline() const {
+ if (paint_fragment_)
+ return paint_fragment_->PhysicalFragment().IsAtomicInline();
+ if (item_)
+ return item_->IsAtomicInline();
NOTREACHED();
return false;
}
-bool NGInlineCursor::IsGeneratedText() const {
- if (current_paint_fragment_) {
+bool NGInlineCursorPosition::IsEllipsis() const {
+ if (paint_fragment_)
+ return paint_fragment_->IsEllipsis();
+ if (item_)
+ return item_->IsEllipsis();
+ NOTREACHED();
+ return false;
+}
+
+bool NGInlineCursorPosition::IsGeneratedText() const {
+ if (paint_fragment_) {
if (auto* text_fragment = DynamicTo<NGPhysicalTextFragment>(
- current_paint_fragment_->PhysicalFragment()))
+ paint_fragment_->PhysicalFragment()))
return text_fragment->IsGeneratedText();
return false;
}
- if (current_item_)
- return current_item_->IsGeneratedText();
+ if (item_)
+ return item_->IsGeneratedText();
NOTREACHED();
return false;
}
-bool NGInlineCursor::IsGeneratedTextType() const {
- if (current_paint_fragment_) {
+bool NGInlineCursorPosition::IsGeneratedTextType() const {
+ if (paint_fragment_) {
if (auto* text_fragment = DynamicTo<NGPhysicalTextFragment>(
- current_paint_fragment_->PhysicalFragment())) {
+ paint_fragment_->PhysicalFragment())) {
return text_fragment->TextType() ==
NGPhysicalTextFragment::kGeneratedText;
}
return false;
}
- if (current_item_)
- return current_item_->Type() == NGFragmentItem::kGeneratedText;
+ if (item_)
+ return item_->Type() == NGFragmentItem::kGeneratedText;
NOTREACHED();
return false;
}
-bool NGInlineCursor::IsHiddenForPaint() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->PhysicalFragment().IsHiddenForPaint();
- if (current_item_)
- return current_item_->IsHiddenForPaint();
+bool NGInlineCursorPosition::IsHiddenForPaint() const {
+ if (paint_fragment_)
+ return paint_fragment_->PhysicalFragment().IsHiddenForPaint();
+ if (item_)
+ return item_->IsHiddenForPaint();
NOTREACHED();
return false;
}
-bool NGInlineCursor::IsHorizontal() const {
- return CurrentStyle().GetWritingMode() == WritingMode::kHorizontalTb;
-}
-
bool NGInlineCursor::IsInlineLeaf() const {
- if (IsHiddenForPaint())
+ if (Current().IsHiddenForPaint())
return false;
- if (IsText())
- return !IsGeneratedTextType();
- if (!IsAtomicInline())
+ if (Current().IsText())
+ return !Current().IsGeneratedTextType();
+ if (!Current().IsAtomicInline())
return false;
- return !IsListMarker();
+ return !Current().IsListMarker();
}
bool NGInlineCursor::IsPartOfCulledInlineBox(
const LayoutInline& layout_inline) const {
- const LayoutObject* const layout_object = CurrentLayoutObject();
+ const LayoutObject* const layout_object = Current().GetLayoutObject();
// We use |IsInline()| to exclude floating and out-of-flow objects.
if (!layout_object || !layout_object->IsInline() ||
layout_object->IsAtomicInlineLevel())
return false;
DCHECK(!layout_object->IsFloatingOrOutOfFlowPositioned());
- DCHECK(!CurrentBoxFragment() ||
- !CurrentBoxFragment()->IsBlockFormattingContextRoot());
+ DCHECK(!Current().BoxFragment() ||
+ !Current().BoxFragment()->IsFormattingContextRoot());
return layout_object->IsDescendantOf(&layout_inline);
}
bool NGInlineCursor::IsLastLineInInlineBlock() const {
- DCHECK(IsLineBox());
+ DCHECK(Current().IsLineBox());
if (!GetLayoutBlockFlow()->IsAtomicInlineLevel())
return false;
NGInlineCursor next_sibling(*this);
@@ -254,45 +274,45 @@ bool NGInlineCursor::IsLastLineInInlineBlock() const {
next_sibling.MoveToNextSibling();
if (!next_sibling)
return true;
- if (next_sibling.IsLineBox())
+ if (next_sibling.Current().IsLineBox())
return false;
// There maybe other top-level objects such as floats, OOF, or list-markers.
}
}
-bool NGInlineCursor::IsLineBreak() const {
- if (current_paint_fragment_) {
+bool NGInlineCursorPosition::IsLineBreak() const {
+ if (paint_fragment_) {
if (auto* text_fragment = DynamicTo<NGPhysicalTextFragment>(
- current_paint_fragment_->PhysicalFragment()))
+ paint_fragment_->PhysicalFragment()))
return text_fragment->IsLineBreak();
return false;
}
- if (current_item_)
- return IsText() && current_item_->IsLineBreak();
+ if (item_)
+ return IsText() && item_->IsLineBreak();
NOTREACHED();
return false;
}
-bool NGInlineCursor::IsListMarker() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->PhysicalFragment().IsListMarker();
- if (current_item_)
- return current_item_->IsListMarker();
+bool NGInlineCursorPosition::IsListMarker() const {
+ if (paint_fragment_)
+ return paint_fragment_->PhysicalFragment().IsListMarker();
+ if (item_)
+ return item_->IsListMarker();
NOTREACHED();
return false;
}
-bool NGInlineCursor::IsText() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->PhysicalFragment().IsText();
- if (current_item_)
- return current_item_->IsText();
+bool NGInlineCursorPosition::IsText() const {
+ if (paint_fragment_)
+ return paint_fragment_->PhysicalFragment().IsText();
+ if (item_)
+ return item_->IsText();
NOTREACHED();
return false;
}
bool NGInlineCursor::IsBeforeSoftLineBreak() const {
- if (IsLineBreak())
+ if (Current().IsLineBreak())
return false;
// Inline block is not be container line box.
// See paint/selection/text-selection-inline-block.html.
@@ -315,57 +335,55 @@ bool NGInlineCursor::IsBeforeSoftLineBreak() const {
// Even If |fragment| is before linebreak, if its direction differs to line
// direction, we don't paint line break. See
// paint/selection/text-selection-newline-mixed-ltr-rtl.html.
- return line.CurrentBaseDirection() == CurrentResolvedDirection();
+ return line.Current().BaseDirection() == Current().ResolvedDirection();
}
bool NGInlineCursor::CanHaveChildren() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->PhysicalFragment().IsContainer();
- if (current_item_) {
- return current_item_->Type() == NGFragmentItem::kLine ||
- (current_item_->Type() == NGFragmentItem::kBox &&
- !current_item_->IsAtomicInline());
+ if (current_.paint_fragment_)
+ return current_.paint_fragment_->PhysicalFragment().IsContainer();
+ if (current_.item_) {
+ return current_.item_->Type() == NGFragmentItem::kLine ||
+ (current_.item_->Type() == NGFragmentItem::kBox &&
+ !current_.item_->IsAtomicInline());
}
NOTREACHED();
return false;
}
-bool NGInlineCursor::IsEmptyLineBox() const {
+bool NGInlineCursorPosition::IsEmptyLineBox() const {
DCHECK(IsLineBox());
- if (current_paint_fragment_) {
- return To<NGPhysicalLineBoxFragment>(
- current_paint_fragment_->PhysicalFragment())
+ if (paint_fragment_) {
+ return To<NGPhysicalLineBoxFragment>(paint_fragment_->PhysicalFragment())
.IsEmptyLineBox();
}
- if (current_item_)
- return current_item_->IsEmptyLineBox();
+ if (item_)
+ return item_->IsEmptyLineBox();
NOTREACHED();
return false;
}
-bool NGInlineCursor::IsLineBox() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->PhysicalFragment().IsLineBox();
- if (current_item_)
- return current_item_->Type() == NGFragmentItem::kLine;
+bool NGInlineCursorPosition::IsLineBox() const {
+ if (paint_fragment_)
+ return paint_fragment_->PhysicalFragment().IsLineBox();
+ if (item_)
+ return item_->Type() == NGFragmentItem::kLine;
NOTREACHED();
return false;
}
-TextDirection NGInlineCursor::CurrentBaseDirection() const {
+TextDirection NGInlineCursorPosition::BaseDirection() const {
DCHECK(IsLineBox());
- if (current_paint_fragment_) {
- return To<NGPhysicalLineBoxFragment>(
- current_paint_fragment_->PhysicalFragment())
+ if (paint_fragment_) {
+ return To<NGPhysicalLineBoxFragment>(paint_fragment_->PhysicalFragment())
.BaseDirection();
}
- if (current_item_)
- return current_item_->BaseDirection();
+ if (item_)
+ return item_->BaseDirection();
NOTREACHED();
return TextDirection::kLtr;
}
-UBiDiLevel NGInlineCursor::CurrentBidiLevel() const {
+UBiDiLevel NGInlineCursorPosition::BidiLevel() const {
if (IsText()) {
if (IsGeneratedTextType()) {
// TODO(yosin): Until we have clients, we don't support bidi-level for
@@ -373,17 +391,18 @@ UBiDiLevel NGInlineCursor::CurrentBidiLevel() const {
NOTREACHED() << this;
return 0;
}
- const LayoutText& layout_text = *ToLayoutText(CurrentLayoutObject());
+ const LayoutText& layout_text = *ToLayoutText(GetLayoutObject());
DCHECK(!layout_text.NeedsLayout()) << this;
const auto* const items = layout_text.GetNGInlineItems();
if (!items || items->size() == 0) {
// In case of <br>, <wbr>, text-combine-upright, etc.
return 0;
}
+ const NGTextOffset offset = TextOffset();
const auto& item = std::find_if(
- items->begin(), items->end(), [this](const NGInlineItem& item) {
- return item.StartOffset() <= CurrentTextStartOffset() &&
- item.EndOffset() >= CurrentTextEndOffset();
+ items->begin(), items->end(), [offset](const NGInlineItem& item) {
+ return item.StartOffset() <= offset.start &&
+ item.EndOffset() >= offset.end;
});
DCHECK(item != items->end()) << this;
return item->BidiLevel();
@@ -391,13 +410,13 @@ UBiDiLevel NGInlineCursor::CurrentBidiLevel() const {
if (IsAtomicInline()) {
const NGPhysicalBoxFragment* fragmentainer =
- CurrentLayoutObject()->ContainingBlockFlowFragment();
+ GetLayoutObject()->ContainingBlockFlowFragment();
DCHECK(fragmentainer);
const LayoutBlockFlow& block_flow =
*To<LayoutBlockFlow>(fragmentainer->GetLayoutObject());
const Vector<NGInlineItem> items =
block_flow.GetNGInlineNodeData()->ItemsData(UsesFirstLineStyle()).items;
- const LayoutObject* const layout_object = CurrentLayoutObject();
+ const LayoutObject* const layout_object = GetLayoutObject();
const auto* const item = std::find_if(
items.begin(), items.end(), [layout_object](const NGInlineItem& item) {
return item.GetLayoutObject() == layout_object;
@@ -410,237 +429,469 @@ UBiDiLevel NGInlineCursor::CurrentBidiLevel() const {
return 0;
}
-const NGPhysicalBoxFragment* NGInlineCursor::CurrentBoxFragment() const {
- if (current_paint_fragment_) {
+const NGPhysicalBoxFragment* NGInlineCursorPosition::BoxFragment() const {
+ if (paint_fragment_) {
return DynamicTo<NGPhysicalBoxFragment>(
- &current_paint_fragment_->PhysicalFragment());
+ &paint_fragment_->PhysicalFragment());
}
- if (current_item_)
- return current_item_->BoxFragment();
+ if (item_)
+ return item_->BoxFragment();
NOTREACHED();
return nullptr;
}
-const DisplayItemClient* NGInlineCursor::CurrentDisplayItemClient() const {
- if (current_paint_fragment_)
- return current_paint_fragment_;
- if (current_item_)
- return current_item_;
+const DisplayItemClient* NGInlineCursorPosition::GetDisplayItemClient() const {
+ if (paint_fragment_)
+ return paint_fragment_;
+ if (item_)
+ return item_;
NOTREACHED();
return nullptr;
}
-const NGInlineBreakToken& NGInlineCursor::CurrentInlineBreakToken() const {
+const NGInlineBreakToken* NGInlineCursorPosition::InlineBreakToken() const {
DCHECK(IsLineBox());
- if (current_paint_fragment_) {
+ if (paint_fragment_) {
return To<NGInlineBreakToken>(
- *To<NGPhysicalLineBoxFragment>(
- current_paint_fragment_->PhysicalFragment())
- .BreakToken());
+ To<NGPhysicalLineBoxFragment>(paint_fragment_->PhysicalFragment())
+ .BreakToken());
}
- DCHECK(current_item_);
- return *current_item_->InlineBreakToken();
+ DCHECK(item_);
+ return item_->InlineBreakToken();
}
-const LayoutObject* NGInlineCursor::CurrentLayoutObject() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->GetLayoutObject();
- if (current_item_)
- return current_item_->GetLayoutObject();
+const LayoutObject* NGInlineCursorPosition::GetLayoutObject() const {
+ if (paint_fragment_)
+ return paint_fragment_->GetLayoutObject();
+ if (item_)
+ return item_->GetLayoutObject();
NOTREACHED();
return nullptr;
}
-LayoutObject* NGInlineCursor::CurrentMutableLayoutObject() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->GetMutableLayoutObject();
- if (current_item_)
- return current_item_->GetMutableLayoutObject();
+LayoutObject* NGInlineCursorPosition::GetMutableLayoutObject() const {
+ if (paint_fragment_)
+ return paint_fragment_->GetMutableLayoutObject();
+ if (item_)
+ return item_->GetMutableLayoutObject();
NOTREACHED();
return nullptr;
}
-Node* NGInlineCursor::CurrentNode() const {
- if (const LayoutObject* layout_object = CurrentLayoutObject())
+const Node* NGInlineCursorPosition::GetNode() const {
+ if (const LayoutObject* layout_object = GetLayoutObject())
return layout_object->GetNode();
return nullptr;
}
-const PhysicalRect NGInlineCursor::CurrentInkOverflow() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->InkOverflow();
- if (current_item_)
- return current_item_->InkOverflow();
+const PhysicalRect NGInlineCursorPosition::InkOverflow() const {
+ if (paint_fragment_)
+ return paint_fragment_->InkOverflow();
+ if (item_)
+ return item_->InkOverflow();
NOTREACHED();
return PhysicalRect();
}
-const PhysicalOffset NGInlineCursor::CurrentOffset() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->InlineOffsetToContainerBox();
- if (current_item_)
- return current_item_->Offset();
+const PhysicalOffset NGInlineCursorPosition::OffsetInContainerBlock() const {
+ if (paint_fragment_)
+ return paint_fragment_->OffsetInContainerBlock();
+ if (item_)
+ return item_->OffsetInContainerBlock();
NOTREACHED();
return PhysicalOffset();
}
-const PhysicalRect NGInlineCursor::CurrentRect() const {
- return PhysicalRect(CurrentOffset(), CurrentSize());
+const PhysicalSize NGInlineCursorPosition::Size() const {
+ if (paint_fragment_)
+ return paint_fragment_->Size();
+ if (item_)
+ return item_->Size();
+ NOTREACHED();
+ return PhysicalSize();
}
-TextDirection NGInlineCursor::CurrentResolvedDirection() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->PhysicalFragment().ResolvedDirection();
- if (current_item_)
- return current_item_->ResolvedDirection();
+const PhysicalRect NGInlineCursorPosition::RectInContainerBlock() const {
+ if (paint_fragment_) {
+ return {paint_fragment_->OffsetInContainerBlock(), paint_fragment_->Size()};
+ }
+ if (item_)
+ return item_->RectInContainerBlock();
NOTREACHED();
- return TextDirection::kLtr;
+ return PhysicalRect();
}
-const PhysicalSize NGInlineCursor::CurrentSize() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->Size();
- if (current_item_)
- return current_item_->Size();
+const PhysicalRect NGInlineCursorPosition::SelfInkOverflow() const {
+ if (paint_fragment_)
+ return paint_fragment_->SelfInkOverflow();
+ if (item_)
+ return item_->SelfInkOverflow();
NOTREACHED();
- return PhysicalSize();
+ return PhysicalRect();
+}
+
+TextDirection NGInlineCursorPosition::ResolvedDirection() const {
+ if (paint_fragment_)
+ return paint_fragment_->PhysicalFragment().ResolvedDirection();
+ if (item_)
+ return item_->ResolvedDirection();
+ NOTREACHED();
+ return TextDirection::kLtr;
}
-const ComputedStyle& NGInlineCursor::CurrentStyle() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->Style();
- return current_item_->Style();
+const ComputedStyle& NGInlineCursorPosition::Style() const {
+ if (paint_fragment_)
+ return paint_fragment_->Style();
+ return item_->Style();
}
-NGStyleVariant NGInlineCursor::CurrentStyleVariant() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->PhysicalFragment().StyleVariant();
- return current_item_->StyleVariant();
+NGStyleVariant NGInlineCursorPosition::StyleVariant() const {
+ if (paint_fragment_)
+ return paint_fragment_->PhysicalFragment().StyleVariant();
+ return item_->StyleVariant();
}
-bool NGInlineCursor::UsesFirstLineStyle() const {
- return CurrentStyleVariant() == NGStyleVariant::kFirstLine;
+bool NGInlineCursorPosition::UsesFirstLineStyle() const {
+ return StyleVariant() == NGStyleVariant::kFirstLine;
}
-NGTextOffset NGInlineCursor::CurrentTextOffset() const {
- if (current_paint_fragment_) {
+NGTextOffset NGInlineCursorPosition::TextOffset() const {
+ if (paint_fragment_) {
const auto& text_fragment =
- To<NGPhysicalTextFragment>(current_paint_fragment_->PhysicalFragment());
- return {text_fragment.StartOffset(), text_fragment.EndOffset()};
+ To<NGPhysicalTextFragment>(paint_fragment_->PhysicalFragment());
+ return text_fragment.TextOffset();
}
- if (current_item_)
- return {current_item_->StartOffset(), current_item_->EndOffset()};
+ if (item_)
+ return item_->TextOffset();
NOTREACHED();
return {};
}
-StringView NGInlineCursor::CurrentText() const {
+StringView NGInlineCursorPosition::Text(const NGInlineCursor& cursor) const {
DCHECK(IsText());
- if (current_paint_fragment_) {
- return To<NGPhysicalTextFragment>(
- current_paint_fragment_->PhysicalFragment())
+ cursor.CheckValid(*this);
+ if (paint_fragment_) {
+ return To<NGPhysicalTextFragment>(paint_fragment_->PhysicalFragment())
.Text();
}
- if (current_item_)
- return current_item_->Text(*fragment_items_);
+ if (item_)
+ return item_->Text(cursor.Items());
NOTREACHED();
return "";
}
-const ShapeResultView* NGInlineCursor::CurrentTextShapeResult() const {
+const ShapeResultView* NGInlineCursorPosition::TextShapeResult() const {
DCHECK(IsText());
- if (current_paint_fragment_) {
- return To<NGPhysicalTextFragment>(
- current_paint_fragment_->PhysicalFragment())
+ if (paint_fragment_) {
+ return To<NGPhysicalTextFragment>(paint_fragment_->PhysicalFragment())
.TextShapeResult();
}
- if (current_item_)
- return current_item_->TextShapeResult();
+ if (item_)
+ return item_->TextShapeResult();
NOTREACHED();
return nullptr;
}
PhysicalRect NGInlineCursor::CurrentLocalRect(unsigned start_offset,
unsigned end_offset) const {
- DCHECK(IsText());
- if (current_paint_fragment_) {
+ DCHECK(Current().IsText());
+ if (current_.paint_fragment_) {
return To<NGPhysicalTextFragment>(
- current_paint_fragment_->PhysicalFragment())
+ current_.paint_fragment_->PhysicalFragment())
.LocalRect(start_offset, end_offset);
}
- if (current_item_) {
- return current_item_->LocalRect(current_item_->Text(*fragment_items_),
- start_offset, end_offset);
+ if (current_.item_) {
+ return current_.item_->LocalRect(current_.item_->Text(*fragment_items_),
+ start_offset, end_offset);
}
NOTREACHED();
return PhysicalRect();
}
LayoutUnit NGInlineCursor::InlinePositionForOffset(unsigned offset) const {
- DCHECK(IsText());
- if (current_paint_fragment_) {
+ DCHECK(Current().IsText());
+ if (current_.paint_fragment_) {
return To<NGPhysicalTextFragment>(
- current_paint_fragment_->PhysicalFragment())
+ current_.paint_fragment_->PhysicalFragment())
.InlinePositionForOffset(offset);
}
- if (current_item_) {
- return current_item_->InlinePositionForOffset(
- current_item_->Text(*fragment_items_), offset);
+ if (current_.item_) {
+ return current_.item_->InlinePositionForOffset(
+ current_.item_->Text(*fragment_items_), offset);
}
NOTREACHED();
return LayoutUnit();
}
PhysicalOffset NGInlineCursor::LineStartPoint() const {
- DCHECK(IsLineBox()) << this;
+ DCHECK(Current().IsLineBox()) << this;
const LogicalOffset logical_start; // (0, 0)
const PhysicalSize pixel_size(LayoutUnit(1), LayoutUnit(1));
- return logical_start.ConvertToPhysical(CurrentStyle().GetWritingMode(),
- CurrentBaseDirection(), CurrentSize(),
- pixel_size);
+ return logical_start.ConvertToPhysical(Current().Style().GetWritingMode(),
+ Current().BaseDirection(),
+ Current().Size(), pixel_size);
}
PhysicalOffset NGInlineCursor::LineEndPoint() const {
- DCHECK(IsLineBox()) << this;
- const LayoutUnit inline_size =
- IsHorizontal() ? CurrentSize().width : CurrentSize().height;
+ DCHECK(Current().IsLineBox()) << this;
+ const WritingMode writing_mode = Current().Style().GetWritingMode();
+ const LayoutUnit inline_size = IsHorizontalWritingMode(writing_mode)
+ ? Current().Size().width
+ : Current().Size().height;
const LogicalOffset logical_end(inline_size, LayoutUnit());
const PhysicalSize pixel_size(LayoutUnit(1), LayoutUnit(1));
- return logical_end.ConvertToPhysical(CurrentStyle().GetWritingMode(),
- CurrentBaseDirection(), CurrentSize(),
- pixel_size);
+ return logical_end.ConvertToPhysical(writing_mode, Current().BaseDirection(),
+ Current().Size(), pixel_size);
}
-PositionWithAffinity NGInlineCursor::PositionForPoint(
- const PhysicalOffset& point) {
- if (root_paint_fragment_)
- return root_paint_fragment_->PositionForPoint(point);
+PositionWithAffinity NGInlineCursor::PositionForPointInInlineFormattingContext(
+ const PhysicalOffset& point,
+ const NGPhysicalBoxFragment& container) {
DCHECK(IsItemCursor());
+ const ComputedStyle& container_style = container.Style();
+ const WritingMode writing_mode = container_style.GetWritingMode();
+ const TextDirection direction = container_style.Direction();
+ const PhysicalSize& container_size = container.Size();
+ const LayoutUnit point_block_offset =
+ point
+ .ConvertToLogical(writing_mode, direction, container_size,
+ // |point| is actually a pixel with size 1x1.
+ PhysicalSize(LayoutUnit(1), LayoutUnit(1)))
+ .block_offset;
+
+ // Stores the closest line box child above |point| in the block direction.
+ // Used if we can't find any child |point| falls in to resolve the position.
+ NGInlineCursorPosition closest_line_before;
+ LayoutUnit closest_line_before_block_offset = LayoutUnit::Min();
+
+ // Stores the closest line box child below |point| in the block direction.
+ // Used if we can't find any child |point| falls in to resolve the position.
+ NGInlineCursorPosition closest_line_after;
+ LayoutUnit closest_line_after_block_offset = LayoutUnit::Max();
+
while (*this) {
- const NGFragmentItem* item = CurrentItem();
- DCHECK(item);
- // TODO(kojii): Do more staff, when the point is not on any item but within
- // line box, etc., see |NGPaintFragment::PositionForPoint|.
- if (!item->Rect().Contains(point)) {
+ const NGFragmentItem* child_item = CurrentItem();
+ DCHECK(child_item);
+ if (child_item->Type() == NGFragmentItem::kLine) {
+ // Try to resolve if |point| falls in a line box in block direction.
+ const LayoutUnit child_block_offset =
+ child_item->OffsetInContainerBlock()
+ .ConvertToLogical(writing_mode, direction, container_size,
+ child_item->Size())
+ .block_offset;
+ if (point_block_offset < child_block_offset) {
+ if (child_block_offset < closest_line_after_block_offset) {
+ closest_line_after_block_offset = child_block_offset;
+ closest_line_after = Current();
+ }
+ MoveToNextItemSkippingChildren();
+ continue;
+ }
+
+ // Hitting on line bottom doesn't count, to match legacy behavior.
+ const LayoutUnit child_block_end_offset =
+ child_block_offset +
+ child_item->Size().ConvertToLogical(writing_mode).block_size;
+ if (point_block_offset >= child_block_end_offset) {
+ if (child_block_end_offset > closest_line_before_block_offset) {
+ closest_line_before_block_offset = child_block_end_offset;
+ closest_line_before = Current();
+ }
+ MoveToNextItemSkippingChildren();
+ continue;
+ }
+
+ if (const PositionWithAffinity child_position =
+ PositionForPointInInlineBox(point))
+ return child_position;
MoveToNextItemSkippingChildren();
continue;
}
- if (item->Type() == NGFragmentItem::kText)
- return item->PositionForPointInText(point, *this);
- MoveToNext();
+ DCHECK_NE(child_item->Type(), NGFragmentItem::kText);
+ MoveToNextItem();
+ }
+
+ if (closest_line_after) {
+ MoveTo(closest_line_after);
+ if (const PositionWithAffinity child_position =
+ PositionForPointInInlineBox(point))
+ return child_position;
+ }
+
+ if (closest_line_before) {
+ MoveTo(closest_line_before);
+ if (const PositionWithAffinity child_position =
+ PositionForPointInInlineBox(point))
+ return child_position;
+ }
+
+ return PositionWithAffinity();
+}
+
+PositionWithAffinity NGInlineCursor::PositionForPointInInlineBox(
+ const PhysicalOffset& point) const {
+ if (const NGPaintFragment* paint_fragment = CurrentPaintFragment()) {
+ DCHECK(paint_fragment->PhysicalFragment().IsLineBox());
+ return paint_fragment->PositionForPoint(point);
+ }
+ const NGFragmentItem* container = CurrentItem();
+ DCHECK(container);
+ DCHECK(container->Type() == NGFragmentItem::kLine ||
+ container->Type() == NGFragmentItem::kBox);
+ const ComputedStyle& container_style = container->Style();
+ const WritingMode writing_mode = container_style.GetWritingMode();
+ const TextDirection direction = container_style.Direction();
+ const PhysicalSize& container_size = container->Size();
+ const LayoutUnit point_inline_offset =
+ point
+ .ConvertToLogical(writing_mode, direction, container_size,
+ // |point| is actually a pixel with size 1x1.
+ PhysicalSize(LayoutUnit(1), LayoutUnit(1)))
+ .inline_offset;
+
+ // Stores the closest child before |point| in the inline direction. Used if we
+ // can't find any child |point| falls in to resolve the position.
+ NGInlineCursorPosition closest_child_before;
+ LayoutUnit closest_child_before_inline_offset = LayoutUnit::Min();
+
+ // Stores the closest child after |point| in the inline direction. Used if we
+ // can't find any child |point| falls in to resolve the position.
+ NGInlineCursorPosition closest_child_after;
+ LayoutUnit closest_child_after_inline_offset = LayoutUnit::Max();
+
+ NGInlineCursor descendants = CursorForDescendants();
+ for (; descendants; descendants.MoveToNext()) {
+ const NGFragmentItem* child_item = descendants.CurrentItem();
+ DCHECK(child_item);
+ if (child_item->Type() == NGFragmentItem::kBox &&
+ !child_item->BoxFragment()) {
+ // Skip virtually "culled" inline box, e.g. <span>foo</span>
+ // "editing/selection/shift-click.html" reaches here.
+ DCHECK(child_item->GetLayoutObject()->IsLayoutInline()) << child_item;
+ continue;
+ }
+ const LayoutUnit child_inline_offset =
+ child_item->OffsetInContainerBlock()
+ .ConvertToLogical(writing_mode, direction, container_size,
+ child_item->Size())
+ .inline_offset;
+ if (point_inline_offset < child_inline_offset) {
+ if (child_inline_offset < closest_child_after_inline_offset) {
+ closest_child_after_inline_offset = child_inline_offset;
+ closest_child_after = descendants.Current();
+ }
+ continue;
+ }
+ const LayoutUnit child_inline_end_offset =
+ child_inline_offset +
+ child_item->Size().ConvertToLogical(writing_mode).inline_size;
+ if (point_inline_offset > child_inline_end_offset) {
+ if (child_inline_end_offset > closest_child_before_inline_offset) {
+ closest_child_before_inline_offset = child_inline_end_offset;
+ closest_child_before = descendants.Current();
+ }
+ continue;
+ }
+
+ if (const PositionWithAffinity child_position =
+ descendants.PositionForPointInChild(point, *child_item))
+ return child_position;
+ }
+
+ if (closest_child_after) {
+ descendants.MoveTo(closest_child_after);
+ if (const PositionWithAffinity child_position =
+ descendants.PositionForPointInChild(point, *closest_child_after))
+ return child_position;
+ // TODO(yosin): we should do like "closest_child_before" once we have a
+ // case.
+ }
+
+ if (closest_child_before) {
+ descendants.MoveTo(closest_child_before);
+ if (const PositionWithAffinity child_position =
+ descendants.PositionForPointInChild(point, *closest_child_before))
+ return child_position;
+ if (closest_child_before->BoxFragment()) {
+ // LayoutViewHitTest.HitTestHorizontal "Top-right corner (outside) of div"
+ // reach here.
+ return descendants.PositionForPointInInlineBox(point);
+ }
+ }
+
+ return PositionWithAffinity();
+}
+
+PositionWithAffinity NGInlineCursor::PositionForPointInChild(
+ const PhysicalOffset& point,
+ const NGFragmentItem& child_item) const {
+ DCHECK_EQ(&child_item, CurrentItem());
+ switch (child_item.Type()) {
+ case NGFragmentItem::kText:
+ return child_item.PositionForPointInText(
+ point - child_item.OffsetInContainerBlock(), *this);
+ case NGFragmentItem::kGeneratedText:
+ break;
+ case NGFragmentItem::kBox:
+ if (const NGPhysicalBoxFragment* box_fragment =
+ child_item.BoxFragment()) {
+ // We must fallback to legacy for old layout roots. We also fallback (to
+ // LayoutNGMixin::PositionForPoint()) for NG block layout, so that we
+ // can utilize LayoutBlock::PositionForPoint() that resolves the
+ // position in block layout.
+ // TODO(xiaochengh): Don't fallback to legacy for NG block layout.
+ if (box_fragment->IsBlockFlow() || box_fragment->IsLegacyLayoutRoot()) {
+ return child_item.GetLayoutObject()->PositionForPoint(
+ point - child_item.OffsetInContainerBlock());
+ }
+ } else {
+ // |LayoutInline| used to be culled.
+ }
+ DCHECK(child_item.GetLayoutObject()->IsLayoutInline()) << child_item;
+ break;
+ case NGFragmentItem::kLine:
+ NOTREACHED();
+ break;
}
return PositionWithAffinity();
}
void NGInlineCursor::MakeNull() {
if (root_paint_fragment_) {
- current_paint_fragment_ = nullptr;
+ current_.paint_fragment_ = nullptr;
return;
}
if (fragment_items_)
return MoveToItem(items_.end());
}
+void NGInlineCursor::MoveTo(const NGInlineCursorPosition& position) {
+ CheckValid(position);
+ current_ = position;
+}
+
+inline unsigned NGInlineCursor::SpanIndexFromItemIndex(unsigned index) const {
+ DCHECK(IsItemCursor());
+ DCHECK_GE(items_.data(), fragment_items_->Items().data());
+ DCHECK_LT(items_.data(), fragment_items_->Items().end());
+ if (items_.data() == fragment_items_->Items().data())
+ return index;
+ unsigned span_index = fragment_items_->Items().data() - items_.data() + index;
+ DCHECK_LT(span_index, items_.size());
+ return span_index;
+}
+
+NGInlineCursor::ItemsSpan::iterator NGInlineCursor::SlowFirstItemIteratorFor(
+ const LayoutObject& layout_object) const {
+ DCHECK(IsItemCursor());
+ for (ItemsSpan::iterator iter = items_.begin(); iter != items_.end();
+ ++iter) {
+ if ((*iter)->GetLayoutObject() == &layout_object)
+ return iter;
+ }
+ return items_.end();
+}
+
void NGInlineCursor::InternalMoveTo(const LayoutObject& layout_object) {
DCHECK(layout_object.IsInLayoutNGInlineFormattingContext());
// If this cursor is rootless, find the root of the inline formatting context.
@@ -662,30 +913,18 @@ void NGInlineCursor::InternalMoveTo(const LayoutObject& layout_object) {
}
}
if (fragment_items_) {
- const wtf_size_t index = layout_object.FirstInlineFragmentItemIndex();
- if (!index) {
+ const wtf_size_t item_index = layout_object.FirstInlineFragmentItemIndex();
+ if (!item_index) {
// TODO(yosin): Once we update all |LayoutObject::FirstInlineFragment()|
// clients, we should replace to |return MakeNull()|
- item_iter_ = items_.begin();
- while (current_item_ && CurrentLayoutObject() != &layout_object)
- MoveToNextItem();
+ MoveToItem(SlowFirstItemIteratorFor(layout_object));
return;
}
- DCHECK_LT(index, items_.size());
- if (!had_root)
- return MoveToItem(items_.begin() + index);
- // Map |index| in |NGFragmentItems| to index of |items_|.
- const LayoutBlockFlow& block_flow =
- *layout_object.RootInlineFormattingContext();
- const auto items =
- ItemsSpan(block_flow.CurrentFragment()->Items()->Items());
- // Note: We use address instead of iterator because we can't compare
- // iterators in different span. See |base::CheckedContiguousIterator<T>|.
- const ptrdiff_t adjusted_index =
- &*(items.begin() + index) - &*items_.begin();
- DCHECK_GE(adjusted_index, 0);
- DCHECK_LT(static_cast<size_t>(adjusted_index), items_.size());
- return MoveToItem(items_.begin() + adjusted_index);
+ const unsigned span_index = SpanIndexFromItemIndex(item_index);
+ DCHECK_EQ(span_index,
+ static_cast<unsigned>(SlowFirstItemIteratorFor(layout_object) -
+ items_.begin()));
+ return MoveToItem(items_.begin() + span_index);
}
if (root_paint_fragment_) {
const auto fragments = NGPaintFragment::InlineFragmentsFor(&layout_object);
@@ -698,13 +937,16 @@ void NGInlineCursor::InternalMoveTo(const LayoutObject& layout_object) {
void NGInlineCursor::MoveTo(const LayoutObject& layout_object) {
DCHECK(layout_object.IsInLayoutNGInlineFormattingContext()) << layout_object;
InternalMoveTo(layout_object);
- if (*this || !HasRoot()) {
+ if (*this || !HasRoot() ||
+ RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
layout_inline_ = nullptr;
return;
}
// This |layout_object| did not produce any fragments.
- //
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
+
// Try to find ancestors if this is a culled inline.
layout_inline_ = ToLayoutInlineOrNull(&layout_object);
if (!layout_inline_)
@@ -715,17 +957,28 @@ void NGInlineCursor::MoveTo(const LayoutObject& layout_object) {
MoveToNext();
}
+void NGInlineCursor::MoveTo(const NGFragmentItem& fragment_item) {
+ DCHECK(!root_paint_fragment_ && !current_.paint_fragment_);
+ MoveTo(*fragment_item.GetLayoutObject());
+ while (IsNotNull()) {
+ if (CurrentItem() == &fragment_item)
+ return;
+ MoveToNext();
+ }
+ NOTREACHED();
+}
+
void NGInlineCursor::MoveTo(const NGInlineCursor& cursor) {
if (const NGPaintFragment* paint_fragment = cursor.CurrentPaintFragment()) {
MoveTo(*paint_fragment);
return;
}
- if (cursor.current_item_) {
+ if (cursor.current_.item_) {
if (!fragment_items_)
SetRoot(*cursor.fragment_items_);
// Note: We use address instead of iterato because we can't compare
// iterators in different span. See |base::CheckedContiguousIterator<T>|.
- const ptrdiff_t index = &*cursor.item_iter_ - &*items_.begin();
+ const ptrdiff_t index = &*cursor.current_.item_iter_ - &*items_.begin();
DCHECK_GE(index, 0);
DCHECK_LT(static_cast<size_t>(index), items_.size());
MoveToItem(items_.begin() + index);
@@ -741,19 +994,26 @@ void NGInlineCursor::MoveTo(const NGPaintFragment& paint_fragment) {
DCHECK(root_paint_fragment_);
DCHECK(paint_fragment.IsDescendantOfNotSelf(*root_paint_fragment_))
<< paint_fragment << " " << root_paint_fragment_;
- current_paint_fragment_ = &paint_fragment;
+ current_.paint_fragment_ = &paint_fragment;
+}
+
+void NGInlineCursor::MoveTo(const NGPaintFragment* paint_fragment) {
+ if (paint_fragment) {
+ MoveTo(*paint_fragment);
+ return;
+ }
+ MakeNull();
}
void NGInlineCursor::MoveToContainingLine() {
- DCHECK(!IsLineBox());
- if (current_paint_fragment_) {
- current_paint_fragment_ = current_paint_fragment_->ContainerLineBox();
+ DCHECK(!Current().IsLineBox());
+ if (current_.paint_fragment_) {
+ current_.paint_fragment_ = current_.paint_fragment_->ContainerLineBox();
return;
}
- if (current_item_) {
- do {
+ if (current_.item_) {
+ while (current_.item_ && !Current().IsLineBox())
MoveToPreviousItem();
- } while (current_item_ && !IsLineBox());
return;
}
NOTREACHED();
@@ -761,7 +1021,7 @@ void NGInlineCursor::MoveToContainingLine() {
void NGInlineCursor::MoveToFirst() {
if (root_paint_fragment_) {
- current_paint_fragment_ = root_paint_fragment_->FirstChild();
+ current_.paint_fragment_ = root_paint_fragment_->FirstChild();
return;
}
if (IsItemCursor()) {
@@ -777,13 +1037,32 @@ void NGInlineCursor::MoveToFirstChild() {
MakeNull();
}
+void NGInlineCursor::MoveToFirstLine() {
+ if (root_paint_fragment_) {
+ MoveTo(root_paint_fragment_->FirstLineBox());
+ return;
+ }
+ if (IsItemCursor()) {
+ auto iter = std::find_if(
+ items_.begin(), items_.end(),
+ [](const auto& item) { return item->Type() == NGFragmentItem::kLine; });
+ if (iter != items_.end()) {
+ MoveToItem(iter);
+ return;
+ }
+ MakeNull();
+ return;
+ }
+ NOTREACHED();
+}
+
void NGInlineCursor::MoveToFirstLogicalLeaf() {
- DCHECK(IsLineBox());
+ DCHECK(Current().IsLineBox());
// TODO(yosin): This isn't correct for mixed Bidi. Fix it. Besides, we
// should compute and store it during layout.
// TODO(yosin): We should check direction of each container instead of line
// box.
- if (IsLtr(CurrentStyle().Direction())) {
+ if (IsLtr(Current().Style().Direction())) {
while (TryToMoveToFirstChild())
continue;
return;
@@ -799,21 +1078,23 @@ void NGInlineCursor::MoveToLastChild() {
}
void NGInlineCursor::MoveToLastForSameLayoutObject() {
- NGInlineCursor last;
- while (IsNotNull()) {
- last = *this;
+ if (!Current())
+ return;
+ NGInlineCursorPosition last;
+ do {
+ last = Current();
MoveToNextForSameLayoutObject();
- }
- *this = last;
+ } while (Current());
+ MoveTo(last);
}
void NGInlineCursor::MoveToLastLogicalLeaf() {
- DCHECK(IsLineBox());
+ DCHECK(Current().IsLineBox());
// TODO(yosin): This isn't correct for mixed Bidi. Fix it. Besides, we
// should compute and store it during layout.
// TODO(yosin): We should check direction of each container instead of line
// box.
- if (IsLtr(CurrentStyle().Direction())) {
+ if (IsLtr(Current().Style().Direction())) {
while (TryToMoveToLastChild())
continue;
return;
@@ -830,15 +1111,16 @@ void NGInlineCursor::MoveToNext() {
void NGInlineCursor::MoveToNextForSameLayoutObject() {
if (layout_inline_) {
+ DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
// Move to next fragment in culled inline box undef |layout_inline_|.
do {
MoveToNext();
} while (IsNotNull() && !IsPartOfCulledInlineBox(*layout_inline_));
return;
}
- if (current_paint_fragment_) {
+ if (current_.paint_fragment_) {
if (auto* paint_fragment =
- current_paint_fragment_->NextForSameLayoutObject()) {
+ current_.paint_fragment_->NextForSameLayoutObject()) {
// |paint_fragment| can be in another fragment tree rooted by
// |root_paint_fragment_|, e.g. "multicol-span-all-restyle-002.html"
root_paint_fragment_ = paint_fragment->Root();
@@ -846,11 +1128,11 @@ void NGInlineCursor::MoveToNextForSameLayoutObject() {
}
return MakeNull();
}
- if (current_item_) {
- const wtf_size_t delta = current_item_->DeltaToNextForSameLayoutObject();
+ if (current_.item_) {
+ const wtf_size_t delta = current_.item_->DeltaToNextForSameLayoutObject();
if (delta == 0u)
return MakeNull();
- return MoveToItem(item_iter_ + delta);
+ return MoveToItem(current_.item_iter_ + delta);
}
}
@@ -864,7 +1146,7 @@ void NGInlineCursor::MoveToNextInlineLeaf() {
void NGInlineCursor::MoveToNextInlineLeafIgnoringLineBreak() {
do {
MoveToNextInlineLeaf();
- } while (IsNotNull() && IsLineBreak());
+ } while (Current() && Current().IsLineBreak());
}
void NGInlineCursor::MoveToNextInlineLeafOnLine() {
@@ -883,23 +1165,23 @@ void NGInlineCursor::MoveToNextInlineLeafOnLine() {
}
void NGInlineCursor::MoveToNextLine() {
- DCHECK(IsLineBox());
- if (current_paint_fragment_) {
- if (auto* paint_fragment = current_paint_fragment_->NextSibling())
+ DCHECK(Current().IsLineBox());
+ if (current_.paint_fragment_) {
+ if (auto* paint_fragment = current_.paint_fragment_->NextSibling())
return MoveTo(*paint_fragment);
return MakeNull();
}
- if (current_item_) {
+ if (current_.item_) {
do {
MoveToNextItem();
- } while (IsNotNull() && !IsLineBox());
+ } while (Current() && !Current().IsLineBox());
return;
}
NOTREACHED();
}
void NGInlineCursor::MoveToNextSibling() {
- if (current_paint_fragment_)
+ if (current_.paint_fragment_)
return MoveToNextSiblingPaintFragment();
return MoveToNextSiblingItem();
}
@@ -926,7 +1208,7 @@ void NGInlineCursor::MoveToPreviousInlineLeaf() {
void NGInlineCursor::MoveToPreviousInlineLeafIgnoringLineBreak() {
do {
MoveToPreviousInlineLeaf();
- } while (IsNotNull() && IsLineBreak());
+ } while (Current() && Current().IsLineBreak());
}
void NGInlineCursor::MoveToPreviousInlineLeafOnLine() {
@@ -945,17 +1227,17 @@ void NGInlineCursor::MoveToPreviousInlineLeafOnLine() {
void NGInlineCursor::MoveToPreviousLine() {
// Note: List marker is sibling of line box.
- DCHECK(IsLineBox());
- if (current_paint_fragment_) {
+ DCHECK(Current().IsLineBox());
+ if (current_.paint_fragment_) {
do {
MoveToPreviousSiblingPaintFragment();
- } while (IsNotNull() && !IsLineBox());
+ } while (Current() && !Current().IsLineBox());
return;
}
- if (current_item_) {
+ if (current_.item_) {
do {
MoveToPreviousItem();
- } while (IsNotNull() && !IsLineBox());
+ } while (Current() && !Current().IsLineBox());
return;
}
NOTREACHED();
@@ -965,10 +1247,10 @@ bool NGInlineCursor::TryToMoveToFirstChild() {
if (!HasChildren())
return false;
if (root_paint_fragment_) {
- MoveTo(*current_paint_fragment_->FirstChild());
+ MoveTo(*current_.paint_fragment_->FirstChild());
return true;
}
- MoveToItem(item_iter_ + 1);
+ MoveToItem(current_.item_iter_ + 1);
return true;
}
@@ -976,14 +1258,14 @@ bool NGInlineCursor::TryToMoveToLastChild() {
if (!HasChildren())
return false;
if (root_paint_fragment_) {
- MoveTo(current_paint_fragment_->Children().back());
+ MoveTo(current_.paint_fragment_->Children().back());
return true;
}
- const auto end = item_iter_ + CurrentItem()->DescendantsCount();
+ const auto end = current_.item_iter_ + CurrentItem()->DescendantsCount();
MoveToNextItem();
DCHECK(!IsNull());
- for (auto it = item_iter_ + 1; it != end; ++it) {
- if (CurrentItem()->HasSameParent(**it))
+ for (auto it = current_.item_iter_ + 1; it != end; ++it) {
+ if (CurrentItem()->IsSiblingOf(**it))
MoveToItem(it);
}
return true;
@@ -991,78 +1273,78 @@ bool NGInlineCursor::TryToMoveToLastChild() {
void NGInlineCursor::MoveToNextItem() {
DCHECK(IsItemCursor());
- if (UNLIKELY(!current_item_))
+ if (UNLIKELY(!current_.item_))
return;
- DCHECK(item_iter_ != items_.end());
- ++item_iter_;
- MoveToItem(item_iter_);
+ DCHECK(current_.item_iter_ != items_.end());
+ ++current_.item_iter_;
+ MoveToItem(current_.item_iter_);
}
void NGInlineCursor::MoveToNextItemSkippingChildren() {
DCHECK(IsItemCursor());
- if (UNLIKELY(!current_item_))
+ if (UNLIKELY(!current_.item_))
return;
// If the current item has |DescendantsCount|, add it to move to the next
// sibling, skipping all children and their descendants.
- if (wtf_size_t descendants_count = current_item_->DescendantsCount())
- return MoveToItem(item_iter_ + descendants_count);
+ if (wtf_size_t descendants_count = current_.item_->DescendantsCount())
+ return MoveToItem(current_.item_iter_ + descendants_count);
return MoveToNextItem();
}
void NGInlineCursor::MoveToNextSiblingItem() {
DCHECK(IsItemCursor());
- if (UNLIKELY(!current_item_))
+ if (UNLIKELY(!current_.item_))
return;
const NGFragmentItem& item = *CurrentItem();
MoveToNextItemSkippingChildren();
- if (IsNull() || item.HasSameParent(*CurrentItem()))
+ if (IsNull() || item.IsSiblingOf(*CurrentItem()))
return;
MakeNull();
}
void NGInlineCursor::MoveToPreviousItem() {
DCHECK(IsItemCursor());
- if (UNLIKELY(!current_item_))
+ if (UNLIKELY(!current_.item_))
return;
- if (item_iter_ == items_.begin())
+ if (current_.item_iter_ == items_.begin())
return MakeNull();
- --item_iter_;
- current_item_ = item_iter_->get();
+ --current_.item_iter_;
+ current_.item_ = current_.item_iter_->get();
}
void NGInlineCursor::MoveToParentPaintFragment() {
- DCHECK(IsPaintFragmentCursor() && current_paint_fragment_);
- const NGPaintFragment* parent = current_paint_fragment_->Parent();
+ DCHECK(IsPaintFragmentCursor() && current_.paint_fragment_);
+ const NGPaintFragment* parent = current_.paint_fragment_->Parent();
if (parent && parent != root_paint_fragment_) {
- current_paint_fragment_ = parent;
+ current_.paint_fragment_ = parent;
return;
}
- current_paint_fragment_ = nullptr;
+ current_.paint_fragment_ = nullptr;
}
void NGInlineCursor::MoveToNextPaintFragment() {
- DCHECK(IsPaintFragmentCursor() && current_paint_fragment_);
- if (const NGPaintFragment* child = current_paint_fragment_->FirstChild()) {
- current_paint_fragment_ = child;
+ DCHECK(IsPaintFragmentCursor() && current_.paint_fragment_);
+ if (const NGPaintFragment* child = current_.paint_fragment_->FirstChild()) {
+ current_.paint_fragment_ = child;
return;
}
MoveToNextPaintFragmentSkippingChildren();
}
void NGInlineCursor::MoveToNextSiblingPaintFragment() {
- DCHECK(IsPaintFragmentCursor() && current_paint_fragment_);
- if (const NGPaintFragment* next = current_paint_fragment_->NextSibling()) {
- current_paint_fragment_ = next;
+ DCHECK(IsPaintFragmentCursor() && current_.paint_fragment_);
+ if (const NGPaintFragment* next = current_.paint_fragment_->NextSibling()) {
+ current_.paint_fragment_ = next;
return;
}
- current_paint_fragment_ = nullptr;
+ current_.paint_fragment_ = nullptr;
}
void NGInlineCursor::MoveToNextPaintFragmentSkippingChildren() {
- DCHECK(IsPaintFragmentCursor() && current_paint_fragment_);
- while (current_paint_fragment_) {
- if (const NGPaintFragment* next = current_paint_fragment_->NextSibling()) {
- current_paint_fragment_ = next;
+ DCHECK(IsPaintFragmentCursor() && current_.paint_fragment_);
+ while (current_.paint_fragment_) {
+ if (const NGPaintFragment* next = current_.paint_fragment_->NextSibling()) {
+ current_.paint_fragment_ = next;
return;
}
MoveToParentPaintFragment();
@@ -1070,25 +1352,25 @@ void NGInlineCursor::MoveToNextPaintFragmentSkippingChildren() {
}
void NGInlineCursor::MoveToPreviousPaintFragment() {
- DCHECK(IsPaintFragmentCursor() && current_paint_fragment_);
- const NGPaintFragment* const parent = current_paint_fragment_->Parent();
+ DCHECK(IsPaintFragmentCursor() && current_.paint_fragment_);
+ const NGPaintFragment* const parent = current_.paint_fragment_->Parent();
MoveToPreviousSiblingPaintFragment();
- if (current_paint_fragment_) {
+ if (current_.paint_fragment_) {
while (TryToMoveToLastChild())
continue;
return;
}
- current_paint_fragment_ = parent == root_paint_fragment_ ? nullptr : parent;
+ current_.paint_fragment_ = parent == root_paint_fragment_ ? nullptr : parent;
}
void NGInlineCursor::MoveToPreviousSiblingPaintFragment() {
- DCHECK(IsPaintFragmentCursor() && current_paint_fragment_);
- const NGPaintFragment* const current = current_paint_fragment_;
- current_paint_fragment_ = nullptr;
+ DCHECK(IsPaintFragmentCursor() && current_.paint_fragment_);
+ const NGPaintFragment* const current = current_.paint_fragment_;
+ current_.paint_fragment_ = nullptr;
for (auto* sibling : current->Parent()->Children()) {
if (sibling == current)
return;
- current_paint_fragment_ = sibling;
+ current_.paint_fragment_ = sibling;
}
NOTREACHED();
}
@@ -1096,28 +1378,35 @@ void NGInlineCursor::MoveToPreviousSiblingPaintFragment() {
NGInlineBackwardCursor::NGInlineBackwardCursor(const NGInlineCursor& cursor)
: cursor_(cursor) {
if (cursor.root_paint_fragment_) {
+ DCHECK(!cursor.CurrentPaintFragment() ||
+ cursor.CurrentPaintFragment()->Parent()->FirstChild() ==
+ cursor.CurrentPaintFragment());
for (NGInlineCursor sibling(cursor); sibling; sibling.MoveToNextSibling())
sibling_paint_fragments_.push_back(sibling.CurrentPaintFragment());
current_index_ = sibling_paint_fragments_.size();
if (current_index_)
- current_paint_fragment_ = sibling_paint_fragments_[--current_index_];
+ current_.paint_fragment_ = sibling_paint_fragments_[--current_index_];
return;
}
if (cursor.IsItemCursor()) {
- for (NGInlineCursor sibling(cursor); sibling; sibling.MoveToNextSibling())
- sibling_item_iterators_.push_back(sibling.item_iter_);
+ DCHECK(!cursor || cursor.items_.begin() == cursor.Current().item_iter_);
+ for (NGInlineCursor sibling(cursor); sibling;
+ sibling.MoveToNextSkippingChildren())
+ sibling_item_iterators_.push_back(sibling.Current().item_iter_);
current_index_ = sibling_item_iterators_.size();
- if (current_index_)
- current_item_ = sibling_item_iterators_[--current_index_]->get();
+ if (current_index_) {
+ current_.item_iter_ = sibling_item_iterators_[--current_index_];
+ current_.item_ = current_.item_iter_->get();
+ }
return;
}
- NOTREACHED();
+ DCHECK(!cursor);
}
NGInlineCursor NGInlineBackwardCursor::CursorForDescendants() const {
- if (const NGPaintFragment* current_paint_fragment = CurrentPaintFragment())
+ if (const NGPaintFragment* current_paint_fragment = Current().PaintFragment())
return NGInlineCursor(*current_paint_fragment);
- if (current_item_) {
+ if (current_.item_) {
NGInlineCursor cursor(cursor_);
cursor.MoveToItem(sibling_item_iterators_[current_index_]);
return cursor.CursorForDescendants();
@@ -1126,38 +1415,21 @@ NGInlineCursor NGInlineBackwardCursor::CursorForDescendants() const {
return NGInlineCursor();
}
-const PhysicalOffset NGInlineBackwardCursor::CurrentOffset() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->InlineOffsetToContainerBox();
- if (current_item_)
- return current_item_->Offset();
- NOTREACHED();
- return PhysicalOffset();
-}
-
-const PhysicalRect NGInlineBackwardCursor::CurrentSelfInkOverflow() const {
- if (current_paint_fragment_)
- return current_paint_fragment_->SelfInkOverflow();
- if (current_item_)
- return current_item_->SelfInkOverflow();
- NOTREACHED();
- return PhysicalRect();
-}
-
void NGInlineBackwardCursor::MoveToPreviousSibling() {
if (current_index_) {
- if (current_paint_fragment_) {
- current_paint_fragment_ = sibling_paint_fragments_[--current_index_];
+ if (current_.paint_fragment_) {
+ current_.paint_fragment_ = sibling_paint_fragments_[--current_index_];
return;
}
- if (current_item_) {
- current_item_ = sibling_item_iterators_[--current_index_]->get();
+ if (current_.item_) {
+ current_.item_iter_ = sibling_item_iterators_[--current_index_];
+ current_.item_ = current_.item_iter_->get();
return;
}
NOTREACHED();
}
- current_paint_fragment_ = nullptr;
- current_item_ = nullptr;
+ current_.paint_fragment_ = nullptr;
+ current_.item_ = nullptr;
}
std::ostream& operator<<(std::ostream& ostream, const NGInlineCursor& cursor) {
@@ -1177,4 +1449,18 @@ std::ostream& operator<<(std::ostream& ostream, const NGInlineCursor* cursor) {
return ostream << *cursor;
}
+#if DCHECK_IS_ON()
+void NGInlineCursor::CheckValid(const NGInlineCursorPosition& position) const {
+ if (position.PaintFragment()) {
+ DCHECK(root_paint_fragment_);
+ DCHECK(
+ position.PaintFragment()->IsDescendantOfNotSelf(*root_paint_fragment_));
+ } else if (position.Item()) {
+ DCHECK(IsItemCursor());
+ const unsigned index = position.item_iter_ - items_.begin();
+ DCHECK_LT(index, items_.size());
+ }
+}
+#endif
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
index 9c23ab2daef..c9626d87b5e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h
@@ -25,7 +25,9 @@ class LayoutObject;
class LayoutUnit;
class NGFragmentItem;
class NGFragmentItems;
+class NGInlineBackwardCursor;
class NGInlineBreakToken;
+class NGInlineCursor;
class NGPaintFragment;
class NGPhysicalBoxFragment;
class Node;
@@ -35,6 +37,128 @@ struct PhysicalOffset;
struct PhysicalRect;
struct PhysicalSize;
+// Represents a position of |NGInlineCursor|. This class:
+// 1. Provides properties for the current position.
+// 2. Allows to save |Current()|, and can move back later. Moving to |Position|
+// is faster than moving to |NGFragmentItem|.
+class CORE_EXPORT NGInlineCursorPosition {
+ STACK_ALLOCATED();
+
+ public:
+ using ItemsSpan = base::span<const std::unique_ptr<NGFragmentItem>>;
+
+ const NGPaintFragment* PaintFragment() const { return paint_fragment_; }
+ const NGFragmentItem* Item() const { return item_; }
+ const NGFragmentItem* operator->() const { return item_; }
+ const NGFragmentItem& operator*() const { return *item_; }
+
+ operator bool() const { return paint_fragment_ || item_; }
+
+ bool operator==(const NGInlineCursorPosition& other) const {
+ return paint_fragment_ == other.paint_fragment_ && item_ == other.item_;
+ }
+ bool operator!=(const NGInlineCursorPosition& other) const {
+ return !operator==(other);
+ }
+
+ // True if the current position is a text. It is error to call at end.
+ bool IsText() const;
+
+ // True if the current position is a generatd text. It is error to call at
+ // end.
+ bool IsGeneratedText() const;
+
+ // True if fragment is |NGFragmentItem::kGeneratedText| or
+ // |NGPhysicalTextFragment::kGeneratedText|.
+ // TODO(yosin): We should rename |IsGeneratedTextType()| to another name.
+ bool IsGeneratedTextType() const;
+
+ // True if the current position is a line break. It is error to call at end.
+ bool IsLineBreak() const;
+
+ // True if the current position is an ellipsis. It is error to call at end.
+ bool IsEllipsis() const;
+
+ // True if the current position is a line box. It is error to call at end.
+ bool IsLineBox() const;
+
+ // True if the current position is an empty line box. It is error to call
+ // other then line box.
+ bool IsEmptyLineBox() const;
+
+ // True if the current position is an inline box. It is error to call at end.
+ bool IsInlineBox() const;
+
+ // True if the current position is an atomic inline. It is error to call at
+ // end.
+ bool IsAtomicInline() const;
+
+ // True if the current position is a list marker.
+ bool IsListMarker() const;
+
+ // True if the current position is hidden for paint. It is error to call at
+ // end.
+ bool IsHiddenForPaint() const;
+
+ // |ComputedStyle| and related functions.
+ NGStyleVariant StyleVariant() const;
+ bool UsesFirstLineStyle() const;
+ const ComputedStyle& Style() const;
+
+ // Functions to get corresponding objects for this position.
+ const NGPhysicalBoxFragment* BoxFragment() const;
+ const LayoutObject* GetLayoutObject() const;
+ LayoutObject* GetMutableLayoutObject() const;
+ const Node* GetNode() const;
+ const DisplayItemClient* GetDisplayItemClient() const;
+
+ // Returns break token for line box. It is error to call other than line box.
+ const NGInlineBreakToken* InlineBreakToken() const;
+
+ // The offset relative to the root of the inline formatting context.
+ const PhysicalRect RectInContainerBlock() const;
+ const PhysicalOffset OffsetInContainerBlock() const;
+ const PhysicalSize Size() const;
+
+ // InkOverflow of itself, including contents if they contribute to the ink
+ // overflow of this object (e.g. when not clipped,) in the local coordinate.
+ const PhysicalRect InkOverflow() const;
+ const PhysicalRect SelfInkOverflow() const;
+
+ // Returns start/end of offset in text content of current text fragment.
+ // It is error when this cursor doesn't point to text fragment.
+ NGTextOffset TextOffset() const;
+ unsigned TextStartOffset() const { return TextOffset().start; }
+ unsigned TextEndOffset() const { return TextOffset().end; }
+
+ // Returns text of the current position. It is error to call other than
+ // text.
+ StringView Text(const NGInlineCursor& cursor) const;
+
+ // Returns |ShapeResultView| of the current position. It is error to call
+ // other than text.
+ const ShapeResultView* TextShapeResult() const;
+
+ // Returns bidi level of current position. It is error to call other than
+ // text and atomic inline. It is also error to call |IsGeneratedTextType()|.
+ UBiDiLevel BidiLevel() const;
+ // Returns text direction of current text or atomic inline. It is error to
+ // call at other than text or atomic inline. Note: <span> doesn't have
+ // reserved direction.
+ TextDirection ResolvedDirection() const;
+ // Returns text direction of current line. It is error to call at other than
+ // line.
+ TextDirection BaseDirection() const;
+
+ private:
+ const NGPaintFragment* paint_fragment_ = nullptr;
+ const NGFragmentItem* item_ = nullptr;
+ ItemsSpan::iterator item_iter_;
+
+ friend class NGInlineBackwardCursor;
+ friend class NGInlineCursor;
+};
+
// This class traverses fragments in an inline formatting context.
//
// When constructed, the initial position is empty. Call |MoveToNext()| to move
@@ -53,12 +177,13 @@ class CORE_EXPORT NGInlineCursor {
explicit NGInlineCursor(const NGFragmentItems& fragment_items,
ItemsSpan items);
explicit NGInlineCursor(const NGPaintFragment& root_paint_fragment);
- NGInlineCursor(const NGInlineCursor& other);
+ NGInlineCursor(const NGInlineCursor& other) = default;
+ NGInlineCursor(const NGInlineBackwardCursor& backward_cursor);
// Creates an |NGInlineCursor| without the root. Even when callers don't know
// the root of the inline formatting context, this cursor can |MoveTo()|
// specific |LayoutObject|.
- NGInlineCursor();
+ NGInlineCursor() = default;
bool operator==(const NGInlineCursor& other) const;
bool operator!=(const NGInlineCursor& other) const {
@@ -83,12 +208,13 @@ class CORE_EXPORT NGInlineCursor {
//
// Functions to query the current position.
//
+ const NGInlineCursorPosition& Current() const { return current_; }
// Returns true if cursor is out of fragment tree, e.g. before first fragment
// or after last fragment in tree.
- bool IsNull() const { return !current_item_ && !current_paint_fragment_; }
- bool IsNotNull() const { return !IsNull(); }
- explicit operator bool() const { return !IsNull(); }
+ bool IsNull() const { return !Current(); }
+ bool IsNotNull() const { return Current(); }
+ operator bool() const { return Current(); }
// True if fragment at the current position can have children.
bool CanHaveChildren() const;
@@ -101,104 +227,38 @@ class CORE_EXPORT NGInlineCursor {
// has no children, returns an empty cursor.
NGInlineCursor CursorForDescendants() const;
+ // If |this| is created by |CursorForDescendants()| to traverse parts of an
+ // inline formatting context, expand the traversable range to the containing
+ // |LayoutBlockFlow|. Does nothing if |this| is for an inline formatting
+ // context.
+ void ExpandRootToContainingBlock();
+
// True if current position has soft wrap to next line. It is error to call
// other than line.
bool HasSoftWrapToNextLine() const;
- // True if the current position is a atomic inline. It is error to call at
- // end.
- bool IsAtomicInline() const;
-
// True if the current position is before soft line break. It is error to call
// at end.
bool IsBeforeSoftLineBreak() const;
- // True if the current position is an ellipsis. It is error to call at end.
- bool IsEllipsis() const;
-
- // True if the current position is an empty line box. It is error to call
- // other then line box.
- bool IsEmptyLineBox() const;
-
- // True if the current position is a generatd text. It is error to call at
- // end.
- bool IsGeneratedText() const;
-
- // True if fragment is |NGFragmentItem::kGeneratedText| or
- // |NGPhysicalTextFragment::kGeneratedText|.
- // TODO(yosin): We should rename |IsGeneratedTextType()| to another name.
- bool IsGeneratedTextType() const;
-
- // True if the current position is hidden for paint. It is error to call at
- // end.
- bool IsHiddenForPaint() const;
-
- // True if the current position's writing mode in style is horizontal.
- bool IsHorizontal() const;
-
// True if the current position is text or atomic inline box.
// Note: Because of this function is used for caret rect, hit testing, etc,
// this function returns false for hidden for paint, text overflow ellipsis,
// and line break hyphen.
bool IsInlineLeaf() const;
- // True if the current position is a line box. It is error to call at end.
- bool IsLineBox() const;
-
- // True if the current position is a line break. It is error to call at end.
- bool IsLineBreak() const;
-
- // True if the current position is a list marker.
- bool IsListMarker() const;
-
- // True if the current position is a text. It is error to call at end.
- bool IsText() const;
-
// |Current*| functions return an object for the current position.
- const NGFragmentItem* CurrentItem() const { return current_item_; }
+ const NGFragmentItem* CurrentItem() const { return Current().Item(); }
const NGPaintFragment* CurrentPaintFragment() const {
- return current_paint_fragment_;
+ return Current().PaintFragment();
+ }
+ LayoutObject* CurrentMutableLayoutObject() const {
+ return Current().GetMutableLayoutObject();
}
- // Returns text direction of current line. It is error to call at other than
- // line.
- TextDirection CurrentBaseDirection() const;
- const NGPhysicalBoxFragment* CurrentBoxFragment() const;
- const DisplayItemClient* CurrentDisplayItemClient() const;
- const LayoutObject* CurrentLayoutObject() const;
- LayoutObject* CurrentMutableLayoutObject() const;
- Node* CurrentNode() const;
-
- // Returns bidi level of current position. It is error to call other than
- // text and atomic inline. It is also error to call |IsGeneratedTextType()|.
- UBiDiLevel CurrentBidiLevel() const;
-
- // Returns text direction of current text or atomic inline. It is error to
- // call at other than text or atomic inline. Note: <span> doesn't have
- // reserved direction.
- TextDirection CurrentResolvedDirection() const;
- const ComputedStyle& CurrentStyle() const;
-
- // InkOverflow of itself, including contents if they contribute to the ink
- // overflow of this object (e.g. when not clipped,) in the local coordinate.
- const PhysicalRect CurrentInkOverflow() const;
- // The offset relative to the root of the inline formatting context.
- const PhysicalOffset CurrentOffset() const;
- const PhysicalRect CurrentRect() const;
- const PhysicalSize CurrentSize() const;
-
- // Returns start/end of offset in text content of current text fragment.
- // It is error when this cursor doesn't point to text fragment.
- NGTextOffset CurrentTextOffset() const;
- unsigned CurrentTextStartOffset() const { return CurrentTextOffset().start; }
- unsigned CurrentTextEndOffset() const { return CurrentTextOffset().end; }
// Returns text of the current position. It is error to call other than
// text.
- StringView CurrentText() const;
-
- // Returns |ShapeResultView| of the current position. It is error to call
- // other than text.
- const ShapeResultView* CurrentTextShapeResult() const;
+ StringView CurrentText() const { return Current().Text(*this); }
// The layout box of text in (start, end) range in local coordinate.
// Start and end offsets must be between |CurrentTextStartOffset()| and
@@ -216,12 +276,24 @@ class CORE_EXPORT NGInlineCursor {
PhysicalOffset LineEndPoint() const;
// Converts the given point, relative to the fragment itself, into a position
- // in DOM tree within the range of |this|.
- PositionWithAffinity PositionForPoint(const PhysicalOffset&);
+ // in DOM tree within the range of |this|. This variation ignores the inline
+ // offset, and snaps to the nearest line in the block direction.
+ PositionWithAffinity PositionForPointInInlineFormattingContext(
+ const PhysicalOffset& point,
+ const NGPhysicalBoxFragment& container);
+ // Find the |Position| in the line box |Current()| points to. This variation
+ // ignores the block offset, and snaps to the nearest item in inline
+ // direction.
+ PositionWithAffinity PositionForPointInInlineBox(
+ const PhysicalOffset& point) const;
//
// Functions to move the current position.
//
+ void MoveTo(const NGInlineCursorPosition& position);
+
+ // Move the current position at |fragment_item|.
+ void MoveTo(const NGFragmentItem& fragment_item);
// Move the current position at |cursor|. Unlinke copy constrcutr, this
// function doesn't copy root. Note: The current position in |cursor|
@@ -230,6 +302,7 @@ class CORE_EXPORT NGInlineCursor {
// Move the current posint at |paint_fragment|.
void MoveTo(const NGPaintFragment& paint_fragment);
+ void MoveTo(const NGPaintFragment* paint_fragment);
// Move to first |NGFragmentItem| or |NGPaintFragment| associated to
// |layout_object|. When |layout_object| has no associated fragments, this
@@ -244,6 +317,9 @@ class CORE_EXPORT NGInlineCursor {
// See also |TryToMoveToFirstChild()|.
void MoveToFirstChild();
+ // Move to the first line.
+ void MoveToFirstLine();
+
// Move to first logical leaf of current line box. If current line box has
// no children, curosr becomes null.
void MoveToFirstLogicalLeaf();
@@ -253,6 +329,9 @@ class CORE_EXPORT NGInlineCursor {
// See also |TryToMoveToFirstChild()|.
void MoveToLastChild();
+ // Move the current position to the last fragment on same layout object.
+ void MoveToLastForSameLayoutObject();
+
// Move to last logical leaf of current line box. If current line box has
// no children, curosr becomes null.
void MoveToLastLogicalLeaf();
@@ -269,6 +348,7 @@ class CORE_EXPORT NGInlineCursor {
void MoveToNextLine();
// Move the current position to next sibling fragment.
+ // |MoveToNextSibling()| is deprecated. New code should not be used.
void MoveToNextSibling();
// Same as |MoveToNext| except that this skips children even if they exist.
@@ -304,14 +384,13 @@ class CORE_EXPORT NGInlineCursor {
// TODO(kojii): Add more variations as needed, NextSibling,
// NextSkippingChildren, Previous, etc.
- private:
- // Returns break token for line box. It is error to call other than line box.
- const NGInlineBreakToken& CurrentInlineBreakToken() const;
-
- // Returns style variant of the current position.
- NGStyleVariant CurrentStyleVariant() const;
- bool UsesFirstLineStyle() const;
+#if DCHECK_IS_ON()
+ void CheckValid(const NGInlineCursorPosition& position) const;
+#else
+ void CheckValid(const NGInlineCursorPosition&) const {}
+#endif
+ private:
// True if current position is part of culled inline box |layout_inline|.
bool IsPartOfCulledInlineBox(const LayoutInline& layout_inline) const;
@@ -326,9 +405,6 @@ class CORE_EXPORT NGInlineCursor {
// Move the cursor position to the first fragment in tree.
void MoveToFirst();
- // Move the current position to the last fragment on same layout object.
- void MoveToLastForSameLayoutObject();
-
// Same as |MoveTo()| but not support culled inline.
void InternalMoveTo(const LayoutObject& layout_object);
@@ -350,13 +426,20 @@ class CORE_EXPORT NGInlineCursor {
void MoveToPreviousPaintFragment();
void MoveToPreviousSiblingPaintFragment();
+ ItemsSpan::iterator SlowFirstItemIteratorFor(
+ const LayoutObject& layout_object) const;
+ unsigned SpanIndexFromItemIndex(unsigned index) const;
+
+ PositionWithAffinity PositionForPointInChild(
+ const PhysicalOffset& point,
+ const NGFragmentItem& child_item) const;
+
+ NGInlineCursorPosition current_;
+
ItemsSpan items_;
- ItemsSpan::iterator item_iter_;
- const NGFragmentItem* current_item_ = nullptr;
const NGFragmentItems* fragment_items_ = nullptr;
const NGPaintFragment* root_paint_fragment_ = nullptr;
- const NGPaintFragment* current_paint_fragment_ = nullptr;
// Used in |MoveToNextForSameLayoutObject()| to support culled inline.
const LayoutInline* layout_inline_ = nullptr;
@@ -370,31 +453,25 @@ class CORE_EXPORT NGInlineBackwardCursor {
STACK_ALLOCATED();
public:
+ // |cursor| should be the first child of root or descendants, e.g. the first
+ // item in |NGInlineCursor::items_|.
NGInlineBackwardCursor(const NGInlineCursor& cursor);
- NGInlineCursor CursorForDescendants() const;
-
- explicit operator bool() const {
- return current_paint_fragment_ || current_item_;
- }
-
- const NGFragmentItem* CurrentItem() const { return current_item_; }
- const NGPaintFragment* CurrentPaintFragment() const {
- return current_paint_fragment_;
- }
+ const NGInlineCursorPosition& Current() const { return current_; }
+ operator bool() const { return Current(); }
- const PhysicalOffset CurrentOffset() const;
- const PhysicalRect CurrentSelfInkOverflow() const;
+ NGInlineCursor CursorForDescendants() const;
void MoveToPreviousSibling();
private:
+ NGInlineCursorPosition current_;
const NGInlineCursor& cursor_;
Vector<const NGPaintFragment*, 16> sibling_paint_fragments_;
Vector<NGInlineCursor::ItemsSpan::iterator, 16> sibling_item_iterators_;
- const NGPaintFragment* current_paint_fragment_ = nullptr;
- const NGFragmentItem* current_item_ = nullptr;
wtf_size_t current_index_;
+
+ friend class NGInlineCursor;
};
CORE_EXPORT std::ostream& operator<<(std::ostream&, const NGInlineCursor&);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc
index 8ded96613d1..8398da81ecb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor_test.cc
@@ -53,7 +53,7 @@ class NGInlineCursorTest : public NGLayoutTest,
Vector<const NGPaintFragment*> backwards;
for (NGInlineBackwardCursor cursor(start); cursor;
cursor.MoveToPreviousSibling())
- backwards.push_back(cursor.CurrentPaintFragment());
+ backwards.push_back(cursor.Current().PaintFragment());
backwards.Reverse();
EXPECT_THAT(backwards, forwards);
return;
@@ -65,16 +65,16 @@ class NGInlineCursorTest : public NGLayoutTest,
Vector<const NGFragmentItem*> backwards;
for (NGInlineBackwardCursor cursor(start); cursor;
cursor.MoveToPreviousSibling())
- backwards.push_back(cursor.CurrentItem());
+ backwards.push_back(cursor.Current().Item());
backwards.Reverse();
EXPECT_THAT(backwards, forwards);
}
String ToDebugString(const NGInlineCursor& cursor) {
- if (cursor.IsLineBox())
+ if (cursor.Current().IsLineBox())
return "#linebox";
- if (cursor.IsGeneratedTextType()) {
+ if (cursor.Current().IsGeneratedTextType()) {
StringBuilder result;
result.Append("#'");
result.Append(cursor.CurrentText());
@@ -82,10 +82,11 @@ class NGInlineCursorTest : public NGLayoutTest,
return result.ToString();
}
- if (cursor.IsText())
+ if (cursor.Current().IsText())
return cursor.CurrentText().ToString().StripWhiteSpace();
- if (const LayoutObject* layout_object = cursor.CurrentLayoutObject()) {
+ if (const LayoutObject* layout_object =
+ cursor.Current().GetLayoutObject()) {
if (const Element* element =
DynamicTo<Element>(layout_object->GetNode())) {
if (const AtomicString& id = element->GetIdAttribute())
@@ -100,18 +101,22 @@ class NGInlineCursorTest : public NGLayoutTest,
Vector<String> ToDebugStringListWithBidiLevel(const NGInlineCursor& start) {
Vector<String> list;
- for (NGInlineCursor cursor(start); cursor; cursor.MoveToNext())
+ for (NGInlineCursor cursor(start); cursor; cursor.MoveToNext()) {
+ // Inline boxes do not have bidi level.
+ if (cursor.Current().IsInlineBox())
+ continue;
list.push_back(ToDebugStringWithBidiLevel(cursor));
+ }
return list;
}
String ToDebugStringWithBidiLevel(const NGInlineCursor& cursor) {
- if (!cursor.IsText() && !cursor.IsAtomicInline())
+ if (!cursor.Current().IsText() && !cursor.Current().IsAtomicInline())
return ToDebugString(cursor);
StringBuilder result;
result.Append(ToDebugString(cursor));
result.Append(':');
- result.AppendNumber(cursor.CurrentBidiLevel());
+ result.AppendNumber(cursor.Current().BidiLevel());
return result.ToString();
}
};
@@ -126,8 +131,8 @@ TEST_P(NGInlineCursorTest, BidiLevelInlineBoxLTR) {
"<div id=root dir=ltr>"
"abc<b id=def>def</b><bdo dir=rtl><b id=ghi>GHI</b></bdo>jkl</div>");
Vector<String> list = ToDebugStringListWithBidiLevel(cursor);
- EXPECT_THAT(list, ElementsAre("#linebox", "abc:0", "#def:0",
- "LayoutInline BDO", "#ghi:1", "jkl:0"));
+ EXPECT_THAT(list,
+ ElementsAre("#linebox", "abc:0", "#def:0", "#ghi:1", "jkl:0"));
}
TEST_P(NGInlineCursorTest, BidiLevelInlineBoxRTL) {
@@ -136,8 +141,8 @@ TEST_P(NGInlineCursorTest, BidiLevelInlineBoxRTL) {
"<div id=root dir=rtl>"
"abc<b id=def>def</b><bdo dir=rtl><b id=ghi>GHI</b></bdo>jkl</div>");
Vector<String> list = ToDebugStringListWithBidiLevel(cursor);
- EXPECT_THAT(list, ElementsAre("#linebox", "LayoutInline BDO", "#ghi:3",
- "jkl:2", "#def:1", "abc:2"));
+ EXPECT_THAT(list,
+ ElementsAre("#linebox", "#ghi:3", "jkl:2", "#def:1", "abc:2"));
}
TEST_P(NGInlineCursorTest, BidiLevelSimpleLTR) {
@@ -163,7 +168,7 @@ TEST_P(NGInlineCursorTest, BidiLevelSimpleRTL) {
TEST_P(NGInlineCursorTest, GetLayoutBlockFlowWithScopedCursor) {
NGInlineCursor line = SetupCursor("<div id=root>line1<br>line2</div>");
- ASSERT_TRUE(line.IsLineBox()) << line;
+ ASSERT_TRUE(line.Current().IsLineBox()) << line;
NGInlineCursor cursor = line.CursorForDescendants();
EXPECT_EQ(line.GetLayoutBlockFlow(), cursor.GetLayoutBlockFlow());
}
@@ -175,11 +180,11 @@ TEST_P(NGInlineCursorTest, ContainingLine) {
SetupCursor("<div id=root>abc<a id=target>def</a>ghi<br>xyz</div>");
const LayoutBlockFlow& block_flow = *cursor.GetLayoutBlockFlow();
NGInlineCursor line1(cursor);
- ASSERT_TRUE(line1.IsLineBox());
+ ASSERT_TRUE(line1.Current().IsLineBox());
NGInlineCursor line2(line1);
line2.MoveToNextSibling();
- ASSERT_TRUE(line2.IsLineBox());
+ ASSERT_TRUE(line2.Current().IsLineBox());
cursor.MoveTo(*block_flow.FirstChild());
cursor.MoveToContainingLine();
@@ -212,9 +217,14 @@ TEST_P(NGInlineCursorTest, CulledInlineWithAtomicInline) {
list.push_back(ToDebugString(cursor));
cursor.MoveToNextForSameLayoutObject();
}
- EXPECT_THAT(list, ElementsAre("abc", "ABC", "", "XYZ", "xyz"));
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ EXPECT_THAT(list, ElementsAre("#culled", "#culled"));
+ else
+ EXPECT_THAT(list, ElementsAre("abc", "ABC", "", "XYZ", "xyz"));
}
+// We should not have float:right fragment, because it isn't in-flow in
+// an inline formatting context.
// For https://crbug.com/1026022
TEST_P(NGInlineCursorTest, CulledInlineWithFloat) {
SetBodyInnerHTML(
@@ -228,23 +238,27 @@ TEST_P(NGInlineCursorTest, CulledInlineWithFloat) {
list.push_back(ToDebugString(cursor));
cursor.MoveToNextForSameLayoutObject();
}
- EXPECT_THAT(list, ElementsAre("abc", "xyz"))
- << "We should not have float:right fragment, because it isn't in-flow in "
- "an inline formatting context.";
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ EXPECT_THAT(list, ElementsAre("#culled"));
+ else
+ EXPECT_THAT(list, ElementsAre("abc", "xyz"));
}
TEST_P(NGInlineCursorTest, CulledInlineWithRoot) {
- NGInlineCursor cursor =
- SetupCursor("<div id=root><a><b>abc</b><br><i>xyz</i></a></div>");
- const LayoutInline& layout_inline =
- ToLayoutInline(*cursor.GetLayoutBlockFlow()->FirstChild());
- cursor.MoveTo(layout_inline);
+ NGInlineCursor cursor = SetupCursor(R"HTML(
+ <div id="root"><a id="a"><b>abc</b><br><i>xyz</i></a></div>
+ )HTML");
+ const LayoutObject* layout_inline_a = GetLayoutObjectByElementId("a");
+ cursor.MoveTo(*layout_inline_a);
Vector<String> list;
while (cursor) {
list.push_back(ToDebugString(cursor));
cursor.MoveToNextForSameLayoutObject();
}
- EXPECT_THAT(list, ElementsAre("abc", "", "xyz"));
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ EXPECT_THAT(list, ElementsAre("#a", "#a"));
+ else
+ EXPECT_THAT(list, ElementsAre("abc", "", "xyz"));
}
TEST_P(NGInlineCursorTest, CulledInlineWithoutRoot) {
@@ -259,7 +273,10 @@ TEST_P(NGInlineCursorTest, CulledInlineWithoutRoot) {
list.push_back(ToDebugString(cursor));
cursor.MoveToNextForSameLayoutObject();
}
- EXPECT_THAT(list, ElementsAre("abc", "", "xyz"));
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ EXPECT_THAT(list, ElementsAre("#a", "#a"));
+ else
+ EXPECT_THAT(list, ElementsAre("abc", "", "xyz"));
}
TEST_P(NGInlineCursorTest, FirstChild) {
@@ -367,6 +384,17 @@ TEST_P(NGInlineCursorTest, FirstLastLogicalLeafWithImages) {
EXPECT_EQ("#last", ToDebugString(last_logical_leaf));
}
+TEST_P(NGInlineCursorTest, IsEmptyLineBox) {
+ InsertStyleElement("b { margin-bottom: 1px; }");
+ NGInlineCursor cursor = SetupCursor("<div id=root>abc<br><b></b></div>");
+
+ EXPECT_FALSE(cursor.Current().IsEmptyLineBox())
+ << "'abc\\n' is in non-empty line box.";
+ cursor.MoveToNextLine();
+ EXPECT_TRUE(cursor.Current().IsEmptyLineBox())
+ << "<b></b> with margin produces empty line box.";
+}
+
TEST_P(NGInlineCursorTest, LastChild) {
// TDOO(yosin): Remove <style> once NGFragmentItem don't do culled inline.
InsertStyleElement("a, b { background: gray; }");
@@ -431,11 +459,27 @@ TEST_P(NGInlineCursorTest, NextWithEllipsis) {
EXPECT_THAT(list, ElementsAre("#linebox", "abcdefghi", "abcd", u"#'\u2026'"));
}
+TEST_P(NGInlineCursorTest, NextWithEllipsisInlineBoxOnly) {
+ LoadAhem();
+ InsertStyleElement(
+ "#root {"
+ "font: 10px/1 Ahem;"
+ "width: 5ch;"
+ "overflow: hidden;"
+ "text-overflow: ellipsis;"
+ "}"
+ "span { border: solid 10ch blue; }");
+ NGInlineCursor cursor = SetupCursor("<div id=root><span></span></div>");
+ Vector<String> list = ToDebugStringList(cursor);
+ EXPECT_THAT(list, ElementsAre("#linebox", "LayoutInline SPAN"));
+}
+
TEST_P(NGInlineCursorTest, NextWithListItem) {
NGInlineCursor cursor = SetupCursor("<ul><li id=root>abc</li></ul>");
Vector<String> list = ToDebugStringList(cursor);
- EXPECT_THAT(list,
- ElementsAre("LayoutNGListMarker (anonymous)", "#linebox", "abc"));
+ EXPECT_THAT(list, ElementsAre("LayoutNGOutsideListMarker ::marker",
+ "#linebox", "abc"));
+ EXPECT_EQ(GetLayoutObjectByElementId("root"), cursor.GetLayoutBlockFlow());
}
TEST_P(NGInlineCursorTest, NextWithSoftHyphens) {
@@ -546,12 +590,12 @@ TEST_P(NGInlineCursorTest, NextInlineLeafIgnoringLineBreak) {
TEST_P(NGInlineCursorTest, NextLine) {
NGInlineCursor cursor = SetupCursor("<div id=root>abc<br>xyz</div>");
NGInlineCursor line1(cursor);
- while (line1 && !line1.IsLineBox())
+ while (line1 && !line1.Current().IsLineBox())
line1.MoveToNext();
ASSERT_TRUE(line1.IsNotNull());
NGInlineCursor line2(line1);
line2.MoveToNext();
- while (line2 && !line2.IsLineBox())
+ while (line2 && !line2.Current().IsLineBox())
line2.MoveToNext();
ASSERT_NE(line1, line2);
@@ -576,6 +620,10 @@ TEST_P(NGInlineCursorTest, NextWithInlineBox) {
SetupCursor("<div id=root>abc<b id=ib>def</b>xyz</div>");
Vector<String> list = ToDebugStringList(cursor);
EXPECT_THAT(list, ElementsAre("#linebox", "abc", "#ib", "xyz"));
+
+ NGInlineCursor cursor2;
+ cursor2.MoveTo(*GetElementById("ib")->firstChild()->GetLayoutObject());
+ EXPECT_EQ(GetLayoutObjectByElementId("ib"), cursor2.GetLayoutBlockFlow());
}
TEST_P(NGInlineCursorTest, NextForSameLayoutObject) {
@@ -594,10 +642,10 @@ TEST_P(NGInlineCursorTest, Sibling) {
InsertStyleElement("a, b { background: gray; }");
NGInlineCursor cursor =
SetupCursor("<div id=root>abc<a>DEF<b>GHI</b></a>xyz</div>");
+ TestPrevoiusSibling(cursor.CursorForDescendants());
cursor.MoveToFirstChild(); // go to "abc"
Vector<String> list = SiblingsToDebugStringList(cursor);
EXPECT_THAT(list, ElementsAre("abc", "LayoutInline A", "xyz"));
- TestPrevoiusSibling(cursor);
}
TEST_P(NGInlineCursorTest, Sibling2) {
@@ -606,10 +654,10 @@ TEST_P(NGInlineCursorTest, Sibling2) {
NGInlineCursor cursor =
SetupCursor("<div id=root><a>abc<b>def</b>xyz</a></div>");
cursor.MoveToFirstChild(); // go to <a>abc</a>
+ TestPrevoiusSibling(cursor.CursorForDescendants());
cursor.MoveToFirstChild(); // go to "abc"
Vector<String> list = SiblingsToDebugStringList(cursor);
EXPECT_THAT(list, ElementsAre("abc", "LayoutInline B", "xyz"));
- TestPrevoiusSibling(cursor);
}
TEST_P(NGInlineCursorTest, NextSkippingChildren) {
@@ -741,12 +789,12 @@ TEST_P(NGInlineCursorTest, PreviousInlineLeafOnLineFromLayoutText) {
TEST_P(NGInlineCursorTest, PreviousLine) {
NGInlineCursor cursor = SetupCursor("<div id=root>abc<br>xyz</div>");
NGInlineCursor line1(cursor);
- while (line1 && !line1.IsLineBox())
+ while (line1 && !line1.Current().IsLineBox())
line1.MoveToNext();
ASSERT_TRUE(line1.IsNotNull());
NGInlineCursor line2(line1);
line2.MoveToNext();
- while (line2 && !line2.IsLineBox())
+ while (line2 && !line2.Current().IsLineBox())
line2.MoveToNext();
ASSERT_NE(line1, line2);
@@ -784,9 +832,9 @@ TEST_P(NGInlineCursorTest, CursorForDescendants) {
LayoutBlockFlow* block_flow =
To<LayoutBlockFlow>(GetLayoutObjectByElementId("root"));
NGInlineCursor cursor(*block_flow);
- EXPECT_TRUE(cursor.IsLineBox());
+ EXPECT_TRUE(cursor.Current().IsLineBox());
cursor.MoveToNext();
- EXPECT_TRUE(cursor.IsText());
+ EXPECT_TRUE(cursor.Current().IsText());
EXPECT_THAT(ToDebugStringList(cursor.CursorForDescendants()), ElementsAre());
cursor.MoveToNext();
EXPECT_EQ(ToDebugString(cursor), "#span1");
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc
index d9aa540d902..443c9070088 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc
@@ -62,13 +62,13 @@ class NGPhysicalFragmentCollectorBase {
// Traverse descendants unless the fragment is laid out separately from the
// inline layout algorithm.
- if (&fragment != root_fragment_ && fragment.IsBlockFormattingContextRoot())
+ if (&fragment != root_fragment_ && fragment.IsFormattingContextRoot())
return;
DCHECK(fragment.IsContainer());
DCHECK(fragment.IsInline() || fragment.IsLineBox() ||
(fragment.IsBlockFlow() &&
- To<NGPhysicalBoxFragment>(fragment).ChildrenInline()));
+ To<NGPhysicalBoxFragment>(fragment).IsInlineFormattingContext()));
for (const auto& child :
To<NGPhysicalContainerFragment>(fragment).Children()) {
@@ -179,7 +179,7 @@ Vector<Result> NGInlineFragmentTraversal::SelfFragmentsOf(
for (const NGPaintFragment* fragment :
NGPaintFragment::InlineFragmentsFor(layout_object)) {
result.push_back(Result{&fragment->PhysicalFragment(),
- fragment->InlineOffsetToContainerBox()});
+ fragment->OffsetInContainerBlock()});
}
return result;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc
index e9ab83060fe..d356f218bbf 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc
@@ -50,6 +50,10 @@ class NGInlineFragmentTraversalTest : public NGLayoutTest {
}
TEST_F(NGInlineFragmentTraversalTest, DescendantsOf) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ // NGFragmentItem doesn't use |NGInlineFragmentTraversal|.
+ return;
+ }
SetBodyInnerHTML(
"<style>* { border: 1px solid}</style>"
"<div id=t>foo<b id=b>bar</b><br>baz</div>");
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
index 1e17b432948..bb809f51b2b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc
@@ -60,7 +60,8 @@ bool IsInlineBoxEndEmpty(const ComputedStyle& style,
NGInlineItem::NGInlineItem(NGInlineItemType type,
unsigned start,
unsigned end,
- LayoutObject* layout_object)
+ LayoutObject* layout_object,
+ bool is_first_for_node)
: start_offset_(start),
end_offset_(end),
layout_object_(layout_object),
@@ -74,7 +75,8 @@ NGInlineItem::NGInlineItem(NGInlineItemType type,
end_collapse_type_(kNotCollapsible),
is_end_collapsible_newline_(false),
is_symbol_marker_(false),
- is_generated_for_line_break_(false) {
+ is_generated_for_line_break_(false),
+ is_first_for_node_(is_first_for_node) {
DCHECK_GE(end, start);
ComputeBoxProperties();
}
@@ -97,7 +99,8 @@ NGInlineItem::NGInlineItem(const NGInlineItem& other,
end_collapse_type_(other.end_collapse_type_),
is_end_collapsible_newline_(other.is_end_collapsible_newline_),
is_symbol_marker_(other.is_symbol_marker_),
- is_generated_for_line_break_(other.is_generated_for_line_break_) {
+ is_generated_for_line_break_(other.is_generated_for_line_break_),
+ is_first_for_node_(other.is_first_for_node_) {
DCHECK_GE(end, start);
}
@@ -197,6 +200,7 @@ void NGInlineItem::Split(Vector<NGInlineItem>& items,
items.insert(index + 1, items[index]);
items[index].end_offset_ = offset;
items[index + 1].start_offset_ = offset;
+ items[index + 1].is_first_for_node_ = false;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
index 018e02db8d5..5a8575d3a51 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h
@@ -66,7 +66,8 @@ class CORE_EXPORT NGInlineItem {
NGInlineItem(NGInlineItemType type,
unsigned start,
unsigned end,
- LayoutObject* layout_object = nullptr);
+ LayoutObject* layout_object,
+ bool is_first_for_node);
~NGInlineItem();
// Copy constructor adjusting start/end and shape results.
@@ -199,6 +200,11 @@ class CORE_EXPORT NGInlineItem {
static void Split(Vector<NGInlineItem>&, unsigned index, unsigned offset);
+ // Return true if this is the first item created for the node. A node may be
+ // split into multiple inline items due e.g. hard line breaks or bidi
+ // segments.
+ bool IsFirstForNode() const { return is_first_for_node_; }
+
// RunSegmenter properties.
unsigned SegmentData() const { return segment_data_; }
static void SetSegmentData(const RunSegmenter::RunSegmenterRange& range,
@@ -253,6 +259,7 @@ class CORE_EXPORT NGInlineItem {
unsigned is_end_collapsible_newline_ : 1;
unsigned is_symbol_marker_ : 1;
unsigned is_generated_for_line_break_ : 1;
+ unsigned is_first_for_node_ : 1;
friend class NGInlineNode;
friend class NGInlineNodeDataEditor;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc
index 801aaf305c2..b6e4388cefb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc
@@ -220,18 +220,7 @@ LayoutUnit NGLineInfo::ComputeWidth() const {
for (const NGInlineItemResult& item_result : Results())
inline_size += item_result.inline_size;
- if (UNLIKELY(line_end_fragment_)) {
- inline_size += line_end_fragment_->Size()
- .ConvertToLogical(LineStyle().GetWritingMode())
- .inline_size;
- }
-
return inline_size;
}
-void NGLineInfo::SetLineEndFragment(
- scoped_refptr<const NGPhysicalTextFragment> fragment) {
- line_end_fragment_ = std::move(fragment);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
index c55dfae46de..2015830ed2c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h
@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_end_effect.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
@@ -37,6 +36,15 @@ struct CORE_EXPORT NGInlineItemResult {
return end_offset - start_offset;
}
+ LayoutUnit HyphenInlineSize() const {
+ return hyphen_shape_result->SnappedWidth().ClampNegativeToZero();
+ }
+
+ void ClearHyphen() {
+ hyphen_string = String();
+ hyphen_shape_result = nullptr;
+ }
+
// The NGInlineItem and its index.
const NGInlineItem* item;
unsigned item_index;
@@ -52,6 +60,10 @@ struct CORE_EXPORT NGInlineItemResult {
// is needed in the line breaker.
scoped_refptr<const ShapeResultView> shape_result;
+ // Hyphen character and its |ShapeResult| if this text is hyphenated.
+ String hyphen_string;
+ scoped_refptr<const ShapeResult> hyphen_shape_result;
+
// NGLayoutResult for atomic inline items.
scoped_refptr<const NGLayoutResult> layout_result;
@@ -112,10 +124,6 @@ struct CORE_EXPORT NGInlineItemResult {
// position) any unpositioned floats.
bool has_unpositioned_floats = false;
- // End effects for text items.
- // The effects are included in |shape_result|, but not in text content.
- NGTextEndEffect text_end_effect = NGTextEndEffect::kNone;
-
NGInlineItemResult();
NGInlineItemResult(const NGInlineItem*,
unsigned index,
@@ -139,7 +147,7 @@ using NGInlineItemResults = Vector<NGInlineItemResult, 32>;
//
// NGLineBreaker produces, and NGInlineLayoutAlgorithm consumes.
class CORE_EXPORT NGLineInfo {
- DISALLOW_NEW();
+ STACK_ALLOCATED();
public:
const NGInlineItemsData& ItemsData() const {
@@ -208,7 +216,7 @@ class CORE_EXPORT NGLineInfo {
// True if this line has overflow, excluding preserved trailing spaces.
bool HasOverflow() const { return has_overflow_; }
- void SetHasOverflow() { has_overflow_ = true; }
+ void SetHasOverflow(bool value = true) { has_overflow_ = value; }
void SetBfcOffset(const NGBfcOffset& bfc_offset) { bfc_offset_ = bfc_offset; }
void SetWidth(LayoutUnit available_width, LayoutUnit width) {
@@ -242,12 +250,6 @@ class CORE_EXPORT NGLineInfo {
// justify alignment.
bool NeedsAccurateEndPosition() const { return needs_accurate_end_position_; }
- // Fragment to append to the line end. Used by 'text-overflow: ellipsis'.
- scoped_refptr<const NGPhysicalTextFragment>& LineEndFragment() {
- return line_end_fragment_;
- }
- void SetLineEndFragment(scoped_refptr<const NGPhysicalTextFragment>);
-
private:
bool ComputeNeedsAccurateEndPosition() const;
@@ -258,7 +260,6 @@ class CORE_EXPORT NGLineInfo {
const NGInlineItemsData* items_data_ = nullptr;
const ComputedStyle* line_style_ = nullptr;
NGInlineItemResults results_;
- scoped_refptr<const NGPhysicalTextFragment> line_end_fragment_;
NGBfcOffset bfc_offset_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
index 744cff0d35a..84d422cbc20 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc
@@ -128,8 +128,10 @@ void AppendItem(Vector<NGInlineItem>* items,
NGInlineItem::NGInlineItemType type,
unsigned start,
unsigned end,
- LayoutObject* layout_object = nullptr) {
- items->push_back(NGInlineItem(type, start, end, layout_object));
+ LayoutObject* layout_object,
+ bool is_first_for_node = true) {
+ items->push_back(
+ NGInlineItem(type, start, end, layout_object, is_first_for_node));
}
inline bool ShouldIgnore(UChar c) {
@@ -197,8 +199,8 @@ NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::BoxInfo::BoxInfo(
const NGInlineItem& item)
: item_index(item_index),
should_create_box_fragment(item.ShouldCreateBoxFragment()),
- style(*item.Style()),
- text_metrics(NGLineHeightMetrics(style)) {
+ may_have_margin_(item.Style()->MayHaveMargin()),
+ text_metrics(NGLineHeightMetrics(*item.Style())) {
DCHECK(item.Style());
}
@@ -208,7 +210,7 @@ bool NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::BoxInfo::
ShouldCreateBoxFragmentForChild(const BoxInfo& child) const {
// When a child inline box has margins, the parent has different width/height
// from the union of children.
- if (child.style.MayHaveMargin())
+ if (child.may_have_margin_)
return true;
// Returns true when parent and child boxes have different font metrics, since
@@ -231,21 +233,24 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::BoxInfo::
template <typename OffsetMappingBuilder>
void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendTextItem(
const StringView string,
- LayoutText* layout_object) {
+ LayoutText* layout_object,
+ bool is_first_for_node) {
DCHECK(layout_object);
- AppendTextItem(NGInlineItem::kText, string, layout_object);
+ AppendTextItem(NGInlineItem::kText, string, layout_object, is_first_for_node);
}
template <typename OffsetMappingBuilder>
void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendTextItem(
NGInlineItem::NGInlineItemType type,
const StringView string,
- LayoutText* layout_object) {
+ LayoutText* layout_object,
+ bool is_first_for_node) {
DCHECK(layout_object);
unsigned start_offset = text_.length();
text_.Append(string);
mapping_builder_.AppendIdentityMapping(string.length());
- AppendItem(items_, type, start_offset, text_.length(), layout_object);
+ AppendItem(items_, type, start_offset, text_.length(), layout_object,
+ is_first_for_node);
DCHECK(!items_->back().IsEmptyItem());
// text item is not empty.
is_empty_inline_ = false;
@@ -501,7 +506,8 @@ template <typename OffsetMappingBuilder>
void NGInlineItemsBuilderTemplate<
OffsetMappingBuilder>::AppendCollapseWhitespace(const StringView string,
const ComputedStyle* style,
- LayoutText* layout_object) {
+ LayoutText* layout_object,
+ bool is_first_for_node) {
DCHECK(!string.IsEmpty());
// This algorithm segments the input string at the collapsible space, and
@@ -528,7 +534,7 @@ void NGInlineItemsBuilderTemplate<
// LayoutBR does not set preserve_newline, but should be preserved.
if (UNLIKELY(space_run_has_newline && string.length() == 1 &&
layout_object && layout_object->IsBR())) {
- AppendForcedBreakCollapseWhitespace(layout_object);
+ AppendForcedBreakCollapseWhitespace(layout_object, is_first_for_node);
return;
}
@@ -685,7 +691,7 @@ void NGInlineItemsBuilderTemplate<
}
AppendItem(items_, NGInlineItem::kText, start_offset, text_.length(),
- layout_object);
+ layout_object, is_first_for_node);
NGInlineItem& item = items_->back();
item.SetEndCollapseType(end_collapse, space_run_has_newline);
DCHECK(!item.IsEmptyItem());
@@ -727,7 +733,8 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::
do {
++end;
} while (end < string.length() && string[end] == kSpaceCharacter);
- AppendTextItem(StringView(string, *start, end - *start), layout_object);
+ AppendTextItem(StringView(string, *start, end - *start), layout_object,
+ /* is_first_for_node */ false);
AppendGeneratedBreakOpportunity(layout_object);
*start = end;
}
@@ -752,11 +759,12 @@ void NGInlineItemsBuilderTemplate<
unsigned start = 0;
InsertBreakOpportunityAfterLeadingPreservedSpaces(string, *style,
layout_object, &start);
- for (; start < string.length();) {
+ bool is_first_for_node = true;
+ for (; start < string.length(); is_first_for_node = false) {
UChar c = string[start];
if (IsControlItemCharacter(c)) {
if (c == kNewlineCharacter) {
- AppendForcedBreak(layout_object);
+ AppendForcedBreak(layout_object, is_first_for_node);
start++;
// A forced break is not a collapsible space, but following collapsible
// spaces are leading spaces and they need a special code in the line
@@ -771,13 +779,14 @@ void NGInlineItemsBuilderTemplate<
if (end == kNotFound)
end = string.length();
AppendTextItem(NGInlineItem::kControl,
- StringView(string, start, end - start), layout_object);
+ StringView(string, start, end - start), layout_object,
+ is_first_for_node);
start = end;
continue;
}
// ZWNJ splits item, but it should be text.
if (c != kZeroWidthNonJoinerCharacter) {
- Append(NGInlineItem::kControl, c, layout_object);
+ Append(NGInlineItem::kControl, c, layout_object, is_first_for_node);
start++;
continue;
}
@@ -786,7 +795,8 @@ void NGInlineItemsBuilderTemplate<
wtf_size_t end = string.Find(IsControlItemCharacter, start + 1);
if (end == kNotFound)
end = string.length();
- AppendTextItem(StringView(string, start, end - start), layout_object);
+ AppendTextItem(StringView(string, start, end - start), layout_object,
+ is_first_for_node);
start = end;
}
}
@@ -796,9 +806,10 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendPreserveNewline(
const String& string,
const ComputedStyle* style,
LayoutText* layout_object) {
- for (unsigned start = 0; start < string.length();) {
+ bool is_first_for_node = true;
+ for (unsigned start = 0; start < string.length(); is_first_for_node = false) {
if (string[start] == kNewlineCharacter) {
- AppendForcedBreakCollapseWhitespace(layout_object);
+ AppendForcedBreakCollapseWhitespace(layout_object, is_first_for_node);
start++;
continue;
}
@@ -808,14 +819,15 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendPreserveNewline(
end = string.length();
DCHECK_GE(end, start);
AppendCollapseWhitespace(StringView(string, start, end - start), style,
- layout_object);
+ layout_object, is_first_for_node);
start = end;
}
}
template <typename OffsetMappingBuilder>
void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendForcedBreak(
- LayoutObject* layout_object) {
+ LayoutObject* layout_object,
+ bool is_first_for_node) {
DCHECK(layout_object);
// At the forced break, add bidi controls to pop all contexts.
// https://drafts.csswg.org/css-writing-modes-3/#bidi-embedding-breaks
@@ -829,7 +841,8 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendForcedBreak(
}
}
- Append(NGInlineItem::kControl, kNewlineCharacter, layout_object);
+ Append(NGInlineItem::kControl, kNewlineCharacter, layout_object,
+ is_first_for_node);
// A forced break is not a collapsible space, but following collapsible spaces
// are leading spaces and that they should be collapsed.
@@ -849,11 +862,12 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendForcedBreak(
template <typename OffsetMappingBuilder>
void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::
- AppendForcedBreakCollapseWhitespace(LayoutObject* layout_object) {
+ AppendForcedBreakCollapseWhitespace(LayoutObject* layout_object,
+ bool is_first_for_node) {
// Remove collapsible spaces immediately before a preserved newline.
RemoveTrailingCollapsibleSpaceIfExists();
- AppendForcedBreak(layout_object);
+ AppendForcedBreak(layout_object, is_first_for_node);
}
template <typename OffsetMappingBuilder>
@@ -867,13 +881,15 @@ template <typename OffsetMappingBuilder>
void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::Append(
NGInlineItem::NGInlineItemType type,
UChar character,
- LayoutObject* layout_object) {
+ LayoutObject* layout_object,
+ bool is_first_for_node) {
DCHECK_NE(character, kSpaceCharacter);
text_.Append(character);
mapping_builder_.AppendIdentityMapping(1);
unsigned end_offset = text_.length();
- AppendItem(items_, type, end_offset - 1, end_offset, layout_object);
+ AppendItem(items_, type, end_offset - 1, end_offset, layout_object,
+ is_first_for_node);
is_empty_inline_ &= items_->back().IsEmptyItem();
is_block_level_ &= items_->back().IsBlockLevel();
@@ -887,7 +903,7 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::AppendAtomicInline(
layout_object);
RestoreTrailingCollapsibleSpaceIfRemoved();
Append(NGInlineItem::kAtomicInline, kObjectReplacementCharacter,
- layout_object);
+ layout_object, /* is_first_for_node */ true);
// Mark dirty lines. Clear if marked, only the first dirty line is relevant.
if (dirty_lines_ &&
@@ -1231,6 +1247,27 @@ void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::Exit(
}
template <typename OffsetMappingBuilder>
+bool NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::MayBeBidiEnabled()
+ const {
+ return !text_.Is8Bit() || HasBidiControls();
+}
+
+template <typename OffsetMappingBuilder>
+void NGInlineItemsBuilderTemplate<
+ OffsetMappingBuilder>::DidFinishCollectInlines(NGInlineNodeData* data) {
+ data->text_content = ToString();
+
+ // Set |is_bidi_enabled_| for all UTF-16 strings for now, because at this
+ // point the string may or may not contain RTL characters.
+ // |SegmentText()| will analyze the text and reset |is_bidi_enabled_| if it
+ // doesn't contain any RTL characters.
+ data->is_bidi_enabled_ = MayBeBidiEnabled();
+ data->is_empty_inline_ = IsEmptyInline();
+ data->is_block_level_ = IsBlockLevel();
+ data->changes_may_affect_earlier_lines_ = ChangesMayAffectEarlierLines();
+}
+
+template <typename OffsetMappingBuilder>
void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::SetIsSymbolMarker(
bool b) {
DCHECK(!items_->IsEmpty());
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
index 8b0939aa096..eb58909de1d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h
@@ -134,6 +134,9 @@ class NGInlineItemsBuilderTemplate {
void EnterInline(LayoutInline*);
void ExitInline(LayoutObject*);
+ // Set collected inline items data to |data|.
+ void DidFinishCollectInlines(NGInlineNodeData* data);
+
OffsetMappingBuilder& GetOffsetMappingBuilder() { return mapping_builder_; }
void SetIsSymbolMarker(bool b);
@@ -160,9 +163,11 @@ class NGInlineItemsBuilderTemplate {
// Keep track of inline boxes to compute ShouldCreateBoxFragment.
struct BoxInfo {
+ DISALLOW_NEW();
+
unsigned item_index;
bool should_create_box_fragment;
- const ComputedStyle& style;
+ bool may_have_margin_;
NGLineHeightMetrics text_metrics;
BoxInfo(unsigned item_index, const NGInlineItem& item);
@@ -191,18 +196,21 @@ class NGInlineItemsBuilderTemplate {
// LayoutObject.
void Append(NGInlineItem::NGInlineItemType,
UChar,
- LayoutObject*);
+ LayoutObject*,
+ bool is_first_for_node);
void AppendCollapseWhitespace(const StringView,
const ComputedStyle*,
- LayoutText*);
+ LayoutText*,
+ bool is_first_for_node = true);
void AppendPreserveWhitespace(const String&,
const ComputedStyle*,
LayoutText*);
void AppendPreserveNewline(const String&, const ComputedStyle*, LayoutText*);
- void AppendForcedBreakCollapseWhitespace(LayoutObject*);
- void AppendForcedBreak(LayoutObject*);
+ void AppendForcedBreakCollapseWhitespace(LayoutObject*,
+ bool is_first_for_node);
+ void AppendForcedBreak(LayoutObject*, bool is_first_for_node);
void RemoveTrailingCollapsibleSpaceIfExists();
void RemoveTrailingCollapsibleSpace(NGInlineItem*);
@@ -211,16 +219,20 @@ class NGInlineItemsBuilderTemplate {
void RestoreTrailingCollapsibleSpace(NGInlineItem*);
void AppendTextItem(const StringView,
- LayoutText* layout_object);
+ LayoutText* layout_object,
+ bool is_first_for_node);
void AppendTextItem(NGInlineItem::NGInlineItemType type,
const StringView,
- LayoutText* layout_object);
+ LayoutText* layout_object,
+ bool is_first_for_node);
void AppendEmptyTextItem(LayoutText* layout_object);
void AppendGeneratedBreakOpportunity(LayoutObject*);
void Exit(LayoutObject*);
+ bool MayBeBidiEnabled() const;
+
bool ShouldInsertBreakOpportunityAfterLeadingPreservedSpaces(
const String&,
const ComputedStyle&,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
index df95d2fd3f6..77aff76eecc 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc
@@ -28,7 +28,6 @@ class NGInlineItemsBuilderTest : public NGLayoutTest {
void SetUp() override {
NGLayoutTest::SetUp();
style_ = ComputedStyle::Create();
- style_->GetFont().Update(nullptr);
}
void TearDown() override {
@@ -448,11 +447,12 @@ TEST_F(NGInlineItemsBuilderTest, BidiBlockOverride) {
builder.ToString());
}
-static std::unique_ptr<LayoutInline> CreateLayoutInline(
+static LayoutInline* CreateLayoutInline(
+ Document* document,
void (*initialize_style)(ComputedStyle*)) {
scoped_refptr<ComputedStyle> style(ComputedStyle::Create());
initialize_style(style.get());
- std::unique_ptr<LayoutInline> node = std::make_unique<LayoutInline>(nullptr);
+ LayoutInline* const node = LayoutInline::CreateAnonymous(document);
node->SetModifiedStyleOutsideStyleRecalc(
std::move(style), LayoutObject::ApplyStyleChanges::kNo);
node->SetIsInLayoutNGInlineFormattingContext(true);
@@ -463,14 +463,14 @@ TEST_F(NGInlineItemsBuilderTest, BidiIsolate) {
Vector<NGInlineItem> items;
NGInlineItemsBuilder builder(&items);
AppendText("Hello ", &builder);
- std::unique_ptr<LayoutInline> isolate_rtl(
- CreateLayoutInline([](ComputedStyle* style) {
+ LayoutInline* const isolate_rtl =
+ CreateLayoutInline(&GetDocument(), [](ComputedStyle* style) {
style->SetUnicodeBidi(UnicodeBidi::kIsolate);
style->SetDirection(TextDirection::kRtl);
- }));
- builder.EnterInline(isolate_rtl.get());
+ });
+ builder.EnterInline(isolate_rtl);
AppendText(u"\u05E2\u05D1\u05E8\u05D9\u05EA", &builder);
- builder.ExitInline(isolate_rtl.get());
+ builder.ExitInline(isolate_rtl);
AppendText(" World", &builder);
// Expected control characters as defined in:
@@ -481,20 +481,21 @@ TEST_F(NGInlineItemsBuilderTest, BidiIsolate) {
u"\u2069"
u" World"),
builder.ToString());
+ isolate_rtl->Destroy();
}
TEST_F(NGInlineItemsBuilderTest, BidiIsolateOverride) {
Vector<NGInlineItem> items;
NGInlineItemsBuilder builder(&items);
AppendText("Hello ", &builder);
- std::unique_ptr<LayoutInline> isolate_override_rtl(
- CreateLayoutInline([](ComputedStyle* style) {
+ LayoutInline* const isolate_override_rtl =
+ CreateLayoutInline(&GetDocument(), [](ComputedStyle* style) {
style->SetUnicodeBidi(UnicodeBidi::kIsolateOverride);
style->SetDirection(TextDirection::kRtl);
- }));
- builder.EnterInline(isolate_override_rtl.get());
+ });
+ builder.EnterInline(isolate_override_rtl);
AppendText(u"\u05E2\u05D1\u05E8\u05D9\u05EA", &builder);
- builder.ExitInline(isolate_override_rtl.get());
+ builder.ExitInline(isolate_override_rtl);
AppendText(" World", &builder);
// Expected control characters as defined in:
@@ -505,6 +506,7 @@ TEST_F(NGInlineItemsBuilderTest, BidiIsolateOverride) {
u"\u202C\u2069"
u" World"),
builder.ToString());
+ isolate_override_rtl->Destroy();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
index 732b84c0ba2..76a67f7e9eb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc
@@ -6,8 +6,9 @@
#include <memory>
+#include "base/compiler_specific.h"
#include "base/containers/adapters.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h"
+#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_bidi_paragraph.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
@@ -19,12 +20,13 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
@@ -65,7 +67,9 @@ NGInlineLayoutAlgorithm::NGInlineLayoutAlgorithm(
context_(context),
baseline_type_(container_builder_.Style().GetFontBaseline()),
is_horizontal_writing_mode_(
- blink::IsHorizontalWritingMode(space.GetWritingMode())) {
+ blink::IsHorizontalWritingMode(space.GetWritingMode())),
+ truncate_type_(
+ static_cast<unsigned>(TruncateTypeFromConstraintSpace(space))) {
DCHECK(context);
quirks_mode_ = inline_node.InLineHeightQuirksMode();
}
@@ -77,8 +81,10 @@ NGInlineLayoutAlgorithm::~NGInlineLayoutAlgorithm() = default;
NGInlineBoxState* NGInlineLayoutAlgorithm::HandleOpenTag(
const NGInlineItem& item,
const NGInlineItemResult& item_result,
+ NGLineBoxFragmentBuilder::ChildList* line_box,
NGInlineLayoutStateStack* box_states) const {
- NGInlineBoxState* box = box_states->OnOpenTag(item, item_result, line_box_);
+ NGInlineBoxState* box =
+ box_states->OnOpenTag(item, item_result, baseline_type_, line_box);
// Compute text metrics for all inline boxes since even empty inlines
// influence the line height, except when quirks mode and the box is empty
// for the purpose of empty block calculation.
@@ -103,10 +109,14 @@ NGInlineBoxState* NGInlineLayoutAlgorithm::HandleCloseTag(
box->EnsureTextMetrics(*item.Style(), baseline_type_);
box = box_states_->OnCloseTag(&line_box_, box, baseline_type_,
item.HasEndEdge());
- // Just clear |NeedsLayout| flags. Culled inline boxes do not need paint
- // invalidations. If this object produces box fragments,
- // |NGInlineBoxStateStack| takes care of invalidations.
- item.GetLayoutObject()->ClearNeedsLayoutWithoutPaintInvalidation();
+ if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ // Just clear |NeedsLayout| flags. Culled inline boxes do not need paint
+ // invalidations. If this object produces box fragments,
+ // |NGInlineBoxStateStack| takes care of invalidations.
+ item.GetLayoutObject()->ClearNeedsLayoutWithoutPaintInvalidation();
+ } else {
+ item.GetLayoutObject()->ClearNeedsLayout();
+ }
return box;
}
@@ -160,12 +170,13 @@ void NGInlineLayoutAlgorithm::RebuildBoxStates(
}
// Create box states for tags that are not closed yet.
+ NGLineBoxFragmentBuilder::ChildList line_box;
box_states->OnBeginPlaceItems(line_info.LineStyle(), baseline_type_,
- quirks_mode_);
+ quirks_mode_, &line_box);
for (const NGInlineItem* item : open_items) {
NGInlineItemResult item_result;
NGLineBreaker::ComputeOpenTagResult(*item, ConstraintSpace(), &item_result);
- HandleOpenTag(*item, item_result, box_states);
+ HandleOpenTag(*item, item_result, &line_box, box_states);
}
}
@@ -175,9 +186,9 @@ void NGInlineLayoutAlgorithm::CheckBoxStates(
const NGInlineBreakToken* break_token) const {
NGInlineLayoutStateStack rebuilt;
RebuildBoxStates(line_info, break_token, &rebuilt);
- rebuilt.OnBeginPlaceItems(line_info.LineStyle(), baseline_type_,
- quirks_mode_);
-
+ NGLineBoxFragmentBuilder::ChildList line_box;
+ rebuilt.OnBeginPlaceItems(line_info.LineStyle(), baseline_type_, quirks_mode_,
+ &line_box);
DCHECK(box_states_);
box_states_->CheckSame(rebuilt);
}
@@ -201,8 +212,8 @@ void NGInlineLayoutAlgorithm::CreateLine(
// The baseline is adjusted after the height of the line box is computed.
const ComputedStyle& line_style = line_info->LineStyle();
box_states_->SetIsEmptyLine(line_info->IsEmptyLine());
- NGInlineBoxState* box =
- box_states_->OnBeginPlaceItems(line_style, baseline_type_, quirks_mode_);
+ NGInlineBoxState* box = box_states_->OnBeginPlaceItems(
+ line_style, baseline_type_, quirks_mode_, &line_box_);
#if DCHECK_IS_ON()
if (is_box_states_from_context_)
CheckBoxStates(*line_info, BreakToken());
@@ -227,6 +238,8 @@ void NGInlineLayoutAlgorithm::CreateLine(
item.GetLayoutObject()->IsLayoutNGListItem());
DCHECK(item_result.shape_result);
+ text_builder.SetIsFirstForNode(IsFirstForNode(item, BreakToken()));
+
if (UNLIKELY(quirks_mode_))
box->EnsureTextMetrics(*item.Style(), baseline_type_);
@@ -236,7 +249,7 @@ void NGInlineLayoutAlgorithm::CreateLine(
baseline_type_);
}
- if (item.IsSymbolMarker()) {
+ if (UNLIKELY(item.IsSymbolMarker())) {
text_builder.SetItem(NGPhysicalTextFragment::kSymbolMarker,
line_info->ItemsData(), &item_result,
box->text_height);
@@ -245,14 +258,23 @@ void NGInlineLayoutAlgorithm::CreateLine(
line_info->ItemsData(), &item_result,
box->text_height);
}
- line_box_.AddChild(text_builder.ToTextFragment(), box->text_top,
- item_result.inline_size, item.BidiLevel());
+ if (UNLIKELY(item_result.hyphen_shape_result)) {
+ LayoutUnit hyphen_inline_size = item_result.HyphenInlineSize();
+ line_box_.AddChild(text_builder.ToTextFragment(), box->text_top,
+ item_result.inline_size - hyphen_inline_size,
+ item.BidiLevel());
+ PlaceHyphen(item_result, hyphen_inline_size, box);
+ } else {
+ line_box_.AddChild(text_builder.ToTextFragment(), box->text_top,
+ item_result.inline_size, item.BidiLevel());
+ }
// Text boxes always need full paint invalidations.
item.GetLayoutObject()->ClearNeedsLayoutWithFullPaintInvalidation();
+
} else if (item.Type() == NGInlineItem::kControl) {
PlaceControlItem(item, *line_info, &item_result, box);
} else if (item.Type() == NGInlineItem::kOpenTag) {
- box = HandleOpenTag(item, item_result, box_states_);
+ box = HandleOpenTag(item, item_result, &line_box_, box_states_);
} else if (item.Type() == NGInlineItem::kCloseTag) {
box = HandleCloseTag(item, item_result, box);
} else if (item.Type() == NGInlineItem::kAtomicInline) {
@@ -284,13 +306,6 @@ void NGInlineLayoutAlgorithm::CreateLine(
}
}
- if (line_info->LineEndFragment()) {
- // Add a generated text fragment, hyphen or ellipsis, at the logical end.
- // By using the paragraph bidi_level, it will appear at the visual end.
- PlaceGeneratedContent(std::move(line_info->LineEndFragment()),
- IsLtr(line_info->BaseDirection()) ? 0 : 1, box);
- }
-
box_states_->OnEndPlaceItems(&line_box_, baseline_type_);
if (UNLIKELY(Node().IsBidiEnabled())) {
@@ -308,11 +323,21 @@ void NGInlineLayoutAlgorithm::CreateLine(
}
}
- // Truncate the line if 'text-overflow: ellipsis' is set.
- if (UNLIKELY(inline_size > line_info->AvailableWidth() &&
- node_.GetLayoutBlockFlow()->ShouldTruncateOverflowingText())) {
- inline_size = NGLineTruncator(*line_info)
- .TruncateLine(inline_size, &line_box_, box_states_);
+ // Truncate the line if 'text-overflow: ellipsis' is set, or for line-clamp.
+ if (UNLIKELY((inline_size >
+ line_info->AvailableWidth() - line_info->TextIndent() &&
+ node_.GetLayoutBlockFlow()->ShouldTruncateOverflowingText()) ||
+ ShouldTruncateForLineClamp(*line_info))) {
+ NGLineTruncator truncator(*line_info);
+ auto* input =
+ DynamicTo<HTMLInputElement>(node_.GetLayoutBlockFlow()->GetNode());
+ if (input && input->ShouldApplyMiddleEllipsis()) {
+ inline_size = truncator.TruncateLineInTheMiddle(inline_size, &line_box_,
+ box_states_);
+ } else {
+ inline_size =
+ truncator.TruncateLine(inline_size, &line_box_, box_states_);
+ }
}
// Negative margins can make the position negative, but the inline size is
@@ -421,36 +446,28 @@ void NGInlineLayoutAlgorithm::PlaceControlItem(const NGInlineItem& item,
NGTextFragmentBuilder text_builder(ConstraintSpace().GetWritingMode());
text_builder.SetItem(type, line_info.ItemsData(), item_result,
box->text_height);
+ text_builder.SetIsFirstForNode(IsFirstForNode(item, BreakToken()));
line_box_.AddChild(text_builder.ToTextFragment(), box->text_top,
item_result->inline_size, item.BidiLevel());
}
-// Place a generated content that does not exist in DOM nor in LayoutObject
-// tree.
-void NGInlineLayoutAlgorithm::PlaceGeneratedContent(
- scoped_refptr<const NGPhysicalTextFragment> fragment,
- UBiDiLevel bidi_level,
- NGInlineBoxState* box) {
- LayoutUnit inline_size = IsHorizontalWritingMode() ? fragment->Size().width
- : fragment->Size().height;
- const ComputedStyle& style = fragment->Style();
- if (box->CanAddTextOfStyle(style)) {
- if (UNLIKELY(quirks_mode_))
- box->EnsureTextMetrics(style, baseline_type_);
- DCHECK(!box->text_metrics.IsEmpty());
- line_box_.AddChild(std::move(fragment), box->text_top, inline_size,
- bidi_level);
- } else {
- scoped_refptr<ComputedStyle> text_style =
- ComputedStyle::CreateAnonymousStyleWithDisplay(style,
- EDisplay::kInline);
- NGInlineBoxState* box = box_states_->OnOpenTag(*text_style, line_box_);
- box->ComputeTextMetrics(*text_style, baseline_type_);
- DCHECK(!box->text_metrics.IsEmpty());
- line_box_.AddChild(std::move(fragment), box->text_top, inline_size,
- bidi_level);
- box_states_->OnCloseTag(&line_box_, box, baseline_type_);
- }
+void NGInlineLayoutAlgorithm::PlaceHyphen(const NGInlineItemResult& item_result,
+ LayoutUnit hyphen_inline_size,
+ NGInlineBoxState* box) {
+ DCHECK(item_result.item);
+ DCHECK(item_result.hyphen_string);
+ DCHECK(item_result.hyphen_shape_result);
+ DCHECK_EQ(hyphen_inline_size, item_result.HyphenInlineSize());
+ const NGInlineItem& item = *item_result.item;
+ const WritingMode writing_mode = ConstraintSpace().GetWritingMode();
+ NGTextFragmentBuilder builder(writing_mode);
+ builder.SetText(
+ item.GetLayoutObject(), item_result.hyphen_string, item.Style(),
+ /* is_ellipsis_style */ false,
+ ShapeResultView::Create(item_result.hyphen_shape_result.get()));
+ DCHECK(!box->text_metrics.IsEmpty());
+ line_box_.AddChild(builder.ToTextFragment(), box->text_top,
+ hyphen_inline_size, item.BidiLevel());
}
NGInlineBoxState* NGInlineLayoutAlgorithm::PlaceAtomicInline(
@@ -465,7 +482,8 @@ NGInlineBoxState* NGInlineLayoutAlgorithm::PlaceAtomicInline(
// position += item_result->margins.LineLeft(style.Direction());
item_result->has_edge = true;
- NGInlineBoxState* box = box_states_->OnOpenTag(item, *item_result, line_box_);
+ NGInlineBoxState* box =
+ box_states_->OnOpenTag(item, *item_result, baseline_type_, line_box_);
PlaceLayoutResult(item_result, box, box->margin_inline_start);
return box_states_->OnCloseTag(&line_box_, box, baseline_type_);
}
@@ -478,20 +496,20 @@ void NGInlineLayoutAlgorithm::PlaceLayoutResult(NGInlineItemResult* item_result,
DCHECK(item_result->item);
const NGInlineItem& item = *item_result->item;
DCHECK(item.Style());
- NGBoxFragment fragment(ConstraintSpace().GetWritingMode(),
- ConstraintSpace().Direction(),
- To<NGPhysicalBoxFragment>(
- item_result->layout_result->PhysicalFragment()));
- NGLineHeightMetrics metrics = fragment.BaselineMetrics(
- {NGBaselineAlgorithmType::kAtomicInline, baseline_type_},
- ConstraintSpace());
+ NGLineHeightMetrics metrics =
+ NGBoxFragment(ConstraintSpace().GetWritingMode(),
+ ConstraintSpace().Direction(),
+ To<NGPhysicalBoxFragment>(
+ item_result->layout_result->PhysicalFragment()))
+ .BaselineMetrics(item_result->margins, baseline_type_);
if (box)
box->metrics.Unite(metrics);
LayoutUnit line_top = item_result->margins.line_over - metrics.ascent;
line_box_.AddChild(std::move(item_result->layout_result),
LogicalOffset{inline_offset, line_top},
- item_result->inline_size, item.BidiLevel());
+ item_result->inline_size, /* children_count */ 0,
+ item.BidiLevel());
}
// Place all out-of-flow objects in |line_box_|.
@@ -548,7 +566,7 @@ void NGInlineLayoutAlgorithm::PlaceOutOfFlowObjects(
if (box->StyleRef().IsOriginalDisplayInlineType()) {
// An inline-level OOF element positions itself within the line, at the
// position it would have been if it was in-flow.
- static_offset.inline_offset = child.offset.inline_offset;
+ static_offset.inline_offset = child.rect.offset.inline_offset;
// The static-position of inline-level OOF-positioned nodes depends on
// previous floats (if any).
@@ -572,7 +590,7 @@ void NGInlineLayoutAlgorithm::PlaceOutOfFlowObjects(
}
}
- child.offset = static_offset;
+ child.rect.offset = static_offset;
}
if (UNLIKELY(has_rtl_block_level_out_of_flow_objects)) {
@@ -585,7 +603,7 @@ void NGInlineLayoutAlgorithm::PlaceOutOfFlowObjects(
}
if (has_preceding_inline_level_content &&
!box->StyleRef().IsOriginalDisplayInlineType()) {
- child.offset.block_offset += line_height;
+ child.rect.offset.block_offset += line_height;
}
}
}
@@ -646,8 +664,8 @@ void NGInlineLayoutAlgorithm::PlaceFloatingObjects(
block_offset = -fragment.BlockSize() - block_offset;
}
- child.offset = {child.bfc_offset.line_offset - bfc_line_offset,
- block_offset};
+ child.rect.offset = {child.bfc_offset.line_offset - bfc_line_offset,
+ block_offset};
}
}
@@ -660,8 +678,8 @@ void NGInlineLayoutAlgorithm::PlaceListMarker(const NGInlineItem& item,
baseline_type_);
}
- container_builder_.SetUnpositionedListMarker(
- NGUnpositionedListMarker(ToLayoutNGListMarker(item.GetLayoutObject())));
+ container_builder_.SetUnpositionedListMarker(NGUnpositionedListMarker(
+ ToLayoutNGOutsideListMarker(item.GetLayoutObject())));
}
// Justify the line. This changes the size of items by adding spacing.
@@ -694,8 +712,8 @@ bool NGInlineLayoutAlgorithm::ApplyJustify(LayoutUnit space,
// matches to the |ShapeResult|.
DCHECK(!line_info->Results().IsEmpty());
const NGInlineItemResult& last_item_result = line_info->Results().back();
- if (last_item_result.text_end_effect == NGTextEndEffect::kHyphen)
- line_text_builder.Append(last_item_result.item->Style()->HyphenString());
+ if (last_item_result.hyphen_string)
+ line_text_builder.Append(last_item_result.hyphen_string);
// Compute the spacing to justify.
String line_text = line_text_builder.ToString();
@@ -714,14 +732,14 @@ bool NGInlineLayoutAlgorithm::ApplyJustify(LayoutUnit space,
scoped_refptr<ShapeResult> shape_result =
item_result.shape_result->CreateShapeResult();
DCHECK_GE(item_result.start_offset, line_info->StartOffset());
- // |shape_result| has more characters if it's hyphenated.
- DCHECK(item_result.text_end_effect != NGTextEndEffect::kNone ||
- shape_result->NumCharacters() ==
- item_result.end_offset - item_result.start_offset);
+ DCHECK_EQ(shape_result->NumCharacters(),
+ item_result.end_offset - item_result.start_offset);
shape_result->ApplySpacing(spacing, item_result.start_offset -
line_info->StartOffset() -
shape_result->StartIndex());
item_result.inline_size = shape_result->SnappedWidth();
+ if (UNLIKELY(item_result.hyphen_shape_result))
+ item_result.inline_size += item_result.HyphenInlineSize();
item_result.shape_result = ShapeResultView::Create(shape_result.get());
} else if (item_result.item->Type() == NGInlineItem::kAtomicInline) {
float offset = 0.f;
@@ -823,7 +841,7 @@ scoped_refptr<const NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
// In order to get the correct list of layout opportunities, we need to
// position any "leading" floats within the exclusion space first.
- NGPositionedFloatVector leading_floats;
+ STACK_UNINITIALIZED NGPositionedFloatVector leading_floats;
unsigned handled_leading_floats_index =
PositionLeadingFloats(&initial_exclusion_space, &leading_floats);
@@ -832,7 +850,7 @@ scoped_refptr<const NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
// We query all the layout opportunities on the initial exclusion space up
// front, as if the line breaker may add floats and change the opportunities.
- const LayoutOpportunityVector opportunities =
+ const LayoutOpportunityVector& opportunities =
initial_exclusion_space.AllLayoutOpportunities(
{ConstraintSpace().BfcOffset().line_offset,
is_empty_inline ? ConstraintSpace().ExpectedBfcBlockOffset()
@@ -876,7 +894,7 @@ scoped_refptr<const NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
opportunity.ComputeLineLayoutOpportunity(ConstraintSpace(),
line_block_size, block_delta);
- NGLineInfo line_info;
+ STACK_UNINITIALIZED NGLineInfo line_info;
NGLineBreaker line_breaker(Node(), NGLineBreakerMode::kContent,
ConstraintSpace(), line_opportunity,
leading_floats, handled_leading_floats_index,
@@ -1092,22 +1110,9 @@ void NGInlineLayoutAlgorithm::BidiReorder(TextDirection base_direction) {
// For opaque items, copy bidi levels from adjacent items.
if (has_opaque_items) {
- UBiDiLevel last_level = levels.front();
- if (last_level == kOpaqueBidiLevel) {
- for (const UBiDiLevel level : levels) {
- if (level != kOpaqueBidiLevel) {
- last_level = level;
- break;
- }
- }
- }
- // If all items are opaque, use the base direction.
- if (last_level == kOpaqueBidiLevel) {
- if (IsLtr(base_direction))
- return;
- last_level = 1;
- }
- for (UBiDiLevel& level : levels) {
+ // Use the paragraph level for trailing opaque items.
+ UBiDiLevel last_level = IsLtr(base_direction) ? 0 : 1;
+ for (UBiDiLevel& level : base::Reversed(levels)) {
if (level == kOpaqueBidiLevel)
level = last_level;
else
@@ -1130,4 +1135,22 @@ void NGInlineLayoutAlgorithm::BidiReorder(TextDirection base_direction) {
line_box_ = std::move(visual_items);
}
+// static
+NGInlineLayoutAlgorithm::TruncateType
+NGInlineLayoutAlgorithm::TruncateTypeFromConstraintSpace(
+ const NGConstraintSpace& space) {
+ if (space.LinesUntilClamp() != 1)
+ return TruncateType::kDefault;
+ return space.ForceTruncateAtLineClamp() ? TruncateType::kAlways
+ : TruncateType::kIfNotLastLine;
+}
+
+bool NGInlineLayoutAlgorithm::ShouldTruncateForLineClamp(
+ const NGLineInfo& line_info) const {
+ const TruncateType truncate_type = static_cast<TruncateType>(truncate_type_);
+ return truncate_type == TruncateType::kAlways ||
+ (truncate_type == TruncateType::kIfNotLastLine &&
+ !line_info.IsLastLine());
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
index 6fe33fe9220..604eefb4041 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h
@@ -52,6 +52,19 @@ class CORE_EXPORT NGInlineLayoutAlgorithm final
scoped_refptr<const NGLayoutResult> Layout() override;
private:
+ enum class TruncateType {
+ // Indicates default behavior. The default truncates if the text doesn't
+ // fit and ShouldTruncateOverflowingText() returns true.
+ kDefault,
+
+ // Truncate if NGLineInfo has more lines.
+ kIfNotLastLine,
+
+ // Forces truncation. This is used when line-clamp is set and there are
+ // blocks after this.
+ kAlways,
+ };
+
unsigned PositionLeadingFloats(NGExclusionSpace*, NGPositionedFloatVector*);
NGPositionedFloat PositionFloat(LayoutUnit origin_block_bfc_offset,
LayoutObject* floating_object,
@@ -69,6 +82,7 @@ class CORE_EXPORT NGInlineLayoutAlgorithm final
NGInlineBoxState* HandleOpenTag(const NGInlineItem&,
const NGInlineItemResult&,
+ NGLineBoxFragmentBuilder::ChildList*,
NGInlineLayoutStateStack*) const;
NGInlineBoxState* HandleCloseTag(const NGInlineItem&,
const NGInlineItemResult&,
@@ -80,9 +94,9 @@ class CORE_EXPORT NGInlineLayoutAlgorithm final
const NGLineInfo&,
NGInlineItemResult*,
NGInlineBoxState*);
- void PlaceGeneratedContent(scoped_refptr<const NGPhysicalTextFragment>,
- UBiDiLevel,
- NGInlineBoxState*);
+ void PlaceHyphen(const NGInlineItemResult&,
+ LayoutUnit hyphen_inline_size,
+ NGInlineBoxState*);
NGInlineBoxState* PlaceAtomicInline(const NGInlineItem&,
const NGLineInfo&,
NGInlineItemResult*);
@@ -105,6 +119,13 @@ class CORE_EXPORT NGInlineLayoutAlgorithm final
const NGExclusionSpace&,
LayoutUnit line_height);
+ static TruncateType TruncateTypeFromConstraintSpace(
+ const NGConstraintSpace& space);
+
+ // Returns true if truncuation should happen as a result of line-clamp for
+ // |line_info|.
+ bool ShouldTruncateForLineClamp(const NGLineInfo& line_info) const;
+
NGLineBoxFragmentBuilder::ChildList line_box_;
NGInlineLayoutStateStack* box_states_;
NGInlineChildLayoutContext* context_;
@@ -113,6 +134,7 @@ class CORE_EXPORT NGInlineLayoutAlgorithm final
unsigned is_horizontal_writing_mode_ : 1;
unsigned quirks_mode_ : 1;
+ unsigned truncate_type_ : 2;
#if DCHECK_IS_ON()
// True if |box_states_| is taken from |context_|, to check the |box_states_|
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
index 3c1aa36a1bc..fbb4e323541 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc
@@ -9,9 +9,11 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
@@ -50,6 +52,14 @@ TEST_F(NGInlineLayoutAlgorithmTest, BreakToken) {
NGConstraintSpace constraint_space = builder.ToConstraintSpace();
NGInlineChildLayoutContext context;
+ NGBoxFragmentBuilder container_builder(block_flow, block_flow->Style(),
+ block_flow->Style()->GetWritingMode(),
+ block_flow->Style()->Direction());
+ NGFragmentItemsBuilder items_builder(&container_builder);
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ container_builder.SetItemsBuilder(&items_builder);
+ context.SetItemsBuilder(&items_builder);
+ }
scoped_refptr<const NGLayoutResult> layout_result =
inline_node.Layout(constraint_space, nullptr, &context);
const auto& line1 = layout_result->PhysicalFragment();
@@ -68,95 +78,6 @@ TEST_F(NGInlineLayoutAlgorithmTest, BreakToken) {
EXPECT_TRUE(line3.BreakToken()->IsFinished());
}
-TEST_F(NGInlineLayoutAlgorithmTest, GenerateHyphen) {
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- #container {
- font: 10px/1 Ahem;
- width: 5ch;
- }
- </style>
- <div id=container>abc&shy;def</div>
- )HTML");
- scoped_refptr<const NGPhysicalBoxFragment> block =
- GetBoxFragmentByElementId("container");
- EXPECT_EQ(2u, block->Children().size());
- const NGPhysicalLineBoxFragment& line1 =
- To<NGPhysicalLineBoxFragment>(*block->Children()[0].get());
-
- // The hyphen is in its own NGPhysicalTextFragment.
- EXPECT_EQ(2u, line1.Children().size());
- EXPECT_EQ(NGPhysicalFragment::kFragmentText, line1.Children()[1]->Type());
- const auto& hyphen = To<NGPhysicalTextFragment>(*line1.Children()[1].get());
- EXPECT_EQ(String(u"\u2010"), hyphen.Text().ToString());
- // It should have the same LayoutObject as the hyphened word.
- EXPECT_EQ(line1.Children()[0]->GetLayoutObject(), hyphen.GetLayoutObject());
-}
-
-TEST_F(NGInlineLayoutAlgorithmTest, GenerateEllipsis) {
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- #container {
- font: 10px/1 Ahem;
- width: 5ch;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- </style>
- <div id=container>123456</div>
- )HTML");
- scoped_refptr<const NGPhysicalBoxFragment> block =
- GetBoxFragmentByElementId("container");
- EXPECT_EQ(1u, block->Children().size());
- const auto& line1 =
- To<NGPhysicalLineBoxFragment>(*block->Children()[0].get());
-
- // The ellipsis is in its own NGPhysicalTextFragment.
- EXPECT_EQ(3u, line1.Children().size());
- const auto& ellipsis = To<NGPhysicalTextFragment>(*line1.Children().back());
- EXPECT_EQ(String(u"\u2026"), ellipsis.Text().ToString());
- // It should have the same LayoutObject as the clipped word.
- EXPECT_EQ(line1.Children()[0]->GetLayoutObject(), ellipsis.GetLayoutObject());
-}
-
-TEST_F(NGInlineLayoutAlgorithmTest, EllipsisInlineBoxOnly) {
- LoadAhem();
- SetBodyInnerHTML(R"HTML(
- <!DOCTYPE html>
- <style>
- html, body { margin: 0; }
- #container {
- font: 10px/1 Ahem;
- width: 5ch;
- overflow: hidden;
- text-overflow: ellipsis;
- }
- span {
- border: solid 10ch blue;
- }
- </style>
- <div id=container><span></span></div>
- )HTML");
- scoped_refptr<const NGPhysicalBoxFragment> block =
- GetBoxFragmentByElementId("container");
- EXPECT_EQ(1u, block->Children().size());
- const auto& line1 =
- To<NGPhysicalLineBoxFragment>(*block->Children()[0].get());
-
- // There should not be ellipsis in this line.
- for (const auto& child : line1.Children()) {
- if (const auto* text = DynamicTo<NGPhysicalTextFragment>(child.get())) {
- EXPECT_FALSE(text->IsEllipsis());
- }
- }
-}
-
// This test ensures box fragments are generated when necessary, even when the
// line is empty. One such case is when the line contains a containing box of an
// out-of-flow object.
@@ -179,7 +100,7 @@ TEST_F(NGInlineLayoutAlgorithmTest,
}
</style>
<div id=container>
- <oof-container>
+ <oof-container id=target>
<oof></oof>
</oof-container>
</div>
@@ -190,15 +111,17 @@ TEST_F(NGInlineLayoutAlgorithmTest,
ASSERT_TRUE(container);
EXPECT_EQ(LayoutUnit(), container->Size().height);
- EXPECT_EQ(2u, container->Children().size());
- const auto& linebox =
- To<NGPhysicalLineBoxFragment>(*container->Children()[0]);
-
- EXPECT_EQ(1u, linebox.Children().size());
- EXPECT_EQ(PhysicalSize(), linebox.Size());
-
- const auto& oof_container = To<NGPhysicalBoxFragment>(*linebox.Children()[0]);
- EXPECT_EQ(PhysicalSize(), oof_container.Size());
+ NGInlineCursor line_box(*block_flow);
+ ASSERT_TRUE(line_box);
+ ASSERT_TRUE(line_box.Current().IsLineBox());
+ EXPECT_EQ(PhysicalSize(), line_box.Current().Size());
+
+ NGInlineCursor off_container(line_box);
+ off_container.MoveToNext();
+ ASSERT_TRUE(off_container);
+ ASSERT_EQ(GetLayoutObjectByElementId("target"),
+ off_container.Current().GetLayoutObject());
+ EXPECT_EQ(PhysicalSize(), off_container.Current().Size());
}
// This test ensures that if an inline box generates (or does not generate) box
@@ -219,21 +142,31 @@ TEST_F(NGInlineLayoutAlgorithmTest, BoxForEndMargin) {
}
</style>
<!-- This line wraps, and only 2nd line has a border. -->
- <div id=container>12 <span>3 45</span> 6</div>
+ <div id=container>12 <span id=span>3 45</span> 6</div>
)HTML");
auto* block_flow =
To<LayoutBlockFlow>(GetLayoutObjectByElementId("container"));
- const NGPhysicalBoxFragment* block_box = block_flow->CurrentFragment();
- ASSERT_TRUE(block_box);
- EXPECT_EQ(2u, block_box->Children().size());
- const auto& line_box1 =
- To<NGPhysicalLineBoxFragment>(*block_box->Children()[0].get());
- EXPECT_EQ(2u, line_box1.Children().size());
+ NGInlineCursor line_box(*block_flow);
+ ASSERT_TRUE(line_box) << "line_box is at start of first line.";
+ ASSERT_TRUE(line_box.Current().IsLineBox());
+ line_box.MoveToNextLine();
+ ASSERT_TRUE(line_box) << "line_box is at start of second line.";
+ NGInlineCursor cursor(line_box);
+ ASSERT_TRUE(line_box.Current().IsLineBox());
+ cursor.MoveToNext();
+ ASSERT_TRUE(cursor);
+ EXPECT_EQ(GetLayoutObjectByElementId("span"),
+ cursor.Current().GetLayoutObject());
// The <span> generates a box fragment for the 2nd line because it has a
// right border. It should also generate a box fragment for the 1st line even
// though there's no borders on the 1st line.
- EXPECT_EQ(NGPhysicalFragment::kFragmentBox, line_box1.Children()[1]->Type());
+ const NGPhysicalBoxFragment* box_fragment = cursor.Current().BoxFragment();
+ ASSERT_TRUE(box_fragment);
+ EXPECT_EQ(NGPhysicalFragment::kFragmentBox, box_fragment->Type());
+
+ line_box.MoveToNextLine();
+ ASSERT_FALSE(line_box) << "block_flow has two lines.";
}
// A block with inline children generates fragment tree as follows:
@@ -257,8 +190,8 @@ TEST_F(NGInlineLayoutAlgorithmTest, ContainerBorderPadding) {
auto* block_flow =
To<LayoutBlockFlow>(GetLayoutObjectByElementId("container"));
NGBlockNode block_node(block_flow);
- NGConstraintSpace space = NGConstraintSpace::CreateFromLayoutObject(
- *block_flow, false /* is_layout_root */);
+ NGConstraintSpace space =
+ NGConstraintSpace::CreateFromLayoutObject(*block_flow);
scoped_refptr<const NGLayoutResult> layout_result = block_node.Layout(space);
EXPECT_TRUE(layout_result->BfcBlockOffset().has_value());
@@ -289,17 +222,13 @@ TEST_F(NGInlineLayoutAlgorithmTest, MAYBE_VerticalAlignBottomReplaced) {
)HTML");
auto* block_flow =
To<LayoutBlockFlow>(GetLayoutObjectByElementId("container"));
- NGInlineNode inline_node(block_flow);
- NGInlineChildLayoutContext context;
- NGConstraintSpace space = NGConstraintSpace::CreateFromLayoutObject(
- *block_flow, false /* is_layout_root */);
- scoped_refptr<const NGLayoutResult> layout_result =
- inline_node.Layout(space, nullptr, &context);
-
- const auto& line = layout_result->PhysicalFragment();
- EXPECT_EQ(LayoutUnit(96), line.Size().height);
- PhysicalOffset img_offset = line.Children()[0].Offset();
- EXPECT_EQ(LayoutUnit(0), img_offset.top);
+ NGInlineCursor cursor(*block_flow);
+ ASSERT_TRUE(cursor);
+ EXPECT_EQ(LayoutUnit(96), cursor.Current().Size().height);
+ cursor.MoveToNext();
+ ASSERT_TRUE(cursor);
+ EXPECT_EQ(LayoutUnit(0), cursor.Current().OffsetInContainerBlock().top)
+ << "Offset top of <img> should be zero.";
}
// Verifies that text can flow correctly around floats that were positioned
@@ -393,7 +322,7 @@ TEST_F(NGInlineLayoutAlgorithmTest, TextFloatsAroundInlineFloatThatFitsOnLine) {
ASSERT_TRUE(block_box);
// Two lines.
- EXPECT_EQ(2u, block_box->Children().size());
+ ASSERT_EQ(2u, block_box->Children().size());
PhysicalOffset first_line_offset = block_box->Children()[1].Offset();
// 30 == narrow-float's width.
@@ -521,20 +450,24 @@ TEST_F(NGInlineLayoutAlgorithmTest, InkOverflow) {
auto* block_flow =
To<LayoutBlockFlow>(GetLayoutObjectByElementId("container"));
const NGPaintFragment* paint_fragment = block_flow->PaintFragment();
- ASSERT_TRUE(paint_fragment);
- const NGPhysicalFragment& box_fragment = paint_fragment->PhysicalFragment();
-
+ const NGPhysicalBoxFragment& box_fragment = *block_flow->CurrentFragment();
+ if (paint_fragment)
+ ASSERT_EQ(&paint_fragment->PhysicalFragment(), &box_fragment);
EXPECT_EQ(LayoutUnit(10), box_fragment.Size().height);
- PhysicalRect ink_overflow = paint_fragment->InkOverflow();
+ NGInlineCursor cursor(*block_flow);
+ PhysicalRect ink_overflow = cursor.Current().InkOverflow();
EXPECT_EQ(LayoutUnit(-5), ink_overflow.offset.top);
EXPECT_EQ(LayoutUnit(20), ink_overflow.size.height);
- // |ContentsInkOverflow| should match to |InkOverflow|, except the width
- // because |<div id=container>| might be wider than the content.
- EXPECT_EQ(ink_overflow.offset, paint_fragment->ContentsInkOverflow().offset);
- EXPECT_EQ(ink_overflow.size.height,
- paint_fragment->ContentsInkOverflow().size.height);
+ if (paint_fragment) {
+ // |ContentsInkOverflow| should match to |InkOverflow|, except the width
+ // because |<div id=container>| might be wider than the content.
+ const PhysicalRect contents_ink_overflow =
+ paint_fragment->ContentsInkOverflow();
+ EXPECT_EQ(ink_overflow.offset, contents_ink_overflow.offset);
+ EXPECT_EQ(ink_overflow.size.height, contents_ink_overflow.size.height);
+ }
}
#undef MAYBE_VerticalAlignBottomReplaced
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
index 6f83ab768f0..740ab5a243f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc
@@ -24,7 +24,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
@@ -285,7 +284,7 @@ void CollectInlinesInternal(LayoutBlockFlow* block,
builder->ClearInlineFragment(node);
} else if (node->IsAtomicInlineLevel()) {
- if (node->IsListMarkerIncludingNG()) {
+ if (node->IsListMarkerIncludingNGOutside()) {
// LayoutNGListItem produces the 'outside' list marker as an inline
// block. This is an out-of-flow item whose position is computed
// automatically.
@@ -427,13 +426,6 @@ void TruncateOrPadText(String* text, unsigned length) {
}
}
-template <typename OffsetMappingBuilder>
-bool MayBeBidiEnabled(
- const String& text_content,
- const NGInlineItemsBuilderTemplate<OffsetMappingBuilder>& builder) {
- return !text_content.Is8Bit() || builder.HasBidiControls();
-}
-
} // namespace
NGInlineNode::NGInlineNode(LayoutBlockFlow* block)
@@ -528,6 +520,11 @@ class NGInlineNodeDataEditor final {
if (layout_text_.StyleRef().TextSecurity() != ETextSecurity::kNone)
return nullptr;
+ // It is hard to figure differences of bidi control codes before/after
+ // editing. See http://crbug.com/1039143
+ if (layout_text_.HasBidiControlInlineItems())
+ return nullptr;
+
// Note: We should compute offset mapping before calling
// |LayoutBlockFlow::TakeNGInlineNodeData()|
const NGOffsetMapping* const offset_mapping =
@@ -756,6 +753,10 @@ bool NGInlineNode::SetTextWithOffset(LayoutText* layout_text,
if (!previous_data)
return false;
+ // This function runs outside of the layout phase. Prevent purging font cache
+ // while shaping.
+ FontCachePurgePreventer fontCachePurgePreventer;
+
String new_text(std::move(new_text_in));
layout_text->StyleRef().ApplyTextTransform(&new_text,
layout_text->PreviousCharacter());
@@ -769,7 +770,7 @@ bool NGInlineNode::SetTextWithOffset(LayoutText* layout_text,
// inline items.
layout_text->ClearInlineItems();
CollectInlinesInternal(node.GetLayoutBlockFlow(), &builder, previous_data);
- data->text_content = builder.ToString();
+ builder.DidFinishCollectInlines(data);
// Relocates |ShapeResult| in |previous_data| after |offset|+|length|
editor.Run();
node.SegmentText(data);
@@ -877,17 +878,7 @@ void NGInlineNode::CollectInlines(NGInlineNodeData* data,
data->items.ReserveCapacity(EstimateInlineItemsCount(*block));
NGInlineItemsBuilder builder(&data->items, dirty_lines);
CollectInlinesInternal(block, &builder, previous_data);
- data->text_content = builder.ToString();
-
- // Set |is_bidi_enabled_| for all UTF-16 strings for now, because at this
- // point the string may or may not contain RTL characters.
- // |SegmentText()| will analyze the text and reset |is_bidi_enabled_| if it
- // doesn't contain any RTL characters.
- data->is_bidi_enabled_ = MayBeBidiEnabled(data->text_content, builder);
- data->is_empty_inline_ = builder.IsEmptyInline();
- data->is_block_level_ = builder.IsBlockLevel();
- data->changes_may_affect_earlier_lines_ =
- builder.ChangesMayAffectEarlierLines();
+ builder.DidFinishCollectInlines(data);
}
void NGInlineNode::SegmentText(NGInlineNodeData* data) {
@@ -1476,7 +1467,7 @@ String NGInlineNode::TextContentForStickyImagesQuirk(
static LayoutUnit ComputeContentSize(
NGInlineNode node,
WritingMode container_writing_mode,
- const MinMaxSizeInput& input,
+ const MinMaxSizesInput& input,
NGLineBreakerMode mode,
NGLineBreaker::MaxSizeCache* max_size_cache,
base::Optional<LayoutUnit>* max_size_out) {
@@ -1510,7 +1501,7 @@ static LayoutUnit ComputeContentSize(
STACK_ALLOCATED();
public:
- explicit FloatsMaxSize(const MinMaxSizeInput& input)
+ explicit FloatsMaxSize(const MinMaxSizesInput& input)
: floats_inline_size_(input.float_left_inline_size +
input.float_right_inline_size) {
DCHECK_GE(floats_inline_size_, 0);
@@ -1519,7 +1510,7 @@ static LayoutUnit ComputeContentSize(
void AddFloat(const ComputedStyle& float_style,
const ComputedStyle& style,
LayoutUnit float_inline_max_size_with_margin) {
- floating_objects_.push_back(FloatingObject{
+ floating_objects_.push_back(NGInlineNode::FloatingObject{
float_style, style, float_inline_max_size_with_margin});
}
@@ -1561,12 +1552,7 @@ static LayoutUnit ComputeContentSize(
private:
LayoutUnit floats_inline_size_;
- struct FloatingObject {
- const ComputedStyle& float_style;
- const ComputedStyle& style;
- LayoutUnit float_inline_max_size_with_margin;
- };
- Vector<FloatingObject, 4> floating_objects_;
+ HeapVector<NGInlineNode::FloatingObject, 4> floating_objects_;
};
// This struct computes the max size from the line break results for the min
@@ -1711,8 +1697,8 @@ static LayoutUnit ComputeContentSize(
const ComputedStyle& float_style = float_node.Style();
// Floats don't intrude into floats.
- MinMaxSizeInput float_input(input.percentage_resolution_block_size);
- MinMaxSize child_sizes =
+ MinMaxSizesInput float_input(input.percentage_resolution_block_size);
+ MinMaxSizes child_sizes =
ComputeMinAndMaxContentContribution(style, float_node, float_input);
LayoutUnit child_inline_margins =
ComputeMinMaxMargins(style, float_node).InlineSum();
@@ -1751,9 +1737,9 @@ static LayoutUnit ComputeContentSize(
return result;
}
-MinMaxSize NGInlineNode::ComputeMinMaxSize(
+MinMaxSizes NGInlineNode::ComputeMinMaxSizes(
WritingMode container_writing_mode,
- const MinMaxSizeInput& input,
+ const MinMaxSizesInput& input,
const NGConstraintSpace* constraint_space) {
PrepareLayoutIfNeeded();
@@ -1761,7 +1747,7 @@ MinMaxSize NGInlineNode::ComputeMinMaxSize(
// size. This gives the min-content, the width where lines wrap at every
// break opportunity.
NGLineBreaker::MaxSizeCache max_size_cache;
- MinMaxSize sizes;
+ MinMaxSizes sizes;
base::Optional<LayoutUnit> max_size;
sizes.min_size = ComputeContentSize(*this, container_writing_mode, input,
NGLineBreakerMode::kMinContent,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
index ddb8325722d..72a5dd5fa81 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h
@@ -22,7 +22,6 @@ class NGInlineChildLayoutContext;
class NGInlineNodeLegacy;
class NGLayoutResult;
class NGOffsetMapping;
-struct MinMaxSize;
struct NGInlineItemsData;
// Represents an anonymous block box to be laid out, that contains consecutive
@@ -55,9 +54,9 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
// Computes the value of min-content and max-content for this anonymous block
// box. min-content is the inline size when lines wrap at every break
// opportunity, and max-content is when lines do not wrap at all.
- MinMaxSize ComputeMinMaxSize(WritingMode container_writing_mode,
- const MinMaxSizeInput&,
- const NGConstraintSpace* = nullptr);
+ MinMaxSizes ComputeMinMaxSizes(WritingMode container_writing_mode,
+ const MinMaxSizesInput&,
+ const NGConstraintSpace* = nullptr);
// Instruct to re-compute |PrepareLayout| on the next layout.
void InvalidatePrepareLayoutForTest() {
@@ -72,10 +71,19 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
return Data().ItemsData(is_first_line);
}
+ // There's a special intrinsic size measure quirk for images that are direct
+ // children of table cells that have auto inline-size: When measuring
+ // intrinsic min/max inline sizes, we pretend that it's not possible to break
+ // between images, or between text and images. Note that this only applies
+ // when measuring. During actual layout, on the other hand, standard breaking
+ // rules are to be followed.
+ // See https://quirks.spec.whatwg.org/#the-table-cell-width-calculation-quirk
+ bool IsStickyImagesQuirkForContentSize() const;
+
// Returns the text content to use for content sizing. This is normally the
// same as |items_data.text_content|, except when sticky images quirk is
// needed.
- String TextContentForContentSize(const NGInlineItemsData& items_data) const;
+ static String TextContentForStickyImagesQuirk(const NGInlineItemsData&);
// Clear associated fragments for LayoutObjects.
// They are associated when NGPaintFragment is constructed, but when clearing,
@@ -121,6 +129,16 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
String ToString() const;
+ struct FloatingObject {
+ DISALLOW_NEW();
+
+ void Trace(Visitor* visitor) {}
+
+ const ComputedStyle& float_style;
+ const ComputedStyle& style;
+ LayoutUnit float_inline_max_size_with_margin;
+ };
+
protected:
bool IsPrepareLayoutFinished() const;
@@ -160,8 +178,6 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
}
const NGInlineNodeData& EnsureData();
- static String TextContentForStickyImagesQuirk(const NGInlineItemsData&);
-
static void ComputeOffsetMapping(LayoutBlockFlow* layout_block_flow,
NGInlineNodeData* data);
@@ -169,28 +185,14 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
friend class NGInlineNodeLegacy;
};
-inline String NGInlineNode::TextContentForContentSize(
- const NGInlineItemsData& items_data) const {
- const String& text_content = items_data.text_content;
- if (UNLIKELY(text_content.IsEmpty()))
- return text_content;
-
- // There's a special intrinsic size measure quirk for images that are direct
- // children of table cells that have auto inline-size: When measuring
- // intrinsic min/max inline sizes, we pretend that it's not possible to break
- // between images, or between text and images. Note that this only applies
- // when measuring. During actual layout, on the other hand, standard breaking
- // rules are to be followed.
- // See https://quirks.spec.whatwg.org/#the-table-cell-width-calculation-quirk
+inline bool NGInlineNode::IsStickyImagesQuirkForContentSize() const {
if (UNLIKELY(GetDocument().InQuirksMode())) {
const ComputedStyle& style = Style();
if (UNLIKELY(style.Display() == EDisplay::kTableCell &&
- style.LogicalWidth().IsIntrinsicOrAuto())) {
- return TextContentForStickyImagesQuirk(items_data);
- }
+ style.LogicalWidth().IsIntrinsicOrAuto()))
+ return true;
}
-
- return text_content;
+ return false;
}
template <>
@@ -202,4 +204,7 @@ struct DowncastTraits<NGInlineNode> {
} // namespace blink
+WTF_ALLOW_MOVE_INIT_AND_COMPARE_WITH_MEM_FUNCTIONS(
+ blink::NGInlineNode::FloatingObject)
+
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_INLINE_NODE_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
index e77f4b569c9..5dda66cc9f2 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h
@@ -11,6 +11,9 @@
namespace blink {
+template <typename OffsetMappingBuilder>
+class NGInlineItemsBuilderTemplate;
+
// Data which is required for inline nodes.
struct CORE_EXPORT NGInlineNodeData : NGInlineItemsData {
public:
@@ -40,6 +43,9 @@ struct CORE_EXPORT NGInlineNodeData : NGInlineItemsData {
friend class NGInlineNodeForTest;
friend class NGOffsetMappingTest;
+ template <typename OffsetMappingBuilder>
+ friend class NGInlineItemsBuilderTemplate;
+
// Items to use for the first line, when the node has :first-line rules.
//
// Items have different ComputedStyle, and may also have different
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
index 819493a0e6e..8d6cc679213 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/dom/text.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
@@ -48,7 +49,8 @@ class NGInlineNodeForTest : public NGInlineNode {
unsigned start = data->text_content.length();
data->text_content = data->text_content + text;
data->items.push_back(NGInlineItem(NGInlineItem::kText, start,
- start + text.length(), layout_object));
+ start + text.length(), layout_object,
+ /* is_first_for_node */ true));
data->is_empty_inline_ = false;
}
@@ -56,8 +58,9 @@ class NGInlineNodeForTest : public NGInlineNode {
NGInlineNodeData* data = MutableData();
data->text_content = data->text_content + character;
unsigned end = data->text_content.length();
- data->items.push_back(
- NGInlineItem(NGInlineItem::kBidiControl, end - 1, end, nullptr));
+ data->items.push_back(NGInlineItem(NGInlineItem::kBidiControl, end - 1, end,
+ nullptr,
+ /* is_first_for_node */ true));
data->is_bidi_enabled_ = true;
data->is_empty_inline_ = false;
}
@@ -90,7 +93,6 @@ class NGInlineNodeTest : public NGLayoutTest {
void SetUp() override {
NGLayoutTest::SetUp();
style_ = ComputedStyle::Create();
- style_->GetFont().Update(nullptr);
}
void SetupHtml(const char* id, String html) {
@@ -115,31 +117,10 @@ class NGInlineNodeTest : public NGLayoutTest {
return node;
}
- MinMaxSize ComputeMinMaxSize(NGInlineNode node) {
- return node.ComputeMinMaxSize(
+ MinMaxSizes ComputeMinMaxSizes(NGInlineNode node) {
+ return node.ComputeMinMaxSizes(
node.Style().GetWritingMode(),
- MinMaxSizeInput(/* percentage_resolution_block_size */ LayoutUnit()));
- }
-
- void CreateLine(
- NGInlineNode node,
- Vector<scoped_refptr<const NGPhysicalTextFragment>>* fragments_out) {
- NGConstraintSpaceBuilder builder(WritingMode::kHorizontalTb,
- WritingMode::kHorizontalTb,
- /* is_new_fc */ false);
- builder.SetAvailableSize({LayoutUnit::Max(), LayoutUnit(-1)});
- NGConstraintSpace constraint_space = builder.ToConstraintSpace();
- NGInlineChildLayoutContext context;
- scoped_refptr<const NGLayoutResult> result =
- NGInlineLayoutAlgorithm(node, constraint_space,
- nullptr /* break_token */, &context)
- .Layout();
-
- const auto& line =
- To<NGPhysicalLineBoxFragment>(result->PhysicalFragment());
- for (const auto& child : line.Children()) {
- fragments_out->push_back(To<NGPhysicalTextFragment>(child.get()));
- }
+ MinMaxSizesInput(/* percentage_resolution_block_size */ LayoutUnit()));
}
const String& GetText() const {
@@ -177,8 +158,8 @@ class NGInlineNodeTest : public NGLayoutTest {
Vector<unsigned> ToEndOffsetList(
NGInlineItemSegments::const_iterator segments) {
Vector<unsigned> end_offsets;
- for (const NGInlineItemSegment& segment : segments)
- end_offsets.push_back(segment.EndOffset());
+ for (const RunSegmenter::RunSegmenterRange& segment : segments)
+ end_offsets.push_back(segment.end);
return end_offsets;
}
@@ -442,49 +423,27 @@ TEST_F(NGInlineNodeTest, SegmentBidiIsolate) {
TEST_ITEM_OFFSET_DIR(items[8], 22u, 28u, TextDirection::kLtr);
}
-#define TEST_TEXT_FRAGMENT(fragment, start_offset, end_offset) \
- EXPECT_EQ(start_offset, fragment->StartOffset()); \
- EXPECT_EQ(end_offset, fragment->EndOffset());
-
-TEST_F(NGInlineNodeTest, CreateLineBidiIsolate) {
- UseLayoutObjectAndAhem();
- scoped_refptr<ComputedStyle> style = ComputedStyle::Create();
- style->SetLineHeight(Length::Fixed(1));
- style->GetFont().Update(nullptr);
- NGInlineNodeForTest node = CreateInlineNode();
- node = CreateBidiIsolateNode(node, layout_object_);
- node.ShapeText();
- Vector<scoped_refptr<const NGPhysicalTextFragment>> fragments;
- CreateLine(node, &fragments);
- EXPECT_EQ(5u, fragments.size());
- TEST_TEXT_FRAGMENT(fragments[0], 0u, 6u);
- TEST_TEXT_FRAGMENT(fragments[1], 16u, 21u);
- TEST_TEXT_FRAGMENT(fragments[2], 14u, 15u);
- TEST_TEXT_FRAGMENT(fragments[3], 7u, 13u);
- TEST_TEXT_FRAGMENT(fragments[4], 22u, 28u);
-}
-
-TEST_F(NGInlineNodeTest, MinMaxSize) {
+TEST_F(NGInlineNodeTest, MinMaxSizes) {
LoadAhem();
SetupHtml("t", "<div id=t style='font:10px Ahem'>AB CDEF</div>");
NGInlineNodeForTest node = CreateInlineNode();
- MinMaxSize sizes = ComputeMinMaxSize(node);
+ MinMaxSizes sizes = ComputeMinMaxSizes(node);
EXPECT_EQ(40, sizes.min_size);
EXPECT_EQ(70, sizes.max_size);
}
-TEST_F(NGInlineNodeTest, MinMaxSizeElementBoundary) {
+TEST_F(NGInlineNodeTest, MinMaxSizesElementBoundary) {
LoadAhem();
SetupHtml("t", "<div id=t style='font:10px Ahem'>A B<span>C D</span></div>");
NGInlineNodeForTest node = CreateInlineNode();
- MinMaxSize sizes = ComputeMinMaxSize(node);
+ MinMaxSizes sizes = ComputeMinMaxSizes(node);
// |min_content| should be the width of "BC" because there is an element
// boundary between "B" and "C" but no break opportunities.
EXPECT_EQ(20, sizes.min_size);
EXPECT_EQ(60, sizes.max_size);
}
-TEST_F(NGInlineNodeTest, MinMaxSizeFloats) {
+TEST_F(NGInlineNodeTest, MinMaxSizesFloats) {
LoadAhem();
SetupHtml("t", R"HTML(
<style>
@@ -496,13 +455,13 @@ TEST_F(NGInlineNodeTest, MinMaxSizeFloats) {
)HTML");
NGInlineNodeForTest node = CreateInlineNode();
- MinMaxSize sizes = ComputeMinMaxSize(node);
+ MinMaxSizes sizes = ComputeMinMaxSizes(node);
EXPECT_EQ(50, sizes.min_size);
EXPECT_EQ(130, sizes.max_size);
}
-TEST_F(NGInlineNodeTest, MinMaxSizeCloseTagAfterForcedBreak) {
+TEST_F(NGInlineNodeTest, MinMaxSizesCloseTagAfterForcedBreak) {
LoadAhem();
SetupHtml("t", R"HTML(
<style>
@@ -514,14 +473,14 @@ TEST_F(NGInlineNodeTest, MinMaxSizeCloseTagAfterForcedBreak) {
)HTML");
NGInlineNodeForTest node = CreateInlineNode();
- MinMaxSize sizes = ComputeMinMaxSize(node);
+ MinMaxSizes sizes = ComputeMinMaxSizes(node);
// The right border of the `</span>` is included in the line even if it
// appears after `<br>`. crbug.com/991320.
EXPECT_EQ(80, sizes.min_size);
EXPECT_EQ(80, sizes.max_size);
}
-TEST_F(NGInlineNodeTest, MinMaxSizeFloatsClearance) {
+TEST_F(NGInlineNodeTest, MinMaxSizesFloatsClearance) {
LoadAhem();
SetupHtml("t", R"HTML(
<style>
@@ -534,13 +493,13 @@ TEST_F(NGInlineNodeTest, MinMaxSizeFloatsClearance) {
)HTML");
NGInlineNodeForTest node = CreateInlineNode();
- MinMaxSize sizes = ComputeMinMaxSize(node);
+ MinMaxSizes sizes = ComputeMinMaxSizes(node);
EXPECT_EQ(50, sizes.min_size);
EXPECT_EQ(160, sizes.max_size);
}
-TEST_F(NGInlineNodeTest, MinMaxSizeTabulationWithBreakWord) {
+TEST_F(NGInlineNodeTest, MinMaxSizesTabulationWithBreakWord) {
LoadAhem();
SetupHtml("t", R"HTML(
<style>
@@ -554,7 +513,7 @@ TEST_F(NGInlineNodeTest, MinMaxSizeTabulationWithBreakWord) {
)HTML");
NGInlineNodeForTest node = CreateInlineNode();
- MinMaxSize sizes = ComputeMinMaxSize(node);
+ MinMaxSizes sizes = ComputeMinMaxSizes(node);
EXPECT_EQ(160, sizes.min_size);
EXPECT_EQ(170, sizes.max_size);
}
@@ -882,7 +841,12 @@ TEST_F(NGInlineNodeTest, CollectInlinesShouldNotClearFirstInlineFragment) {
// Running |CollectInlines| should not clear |FirstInlineFragment|.
LayoutObject* first_child = container->firstChild()->GetLayoutObject();
- EXPECT_NE(first_child->FirstInlineFragment(), nullptr);
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ // TODO(yosin): We should use |FirstInlineItemFragmentIndex()| once we
+ // implement it.
+ } else {
+ EXPECT_NE(first_child->FirstInlineFragment(), nullptr);
+ }
}
TEST_F(NGInlineNodeTest, InvalidateAddSpan) {
@@ -1371,7 +1335,7 @@ TEST_F(NGInlineNodeTest, MarkLineBoxesDirtyInInlineBlock) {
// Inline block with auto-size calls |ComputeMinMaxSize|, which may call
// |CollectInlines|. Emulate it to ensure it does not let tests to fail.
GetDocument().UpdateStyleAndLayoutTree();
- ComputeMinMaxSize(NGInlineNode(layout_block_flow_));
+ ComputeMinMaxSizes(NGInlineNode(layout_block_flow_));
auto lines = MarkLineBoxesDirty();
// TODO(kojii): Ideally, 0 should be false, or even 1 as well.
@@ -1394,7 +1358,7 @@ TEST_F(NGInlineNodeTest, RemoveInlineNodeDataIfBlockBecomesEmpty2) {
SetupHtml("container", "<div id=container><b><i>foo</i></b></div>");
ASSERT_TRUE(layout_block_flow_->HasNGInlineNodeData());
- GetElementById("container")->SetInnerHTMLFromString("");
+ GetElementById("container")->setInnerHTML("");
UpdateAllLifecyclePhasesForTest();
EXPECT_FALSE(layout_block_flow_->HasNGInlineNodeData());
@@ -1425,9 +1389,9 @@ TEST_F(NGInlineNodeTest, ClearFirstInlineFragmentOnSplitFlow) {
// Keep the text fragment to compare later.
Element* inner_span = GetElementById("inner_span");
Node* text = inner_span->firstChild();
- scoped_refptr<NGPaintFragment> text_fragment_before_split =
- text->GetLayoutObject()->FirstInlineFragment();
- EXPECT_NE(text_fragment_before_split.get(), nullptr);
+ NGInlineCursor text_fragment_before_split;
+ text_fragment_before_split.MoveTo(*text->GetLayoutObject());
+ EXPECT_TRUE(text_fragment_before_split);
// Append <div> to <span>. causing SplitFlow().
Element* outer_span = GetElementById("outer_span");
@@ -1435,30 +1399,29 @@ TEST_F(NGInlineNodeTest, ClearFirstInlineFragmentOnSplitFlow) {
outer_span->appendChild(div);
// Update tree but do NOT update layout. At this point, there's no guarantee,
- // but there are some clients (e.g., Schroll Anchor) who try to read
+ // but there are some clients (e.g., Scroll Anchor) who try to read
// associated fragments.
//
// NGPaintFragment is owned by LayoutNGBlockFlow. Because the original owner
// no longer has an inline formatting context, the NGPaintFragment subtree is
// destroyed, and should not be accessible.
GetDocument().UpdateStyleAndLayoutTree();
- scoped_refptr<NGPaintFragment> text_fragment_before_layout =
- text->GetLayoutObject()->FirstInlineFragment();
- EXPECT_EQ(text_fragment_before_layout, nullptr);
+ EXPECT_FALSE(text->GetLayoutObject()->IsInLayoutNGInlineFormattingContext());
// Update layout. There should be a different instance of the text fragment.
UpdateAllLifecyclePhasesForTest();
- scoped_refptr<NGPaintFragment> text_fragment_after_layout =
- text->GetLayoutObject()->FirstInlineFragment();
- EXPECT_NE(text_fragment_before_split, text_fragment_after_layout);
+ NGInlineCursor text_fragment_after_layout;
+ text_fragment_after_layout.MoveTo(*text->GetLayoutObject());
+ EXPECT_NE(text_fragment_before_split.Current(),
+ text_fragment_after_layout.Current());
// Check it is the one owned by the new root inline formatting context.
LayoutBlock* anonymous_block =
inner_span->GetLayoutObject()->ContainingBlock();
EXPECT_TRUE(anonymous_block->IsAnonymous());
- const NGPaintFragment* block_fragment = anonymous_block->PaintFragment();
- const NGPaintFragment* line_box_fragment = block_fragment->FirstChild();
- EXPECT_EQ(line_box_fragment->FirstChild(), text_fragment_after_layout);
+ EXPECT_EQ(anonymous_block, text_fragment_after_layout.Current()
+ .GetLayoutObject()
+ ->ContainingBlock());
}
TEST_F(NGInlineNodeTest, AddChildToSVGRoot) {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
index af3b4b14df1..acddeab0eaf 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc
@@ -57,14 +57,27 @@ NGLineBoxFragmentBuilder::ChildList::LastInFlowChild() {
return nullptr;
}
+void NGLineBoxFragmentBuilder::ChildList::WillInsertChild(
+ unsigned insert_before) {
+ unsigned index = 0;
+ for (Child& child : children_) {
+ if (index >= insert_before)
+ break;
+ if (child.children_count && index + child.children_count > insert_before)
+ ++child.children_count;
+ ++index;
+ }
+}
+
void NGLineBoxFragmentBuilder::ChildList::InsertChild(unsigned index) {
+ WillInsertChild(index);
children_.insert(index, Child());
}
void NGLineBoxFragmentBuilder::ChildList::MoveInInlineDirection(
LayoutUnit delta) {
for (auto& child : children_)
- child.offset.inline_offset += delta;
+ child.rect.offset.inline_offset += delta;
}
void NGLineBoxFragmentBuilder::ChildList::MoveInInlineDirection(
@@ -72,20 +85,20 @@ void NGLineBoxFragmentBuilder::ChildList::MoveInInlineDirection(
unsigned start,
unsigned end) {
for (unsigned index = start; index < end; index++)
- children_[index].offset.inline_offset += delta;
+ children_[index].rect.offset.inline_offset += delta;
}
void NGLineBoxFragmentBuilder::ChildList::MoveInBlockDirection(
LayoutUnit delta) {
for (auto& child : children_)
- child.offset.block_offset += delta;
+ child.rect.offset.block_offset += delta;
}
void NGLineBoxFragmentBuilder::ChildList::MoveInBlockDirection(LayoutUnit delta,
unsigned start,
unsigned end) {
for (unsigned index = start; index < end; index++)
- children_[index].offset.block_offset += delta;
+ children_[index].rect.offset.block_offset += delta;
}
void NGLineBoxFragmentBuilder::AddChildren(ChildList& children) {
@@ -94,42 +107,39 @@ void NGLineBoxFragmentBuilder::AddChildren(ChildList& children) {
for (auto& child : children) {
if (child.layout_result) {
DCHECK(!child.fragment);
- AddChild(child.layout_result->PhysicalFragment(), child.offset);
+ AddChild(child.layout_result->PhysicalFragment(), child.Offset());
child.layout_result.reset();
} else if (child.fragment) {
- AddChild(std::move(child.fragment), child.offset);
+ AddChild(std::move(child.fragment), child.Offset());
DCHECK(!child.fragment);
} else if (child.out_of_flow_positioned_box) {
AddOutOfFlowInlineChildCandidate(
NGBlockNode(ToLayoutBox(child.out_of_flow_positioned_box)),
- child.offset, child.container_direction);
+ child.Offset(), child.container_direction);
child.out_of_flow_positioned_box = nullptr;
}
}
}
void NGLineBoxFragmentBuilder::PropagateChildrenData(ChildList& children) {
- for (auto& child : children) {
+ for (unsigned index = 0; index < children.size(); ++index) {
+ auto& child = children[index];
if (child.layout_result) {
DCHECK(!child.fragment);
- const NGPhysicalContainerFragment& fragment =
- child.layout_result->PhysicalFragment();
- if (fragment.IsFloating()) {
- // Add positioned floating objects to the fragment tree, not to the
- // fragment item list. Because they are not necessary for inline
- // traversals, and leading floating objects are still in the fragment
- // tree, this helps simplifying painting floats.
- AddChild(fragment, child.offset);
- child.layout_result.reset();
- continue;
- }
- PropagateChildData(child.layout_result->PhysicalFragment(), child.offset);
+ PropagateChildData(child.layout_result->PhysicalFragment(),
+ child.Offset());
+
+ // Skip over any children, the information should have already been
+ // propagated into this layout result.
+ if (child.children_count)
+ index += child.children_count - 1;
+
continue;
}
if (child.out_of_flow_positioned_box) {
AddOutOfFlowInlineChildCandidate(
NGBlockNode(ToLayoutBox(child.out_of_flow_positioned_box)),
- child.offset, child.container_direction);
+ child.Offset(), child.container_direction);
child.out_of_flow_positioned_box = nullptr;
}
}
@@ -148,7 +158,9 @@ NGLineBoxFragmentBuilder::ToLineBoxFragment() {
scoped_refptr<const NGPhysicalLineBoxFragment> fragment =
NGPhysicalLineBoxFragment::Create(this);
- return base::AdoptRef(new NGLayoutResult(std::move(fragment), this));
+ return base::AdoptRef(
+ new NGLayoutResult(NGLayoutResult::NGLineBoxFragmentBuilderPassKey(),
+ std::move(fragment), this));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
index 00807812e98..93550d8b80f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h
@@ -5,7 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_BOX_FRAGMENT_BUILDER_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_BOX_FRAGMENT_BUILDER_H_
-#include "third_party/blink/renderer/core/layout/geometry/logical_offset.h"
+#include "third_party/blink/renderer/core/layout/geometry/logical_rect.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h"
@@ -77,11 +77,12 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
scoped_refptr<const NGLayoutResult> layout_result;
scoped_refptr<const NGPhysicalTextFragment> fragment;
+ const NGInlineItem* inline_item = nullptr;
LayoutObject* out_of_flow_positioned_box = nullptr;
LayoutObject* unpositioned_float = nullptr;
// The offset of the border box, initially in this child coordinate system.
// |ComputeInlinePositions()| converts it to the offset within the line box.
- LogicalOffset offset;
+ LogicalRect rect;
// The offset of a positioned float wrt. the root BFC. This should only be
// set for positioned floats.
NGBfcOffset bfc_offset;
@@ -103,18 +104,35 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
Child() = default;
// Create a placeholder. A placeholder does not have a fragment nor a bidi
// level.
- Child(LogicalOffset offset) : offset(offset) {}
+ Child(LayoutUnit block_offset, LayoutUnit block_size)
+ : rect(LayoutUnit(), block_offset, LayoutUnit(), block_size) {}
+ Child(const NGInlineItem& inline_item,
+ const LogicalRect& rect,
+ unsigned children_count)
+ : inline_item(&inline_item),
+ rect(rect),
+ children_count(children_count) {}
// Crete a bidi control. A bidi control does not have a fragment, but has
// bidi level and affects bidi reordering.
Child(UBiDiLevel bidi_level) : bidi_level(bidi_level) {}
// Create an in-flow |NGLayoutResult|.
Child(scoped_refptr<const NGLayoutResult> layout_result,
+ const LogicalRect& rect,
+ unsigned children_count,
+ UBiDiLevel bidi_level)
+ : layout_result(std::move(layout_result)),
+ rect(rect),
+ children_count(children_count),
+ bidi_level(bidi_level) {}
+ Child(scoped_refptr<const NGLayoutResult> layout_result,
LogicalOffset offset,
LayoutUnit inline_size,
+ unsigned children_count,
UBiDiLevel bidi_level)
: layout_result(std::move(layout_result)),
- offset(offset),
+ rect(offset, LogicalSize()),
inline_size(inline_size),
+ children_count(children_count),
bidi_level(bidi_level) {}
// Create an in-flow |NGPhysicalTextFragment|.
Child(scoped_refptr<const NGPhysicalTextFragment> fragment,
@@ -122,7 +140,7 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
LayoutUnit inline_size,
UBiDiLevel bidi_level)
: fragment(std::move(fragment)),
- offset(offset),
+ rect(offset, LogicalSize()),
inline_size(inline_size),
bidi_level(bidi_level) {}
Child(scoped_refptr<const NGPhysicalTextFragment> fragment,
@@ -130,7 +148,7 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
LayoutUnit inline_size,
UBiDiLevel bidi_level)
: fragment(std::move(fragment)),
- offset({LayoutUnit(), block_offset}),
+ rect(LayoutUnit(), block_offset, LayoutUnit(), LayoutUnit()),
inline_size(inline_size),
bidi_level(bidi_level) {}
// Create an out-of-flow positioned object.
@@ -180,11 +198,20 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
}
return false;
}
+ const LogicalOffset& Offset() const { return rect.offset; }
+ LayoutUnit InlineOffset() const { return rect.offset.inline_offset; }
+ const LogicalSize& Size() const { return rect.size; }
const NGPhysicalFragment* PhysicalFragment() const {
if (layout_result)
return &layout_result->PhysicalFragment();
return fragment.get();
}
+ TextDirection ResolvedDirection() const {
+ // Inline boxes are not leaves that they don't have directions.
+ DCHECK(HasBidiLevel() || layout_result->PhysicalFragment().IsInlineBox());
+ return HasBidiLevel() ? DirectionFromLevel(bidi_level)
+ : TextDirection::kLtr;
+ }
};
// A vector of Child.
@@ -234,11 +261,18 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
void InsertChild(unsigned index);
void InsertChild(unsigned index,
scoped_refptr<const NGLayoutResult> layout_result,
- const LogicalOffset& offset,
- LayoutUnit inline_size,
- UBiDiLevel bidi_level) {
- children_.insert(index, Child{std::move(layout_result), offset,
- inline_size, bidi_level});
+ const LogicalRect& rect,
+ unsigned children_count) {
+ WillInsertChild(index);
+ children_.insert(index, Child(std::move(layout_result), rect,
+ children_count, /* bidi_level */ 0));
+ }
+ void InsertChild(unsigned index,
+ const NGInlineItem& inline_item,
+ const LogicalRect& rect,
+ unsigned children_count) {
+ WillInsertChild(index);
+ children_.insert(index, Child(inline_item, rect, children_count));
}
void MoveInInlineDirection(LayoutUnit);
@@ -247,6 +281,8 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
void MoveInBlockDirection(LayoutUnit, unsigned start, unsigned end);
private:
+ void WillInsertChild(unsigned index);
+
Vector<Child, 16> children_;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
index 31c45dd7290..494d7ae3167 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc
@@ -132,22 +132,16 @@ LayoutUnit ComputeFloatAncestorInlineEndSize(const NGConstraintSpace& space,
return inline_end_size;
}
-scoped_refptr<const NGPhysicalTextFragment> CreateHyphenFragment(
- NGInlineNode node,
- WritingMode writing_mode,
- const NGInlineItem& item) {
+void CreateHyphen(NGInlineNode node,
+ WritingMode writing_mode,
+ const NGInlineItem& item,
+ NGInlineItemResult* item_result) {
DCHECK(item.Style());
const ComputedStyle& style = *item.Style();
TextDirection direction = style.Direction();
- String hyphen_string = style.HyphenString();
- HarfBuzzShaper shaper(hyphen_string);
- scoped_refptr<ShapeResult> hyphen_result =
- shaper.Shape(&style.GetFont(), direction);
- NGTextFragmentBuilder builder(writing_mode);
- builder.SetText(item.GetLayoutObject(), hyphen_string, &style,
- /* is_ellipsis_style */ false,
- ShapeResultView::Create(hyphen_result.get()));
- return builder.ToTextFragment();
+ item_result->hyphen_string = style.HyphenString();
+ HarfBuzzShaper shaper(item_result->hyphen_string);
+ item_result->hyphen_shape_result = shaper.Shape(&style.GetFont(), direction);
}
inline void ClearNeedsLayout(const NGInlineItem& item) {
@@ -183,10 +177,13 @@ NGLineBreaker::NGLineBreaker(NGInlineNode node,
use_first_line_style_(is_first_formatted_line_ &&
node.UseFirstLineStyle()),
in_line_height_quirks_mode_(node.InLineHeightQuirksMode()),
+ sticky_images_quirk_(mode != NGLineBreakerMode::kContent &&
+ node.IsStickyImagesQuirkForContentSize()),
items_data_(node.ItemsData(use_first_line_style_)),
- text_content_(mode == NGLineBreakerMode::kContent
- ? items_data_.text_content
- : node.TextContentForContentSize(items_data_)),
+ text_content_(
+ !sticky_images_quirk_
+ ? items_data_.text_content
+ : NGInlineNode::TextContentForStickyImagesQuirk(items_data_)),
constraint_space_(space),
exclusion_space_(exclusion_space),
break_token_(break_token),
@@ -262,25 +259,6 @@ void NGLineBreaker::SetMaxSizeCache(MaxSizeCache* max_size_cache) {
max_size_cache_ = max_size_cache;
}
-LayoutUnit NGLineBreaker::SetLineEndFragment(
- scoped_refptr<const NGPhysicalTextFragment> fragment,
- NGLineInfo* line_info) {
- LayoutUnit inline_size;
- bool is_horizontal =
- IsHorizontalWritingMode(constraint_space_.GetWritingMode());
- if (line_info->LineEndFragment()) {
- const PhysicalSize& size = line_info->LineEndFragment()->Size();
- inline_size = is_horizontal ? -size.width : -size.height;
- }
- if (fragment) {
- const PhysicalSize& size = fragment->Size();
- inline_size = is_horizontal ? size.width : size.height;
- }
- line_info->SetLineEndFragment(std::move(fragment));
- position_ += inline_size;
- return inline_size;
-}
-
// Compute the base direction for bidi algorithm for this line.
void NGLineBreaker::ComputeBaseDirection() {
// If 'unicode-bidi' is not 'plaintext', use the base direction of the block.
@@ -492,29 +470,15 @@ void NGLineBreaker::ComputeLineLocation(NGLineInfo* line_info) const {
line_info->UpdateTextAlign();
}
-// For Web-compatibility, allow break between an atomic inline and any adjacent
-// U+00A0 NO-BREAK SPACE character.
-// https://www.w3.org/TR/css-text-3/#line-break-details
-bool NGLineBreaker::IsAtomicInlineBeforeNoBreakSpace(
- const NGInlineItemResult& item_result) const {
- DCHECK(auto_wrap_);
- DCHECK_EQ(item_result.item->Type(), NGInlineItem::kAtomicInline);
- const String& text = Text();
- DCHECK_GE(text.length(), item_result.end_offset);
- return text.length() > item_result.end_offset &&
- text[item_result.end_offset] == kNoBreakSpaceCharacter &&
- // Except when sticky images quirk was applied.
- text[item_result.start_offset] != kNoBreakSpaceCharacter;
-}
-
-bool NGLineBreaker::IsAtomicInlineAfterNoBreakSpace(
+// Atomic inlines have break opportunities before and after, even when the
+// adjacent character is U+00A0 NO-BREAK SPACE character.
+bool NGLineBreaker::ShouldForceCanBreakAfter(
const NGInlineItemResult& item_result) const {
DCHECK(auto_wrap_);
DCHECK_EQ(item_result.item->Type(), NGInlineItem::kText);
const String& text = Text();
DCHECK_GE(text.length(), item_result.end_offset);
- if (text[item_result.end_offset - 1] != kNoBreakSpaceCharacter ||
- text.length() <= item_result.end_offset ||
+ if (text.length() <= item_result.end_offset ||
text[item_result.end_offset] != kObjectReplacementCharacter)
return false;
// This kObjectReplacementCharacter can be any objects, such as a floating or
@@ -598,8 +562,10 @@ void NGLineBreaker::HandleText(const NGInlineItem& item,
}
// Try to break inside of this text item.
- BreakResult break_result = BreakText(item_result, item, shape_result,
- RemainingAvailableWidth(), line_info);
+ const LayoutUnit available_width = RemainingAvailableWidth();
+ BreakResult break_result =
+ BreakText(item_result, item, shape_result, available_width,
+ available_width, line_info);
DCHECK(item_result->shape_result ||
(break_result == kOverflow && break_anywhere_if_overflow_ &&
!override_break_anywhere_));
@@ -677,6 +643,7 @@ NGLineBreaker::BreakResult NGLineBreaker::BreakText(
const NGInlineItem& item,
const ShapeResult& item_shape_result,
LayoutUnit available_width,
+ LayoutUnit available_width_with_hyphens,
NGLineInfo* line_info) {
DCHECK(item.Type() == NGInlineItem::kText ||
(item.Type() == NGInlineItem::kControl &&
@@ -739,7 +706,7 @@ NGLineBreaker::BreakResult NGLineBreaker::BreakText(
// rewinded. Making this item long enough to overflow is enough.
if (!shape_result) {
DCHECK(options & ShapingLineBreaker::kNoResultIfOverflow);
- item_result->inline_size = available_width + 1;
+ item_result->inline_size = available_width_with_hyphens + 1;
item_result->end_offset = item.EndOffset();
return kOverflow;
}
@@ -750,25 +717,27 @@ NGLineBreaker::BreakResult NGLineBreaker::BreakText(
CHECK_GT(result.break_offset, item_result->start_offset);
inline_size = shape_result->SnappedWidth().ClampNegativeToZero();
- item_result->inline_size = inline_size;
if (UNLIKELY(result.is_hyphenated)) {
const WritingMode writing_mode = constraint_space_.GetWritingMode();
- scoped_refptr<const NGPhysicalTextFragment> hyphen_fragment =
- CreateHyphenFragment(node_, writing_mode, item);
- LayoutUnit space_for_hyphen = available_width - inline_size;
- LayoutUnit hyphen_inline_size = IsHorizontalWritingMode(writing_mode)
- ? hyphen_fragment->Size().width
- : hyphen_fragment->Size().height;
+ CreateHyphen(node_, writing_mode, item, item_result);
+ DCHECK(item_result->hyphen_shape_result);
+ DCHECK(item_result->hyphen_string);
+ LayoutUnit hyphen_inline_size = item_result->HyphenInlineSize();
// If the hyphen overflows, retry with the reduced available width.
- if (space_for_hyphen >= 0 && hyphen_inline_size > space_for_hyphen) {
- available_width -= hyphen_inline_size;
- continue;
+ if (!result.is_overflow && inline_size <= available_width) {
+ LayoutUnit space_for_hyphen =
+ available_width_with_hyphens - inline_size;
+ if (space_for_hyphen >= 0 && hyphen_inline_size > space_for_hyphen) {
+ available_width -= hyphen_inline_size;
+ continue;
+ }
}
- inline_size += SetLineEndFragment(std::move(hyphen_fragment), line_info);
- item_result->text_end_effect = NGTextEndEffect::kHyphen;
+ inline_size += hyphen_inline_size;
+ } else if (UNLIKELY(item_result->hyphen_shape_result)) {
+ item_result->hyphen_shape_result = nullptr;
+ item_result->hyphen_string = String();
}
- item_result->inline_size =
- shape_result->SnappedWidth().ClampNegativeToZero();
+ item_result->inline_size = inline_size;
item_result->end_offset = result.break_offset;
item_result->shape_result = std::move(shape_result);
break;
@@ -796,7 +765,7 @@ NGLineBreaker::BreakResult NGLineBreaker::BreakText(
item_result->can_break_after =
break_iterator_.IsBreakable(item_result->end_offset);
if (!item_result->can_break_after && item.Type() == NGInlineItem::kText &&
- IsAtomicInlineAfterNoBreakSpace(*item_result))
+ ShouldForceCanBreakAfter(*item_result))
item_result->can_break_after = true;
trailing_whitespace_ = WhitespaceState::kUnknown;
}
@@ -1344,6 +1313,21 @@ void NGLineBreaker::HandleAtomicInline(
DCHECK(item.Style());
const ComputedStyle& style = *item.Style();
+ const LayoutUnit remaining_width = RemainingAvailableWidth();
+ bool ignore_overflow_if_negative_margin = false;
+ if (state_ == LineBreakState::kContinue && remaining_width < 0) {
+ const unsigned item_index = item_index_;
+ DCHECK_EQ(item_index, static_cast<unsigned>(&item - Items().begin()));
+ DCHECK(!line_info->HasOverflow());
+ HandleOverflow(line_info);
+ if (!line_info->HasOverflow() || item_index != item_index_)
+ return;
+ // Compute margins if this line overflows. Negative margins can put the
+ // position back.
+ DCHECK_NE(state_, LineBreakState::kContinue);
+ ignore_overflow_if_negative_margin = true;
+ }
+
// Compute margins before computing overflow, because even when the current
// position is beyond the end, negative margins can bring this item back to on
// the current line.
@@ -1351,13 +1335,18 @@ void NGLineBreaker::HandleAtomicInline(
item_result->margins =
ComputeLineMarginsForVisualContainer(constraint_space_, style);
LayoutUnit inline_margins = item_result->margins.InlineSum();
- LayoutUnit remaining_width = RemainingAvailableWidth();
- bool is_overflow_before =
- state_ == LineBreakState::kContinue && remaining_width < 0;
- if (UNLIKELY(is_overflow_before && inline_margins > remaining_width)) {
- RemoveLastItem(line_info);
- HandleOverflow(line_info);
- return;
+ if (UNLIKELY(ignore_overflow_if_negative_margin)) {
+ DCHECK_LT(remaining_width, 0);
+ // The margin isn't negative, or the negative margin isn't large enough to
+ // put the position back. Break this line before this item.
+ if (inline_margins >= remaining_width) {
+ RemoveLastItem(line_info);
+ return;
+ }
+ // This line once overflowed, but the negative margin puts the position
+ // back.
+ state_ = LineBreakState::kContinue;
+ line_info->SetHasOverflow(false);
}
// When we're just computing min/max content sizes, we can skip the full
@@ -1369,7 +1358,6 @@ void NGLineBreaker::HandleAtomicInline(
item_result->layout_result =
NGBlockNode(ToLayoutBox(item.GetLayoutObject()))
.LayoutAtomicInline(constraint_space_, node_.Style(),
- line_info->LineStyle().GetFontBaseline(),
line_info->UseFirstLineStyle());
item_result->inline_size =
NGFragment(constraint_space_.GetWritingMode(),
@@ -1382,8 +1370,8 @@ void NGLineBreaker::HandleAtomicInline(
} else {
DCHECK(mode_ == NGLineBreakerMode::kMinContent || !max_size_cache_);
NGBlockNode child(ToLayoutBox(item.GetLayoutObject()));
- MinMaxSizeInput input(percentage_resolution_block_size_for_min_max);
- MinMaxSize sizes =
+ MinMaxSizesInput input(percentage_resolution_block_size_for_min_max);
+ MinMaxSizes sizes =
ComputeMinAndMaxContentContribution(node_.Style(), child, input);
if (mode_ == NGLineBreakerMode::kMinContent) {
item_result->inline_size = sizes.min_size + inline_margins;
@@ -1399,10 +1387,11 @@ void NGLineBreaker::HandleAtomicInline(
}
item_result->should_create_line_box = true;
- ComputeCanBreakAfter(item_result, auto_wrap_, break_iterator_);
- if (!item_result->can_break_after && auto_wrap_ &&
- IsAtomicInlineBeforeNoBreakSpace(*item_result))
- item_result->can_break_after = true;
+ // Atomic inlines have break opportunities before and after, even when the
+ // adjacent character is U+00A0 NO-BREAK SPACE character, except when sticky
+ // images quirk is applied.
+ item_result->can_break_after =
+ auto_wrap_ && !(sticky_images_quirk_ && item.IsImage());
position_ += item_result->inline_size;
trailing_whitespace_ = WhitespaceState::kNone;
@@ -1448,6 +1437,10 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item,
!leading_floats_.IsEmpty()) {
DCHECK_LT(leading_floats_index_, leading_floats_.size());
item_result->positioned_float = leading_floats_[leading_floats_index_++];
+
+ // Don't break after leading floats if indented.
+ if (position_ != 0)
+ item_result->can_break_after = false;
return;
}
@@ -1654,9 +1647,6 @@ void NGLineBreaker::HandleOverflow(NGLineInfo* line_info) {
LayoutUnit width_to_rewind = position_ - available_width;
DCHECK_GT(width_to_rewind, 0);
- // Indicates positions of items may be changed and need to UpdatePosition().
- bool position_maybe_changed = false;
-
// Keep track of the shortest break opportunity.
unsigned break_before = 0;
@@ -1699,40 +1689,36 @@ void NGLineBreaker::HandleOverflow(NGLineInfo* line_info) {
// If space is available, and if this text is breakable, part of the text
// may fit. Try to break this item.
if (width_to_rewind < 0 && item_result->may_break_inside) {
- LayoutUnit item_available_width = -width_to_rewind;
+ const LayoutUnit item_available_width = -width_to_rewind;
// Make sure the available width is smaller than the current width. The
// break point must not be at the end when e.g., the text fits but its
// right margin does not or following items do not.
const LayoutUnit min_available_width = item_result->inline_size - 1;
- if (item_available_width > min_available_width) {
- item_available_width = min_available_width;
- // If |inline_size| is zero (e.g., `font-size: 0`), |BreakText| cannot
- // make it shorter. Take the previous break opportunity.
- if (UNLIKELY(item_available_width <= 0)) {
- if (BreakTextAtPreviousBreakOpportunity(item_result)) {
- RewindOverflow(i + 1, line_info);
- return;
- }
- continue;
+ // If |inline_size| is zero (e.g., `font-size: 0`), |BreakText| cannot
+ // make it shorter. Take the previous break opportunity.
+ if (UNLIKELY(min_available_width <= 0)) {
+ if (BreakTextAtPreviousBreakOpportunity(item_result)) {
+ RewindOverflow(i + 1, line_info);
+ return;
}
+ continue;
}
- auto was_current_style = current_style_;
+ scoped_refptr<const ComputedStyle> was_current_style = current_style_;
SetCurrentStyle(*item.Style());
- const unsigned end_offset_before = item_result->end_offset;
- BreakResult break_result =
- BreakText(item_result, item, *item.TextShapeResult(),
- item_available_width, line_info);
- DCHECK_LE(item_result->end_offset, end_offset_before);
+ const NGInlineItemResult item_result_before = *item_result;
+ BreakText(item_result, item, *item.TextShapeResult(),
+ std::min(item_available_width, min_available_width),
+ item_available_width, line_info);
+ DCHECK_LE(item_result->end_offset, item_result_before.end_offset);
#if DCHECK_IS_ON()
item_result->CheckConsistency(true);
#endif
+
// If BreakText() changed this item small enough to fit, break here.
- DCHECK_EQ(break_result == kSuccess,
- item_result->inline_size <= item_available_width);
- if (break_result == kSuccess) {
- DCHECK_LE(item_result->inline_size, item_available_width);
+ if (item_result->can_break_after &&
+ item_result->inline_size <= item_available_width &&
+ item_result->end_offset < item_result_before.end_offset) {
DCHECK_LT(item_result->end_offset, item.EndOffset());
- DCHECK(item_result->can_break_after);
// If this is the last item, adjust it to accommodate the change.
const unsigned new_end = i + 1;
@@ -1740,8 +1726,6 @@ void NGLineBreaker::HandleOverflow(NGLineInfo* line_info) {
if (new_end == item_results->size()) {
position_ =
available_width + width_to_rewind + item_result->inline_size;
- if (line_info->LineEndFragment())
- SetLineEndFragment(nullptr, line_info);
DCHECK_EQ(position_, line_info->ComputeWidth());
item_index_ = item_result->item_index;
offset_ = item_result->end_offset;
@@ -1757,8 +1741,10 @@ void NGLineBreaker::HandleOverflow(NGLineInfo* line_info) {
HandleTrailingSpaces(item, line_info);
return;
}
+
+ // Failed to break to fit. Restore to the original state.
+ *item_result = std::move(item_result_before);
SetCurrentStyle(*was_current_style);
- position_maybe_changed = true;
}
}
}
@@ -1786,11 +1772,6 @@ void NGLineBreaker::HandleOverflow(NGLineInfo* line_info) {
return;
}
- if (position_maybe_changed) {
- trailing_whitespace_ = WhitespaceState::kUnknown;
- position_ = line_info->ComputeWidth();
- }
-
if (CanBreakAfterLast(*item_results)) {
state_ = LineBreakState::kTrailing;
return;
@@ -1810,6 +1791,7 @@ void NGLineBreaker::RewindOverflow(unsigned new_end, NGLineInfo* line_info) {
const Vector<NGInlineItem>& items = Items();
const NGInlineItemResults& item_results = line_info->Results();
DCHECK_LT(new_end, item_results.size());
+
unsigned open_tag_count = 0;
const String& text = Text();
for (unsigned index = new_end; index < item_results.size(); index++) {
@@ -1819,16 +1801,20 @@ void NGLineBreaker::RewindOverflow(unsigned new_end, NGLineInfo* line_info) {
if (item.Type() == NGInlineItem::kText) {
// Text items are trailable if they start with trailable spaces.
DCHECK_GT(item_result.Length(), 0u);
- if (item_result.shape_result) {
+ if (item_result.shape_result || // kNoResultIfOverflow if 'break-word'
+ (break_anywhere_if_overflow_ && !override_break_anywhere_)) {
DCHECK(item.Style());
const EWhiteSpace white_space = item.Style()->WhiteSpace();
if (ComputedStyle::AutoWrap(white_space) &&
white_space != EWhiteSpace::kBreakSpaces &&
IsBreakableSpace(text[item_result.start_offset])) {
- // If all characters are trailable spaces, check the next item.
- if (IsAllBreakableSpaces(text, item_result.start_offset + 1,
- item_result.end_offset))
+ // If more items left and all characters are trailable spaces, check
+ // the next item.
+ if (item_result.shape_result && index < item_results.size() - 1 &&
+ IsAllBreakableSpaces(text, item_result.start_offset + 1,
+ item_result.end_offset)) {
continue;
+ }
// If this item starts with spaces followed by non-space characters,
// rewind to before this item. |HandleText()| will include the spaces
// and break there.
@@ -1836,6 +1822,9 @@ void NGLineBreaker::RewindOverflow(unsigned new_end, NGLineInfo* line_info) {
Rewind(index, line_info);
DCHECK_EQ(static_cast<unsigned>(&item - items.begin()), item_index_);
HandleTrailingSpaces(item, line_info);
+#if DCHECK_IS_ON()
+ item_results.back().CheckConsistency(false);
+#endif
return;
}
}
@@ -1962,7 +1951,6 @@ void NGLineBreaker::Rewind(unsigned new_end, NGLineInfo* line_info) {
item_results.Shrink(new_end);
trailing_collapsible_space_.reset();
- SetLineEndFragment(nullptr, line_info);
position_ = line_info->ComputeWidth();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
index d19c268bcae..ac8685caad5 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h
@@ -99,8 +99,6 @@ class CORE_EXPORT NGLineBreaker {
unsigned end_offset,
NGLineInfo*);
NGInlineItemResult* AddItem(const NGInlineItem&, NGLineInfo*);
- LayoutUnit SetLineEndFragment(scoped_refptr<const NGPhysicalTextFragment>,
- NGLineInfo*);
void BreakLine(LayoutUnit percentage_resolution_block_size_for_min_max,
NGLineInfo*);
@@ -135,6 +133,7 @@ class CORE_EXPORT NGLineBreaker {
const NGInlineItem&,
const ShapeResult&,
LayoutUnit available_width,
+ LayoutUnit available_width_with_hyphens,
NGLineInfo*);
bool BreakTextAtPreviousBreakOpportunity(NGInlineItemResult* item_result);
bool HandleTextForFastMinContent(NGInlineItemResult*,
@@ -166,10 +165,7 @@ class CORE_EXPORT NGLineBreaker {
const NGInlineItem&,
LayoutUnit percentage_resolution_block_size_for_min_max,
NGLineInfo*);
- bool IsAtomicInlineAfterNoBreakSpace(
- const NGInlineItemResult& item_result) const;
- bool IsAtomicInlineBeforeNoBreakSpace(
- const NGInlineItemResult& item_result) const;
+ bool ShouldForceCanBreakAfter(const NGInlineItemResult& item_result) const;
void HandleFloat(const NGInlineItem&,
NGLineInfo*);
void HandleOutOfFlowPositioned(const NGInlineItem&, NGLineInfo*);
@@ -260,6 +256,10 @@ class CORE_EXPORT NGLineBreaker {
// the next line.
bool is_after_forced_break_ = false;
+ // Set in quirks mode when we're not supposed to break inside table cells
+ // between images, and between text and images.
+ bool sticky_images_quirk_ = false;
+
const NGInlineItemsData& items_data_;
// The text content of this node. This is same as |items_data_.text_content|
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
index 34eba2935cd..4e53d79afa3 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc
@@ -17,6 +17,17 @@
namespace blink {
+String ToString(NGInlineItemResults line, NGInlineNode node) {
+ StringBuilder builder;
+ const String& text = node.ItemsData(false).text_content;
+ for (const auto& item_result : line) {
+ builder.Append(
+ StringView(text, item_result.start_offset,
+ item_result.end_offset - item_result.start_offset));
+ }
+ return builder.ToString();
+}
+
class NGLineBreakerTest : public NGLayoutTest {
protected:
NGInlineNode CreateInlineNode(const String& html_content) {
@@ -28,8 +39,10 @@ class NGLineBreakerTest : public NGLayoutTest {
}
// Break lines using the specified available width.
- Vector<NGLineInfo> BreakToLineInfo(NGInlineNode node,
- LayoutUnit available_width) {
+ Vector<std::pair<String, unsigned>> BreakLines(
+ NGInlineNode node,
+ LayoutUnit available_width,
+ bool fill_first_space_ = false) {
DCHECK(node);
node.PrepareLayoutIfNeeded();
@@ -42,13 +55,13 @@ class NGLineBreakerTest : public NGLayoutTest {
scoped_refptr<NGInlineBreakToken> break_token;
- Vector<NGLineInfo> line_infos;
+ Vector<std::pair<String, unsigned>> lines;
trailing_whitespaces_.resize(0);
NGExclusionSpace exclusion_space;
NGPositionedFloatVector leading_floats;
NGLineLayoutOpportunity line_opportunity(available_width);
while (!break_token || !break_token->IsFinished()) {
- NGLineInfo& line_info = line_infos.emplace_back();
+ NGLineInfo line_info;
NGLineBreaker line_breaker(node, NGLineBreakerMode::kContent, space,
line_opportunity, leading_floats, 0u,
break_token.get(), &exclusion_space);
@@ -60,36 +73,25 @@ class NGLineBreakerTest : public NGLayoutTest {
break;
break_token = line_breaker.CreateBreakToken(line_info);
+ if (fill_first_space_ && lines.IsEmpty()) {
+ first_should_hang_trailing_space_ =
+ line_info.ShouldHangTrailingSpaces();
+ first_hang_width_ = line_info.HangWidth();
+ }
+ lines.push_back(std::make_pair(ToString(line_info.Results(), node),
+ line_info.Results().back().item_index));
}
- return line_infos;
- }
-
- Vector<NGInlineItemResults> BreakLines(NGInlineNode node,
- LayoutUnit available_width) {
- Vector<NGLineInfo> line_infos = BreakToLineInfo(node, available_width);
- Vector<NGInlineItemResults> lines;
- for (NGLineInfo& line_info : line_infos)
- lines.push_back(std::move(line_info.Results()));
return lines;
}
Vector<NGLineBreaker::WhitespaceState> trailing_whitespaces_;
+ bool first_should_hang_trailing_space_;
+ LayoutUnit first_hang_width_;
};
namespace {
-String ToString(NGInlineItemResults line, NGInlineNode node) {
- StringBuilder builder;
- const String& text = node.ItemsData(false).text_content;
- for (const auto& item_result : line) {
- builder.Append(
- StringView(text, item_result.start_offset,
- item_result.end_offset - item_result.start_offset));
- }
- return builder.ToString();
-}
-
TEST_F(NGLineBreakerTest, SingleNode) {
LoadAhem();
NGInlineNode node = CreateInlineNode(R"HTML(
@@ -102,17 +104,17 @@ TEST_F(NGLineBreakerTest, SingleNode) {
<div id=container>123 456 789</div>
)HTML");
- Vector<NGInlineItemResults> lines;
+ Vector<std::pair<String, unsigned>> lines;
lines = BreakLines(node, LayoutUnit(80));
EXPECT_EQ(2u, lines.size());
- EXPECT_EQ("123 456", ToString(lines[0], node));
- EXPECT_EQ("789", ToString(lines[1], node));
+ EXPECT_EQ("123 456", lines[0].first);
+ EXPECT_EQ("789", lines[1].first);
lines = BreakLines(node, LayoutUnit(60));
EXPECT_EQ(3u, lines.size());
- EXPECT_EQ("123", ToString(lines[0], node));
- EXPECT_EQ("456", ToString(lines[1], node));
- EXPECT_EQ("789", ToString(lines[2], node));
+ EXPECT_EQ("123", lines[0].first);
+ EXPECT_EQ("456", lines[1].first);
+ EXPECT_EQ("789", lines[2].first);
}
TEST_F(NGLineBreakerTest, OverflowWord) {
@@ -128,17 +130,17 @@ TEST_F(NGLineBreakerTest, OverflowWord) {
)HTML");
// The first line overflows, but the last line does not.
- Vector<NGInlineItemResults> lines;
+ Vector<std::pair<String, unsigned>> lines;
lines = BreakLines(node, LayoutUnit(40));
EXPECT_EQ(2u, lines.size());
- EXPECT_EQ("12345", ToString(lines[0], node));
- EXPECT_EQ("678", ToString(lines[1], node));
+ EXPECT_EQ("12345", lines[0].first);
+ EXPECT_EQ("678", lines[1].first);
// Both lines overflow.
lines = BreakLines(node, LayoutUnit(20));
EXPECT_EQ(2u, lines.size());
- EXPECT_EQ("12345", ToString(lines[0], node));
- EXPECT_EQ("678", ToString(lines[1], node));
+ EXPECT_EQ("12345", lines[0].first);
+ EXPECT_EQ("678", lines[1].first);
}
TEST_F(NGLineBreakerTest, OverflowTab) {
@@ -156,11 +158,11 @@ TEST_F(NGLineBreakerTest, OverflowTab) {
<div id=container>12345&#9;&#9;678</div>
)HTML");
- Vector<NGInlineItemResults> lines;
+ Vector<std::pair<String, unsigned>> lines;
lines = BreakLines(node, LayoutUnit(100));
EXPECT_EQ(2u, lines.size());
- EXPECT_EQ("12345\t\t", ToString(lines[0], node));
- EXPECT_EQ("678", ToString(lines[1], node));
+ EXPECT_EQ("12345\t\t", lines[0].first);
+ EXPECT_EQ("678", lines[1].first);
}
TEST_F(NGLineBreakerTest, OverflowTabBreakWord) {
@@ -179,11 +181,11 @@ TEST_F(NGLineBreakerTest, OverflowTabBreakWord) {
<div id=container>12345&#9;&#9;678</div>
)HTML");
- Vector<NGInlineItemResults> lines;
+ Vector<std::pair<String, unsigned>> lines;
lines = BreakLines(node, LayoutUnit(100));
EXPECT_EQ(2u, lines.size());
- EXPECT_EQ("12345\t\t", ToString(lines[0], node));
- EXPECT_EQ("678", ToString(lines[1], node));
+ EXPECT_EQ("12345\t\t", lines[0].first);
+ EXPECT_EQ("678", lines[1].first);
}
TEST_F(NGLineBreakerTest, OverflowAtomicInline) {
@@ -203,28 +205,28 @@ TEST_F(NGLineBreakerTest, OverflowAtomicInline) {
<div id=container>12345<span></span>678</div>
)HTML");
- Vector<NGInlineItemResults> lines;
+ Vector<std::pair<String, unsigned>> lines;
lines = BreakLines(node, LayoutUnit(80));
EXPECT_EQ(2u, lines.size());
- EXPECT_EQ(String(u"12345\uFFFC"), ToString(lines[0], node));
- EXPECT_EQ("678", ToString(lines[1], node));
+ EXPECT_EQ(String(u"12345\uFFFC"), lines[0].first);
+ EXPECT_EQ("678", lines[1].first);
lines = BreakLines(node, LayoutUnit(70));
EXPECT_EQ(2u, lines.size());
- EXPECT_EQ("12345", ToString(lines[0], node));
- EXPECT_EQ(String(u"\uFFFC678"), ToString(lines[1], node));
+ EXPECT_EQ("12345", lines[0].first);
+ EXPECT_EQ(String(u"\uFFFC678"), lines[1].first);
lines = BreakLines(node, LayoutUnit(40));
EXPECT_EQ(3u, lines.size());
- EXPECT_EQ("12345", ToString(lines[0], node));
- EXPECT_EQ(String(u"\uFFFC"), ToString(lines[1], node));
- EXPECT_EQ("678", ToString(lines[2], node));
+ EXPECT_EQ("12345", lines[0].first);
+ EXPECT_EQ(String(u"\uFFFC"), lines[1].first);
+ EXPECT_EQ("678", lines[2].first);
lines = BreakLines(node, LayoutUnit(20));
EXPECT_EQ(3u, lines.size());
- EXPECT_EQ("12345", ToString(lines[0], node));
- EXPECT_EQ(String(u"\uFFFC"), ToString(lines[1], node));
- EXPECT_EQ("678", ToString(lines[2], node));
+ EXPECT_EQ("12345", lines[0].first);
+ EXPECT_EQ(String(u"\uFFFC"), lines[1].first);
+ EXPECT_EQ("678", lines[2].first);
}
TEST_F(NGLineBreakerTest, OverflowMargin) {
@@ -246,21 +248,21 @@ TEST_F(NGLineBreakerTest, OverflowMargin) {
// While "123 456" can fit in a line, "456" has a right margin that cannot
// fit. Since "456" and its right margin is not breakable, "456" should be on
// the next line.
- Vector<NGInlineItemResults> lines;
+ Vector<std::pair<String, unsigned>> lines;
lines = BreakLines(node, LayoutUnit(80));
EXPECT_EQ(3u, lines.size());
- EXPECT_EQ("123", ToString(lines[0], node));
- EXPECT_EQ("456", ToString(lines[1], node));
- DCHECK_EQ(NGInlineItem::kCloseTag, items[lines[1].back().item_index].Type());
- EXPECT_EQ("789", ToString(lines[2], node));
+ EXPECT_EQ("123", lines[0].first);
+ EXPECT_EQ("456", lines[1].first);
+ DCHECK_EQ(NGInlineItem::kCloseTag, items[lines[1].second].Type());
+ EXPECT_EQ("789", lines[2].first);
// Same as above, but this time "456" overflows the line because it is 70px.
lines = BreakLines(node, LayoutUnit(60));
EXPECT_EQ(3u, lines.size());
- EXPECT_EQ("123", ToString(lines[0], node));
- EXPECT_EQ("456", ToString(lines[1], node));
- DCHECK_EQ(NGInlineItem::kCloseTag, items[lines[1].back().item_index].Type());
- EXPECT_EQ("789", ToString(lines[2], node));
+ EXPECT_EQ("123", lines[0].first);
+ EXPECT_EQ("456", lines[1].first);
+ DCHECK_EQ(NGInlineItem::kCloseTag, items[lines[1].second].Type());
+ EXPECT_EQ("789", lines[2].first);
}
TEST_F(NGLineBreakerTest, OverflowAfterSpacesAcrossElements) {
@@ -278,12 +280,12 @@ TEST_F(NGLineBreakerTest, OverflowAfterSpacesAcrossElements) {
<div id=container><span>12345 </span> 1234567890123</div>
)HTML");
- Vector<NGInlineItemResults> lines;
+ Vector<std::pair<String, unsigned>> lines;
lines = BreakLines(node, LayoutUnit(100));
EXPECT_EQ(3u, lines.size());
- EXPECT_EQ("12345 ", ToString(lines[0], node));
- EXPECT_EQ("1234567890", ToString(lines[1], node));
- EXPECT_EQ("123", ToString(lines[2], node));
+ EXPECT_EQ("12345 ", lines[0].first);
+ EXPECT_EQ("1234567890", lines[1].first);
+ EXPECT_EQ("123", lines[2].first);
}
// Tests when the last word in a node wraps, and another node continues.
@@ -299,11 +301,11 @@ TEST_F(NGLineBreakerTest, WrapLastWord) {
<div id=container>AAA AAA AAA <span>BB</span> CC</div>
)HTML");
- Vector<NGInlineItemResults> lines;
+ Vector<std::pair<String, unsigned>> lines;
lines = BreakLines(node, LayoutUnit(100));
EXPECT_EQ(2u, lines.size());
- EXPECT_EQ("AAA AAA", ToString(lines[0], node));
- EXPECT_EQ("AAA BB CC", ToString(lines[1], node));
+ EXPECT_EQ("AAA AAA", lines[0].first);
+ EXPECT_EQ("AAA BB CC", lines[1].first);
}
TEST_F(NGLineBreakerTest, WrapLetterSpacing) {
@@ -319,11 +321,11 @@ TEST_F(NGLineBreakerTest, WrapLetterSpacing) {
<div id=container>Star Wars</div>
)HTML");
- Vector<NGInlineItemResults> lines;
+ Vector<std::pair<String, unsigned>> lines;
lines = BreakLines(node, LayoutUnit(100));
EXPECT_EQ(2u, lines.size());
- EXPECT_EQ("Star", ToString(lines[0], node));
- EXPECT_EQ("Wars", ToString(lines[1], node));
+ EXPECT_EQ("Star", lines[0].first);
+ EXPECT_EQ("Wars", lines[1].first);
}
TEST_F(NGLineBreakerTest, BoundaryInWord) {
@@ -340,20 +342,20 @@ TEST_F(NGLineBreakerTest, BoundaryInWord) {
// The element boundary within "456789" should not cause a break.
// Since "789" does not fit, it should go to the next line along with "456".
- Vector<NGInlineItemResults> lines;
+ Vector<std::pair<String, unsigned>> lines;
lines = BreakLines(node, LayoutUnit(80));
EXPECT_EQ(3u, lines.size());
- EXPECT_EQ("123", ToString(lines[0], node));
- EXPECT_EQ("456789", ToString(lines[1], node));
- EXPECT_EQ("abc", ToString(lines[2], node));
+ EXPECT_EQ("123", lines[0].first);
+ EXPECT_EQ("456789", lines[1].first);
+ EXPECT_EQ("abc", lines[2].first);
// Same as above, but this time "456789" overflows the line because it is
// 60px.
lines = BreakLines(node, LayoutUnit(50));
EXPECT_EQ(3u, lines.size());
- EXPECT_EQ("123", ToString(lines[0], node));
- EXPECT_EQ("456789", ToString(lines[1], node));
- EXPECT_EQ("abc", ToString(lines[2], node));
+ EXPECT_EQ("123", lines[0].first);
+ EXPECT_EQ("456789", lines[1].first);
+ EXPECT_EQ("abc", lines[2].first);
}
TEST_F(NGLineBreakerTest, BoundaryInFirstWord) {
@@ -368,21 +370,21 @@ TEST_F(NGLineBreakerTest, BoundaryInFirstWord) {
<div id=container><span>123</span>456 789</div>
)HTML");
- Vector<NGInlineItemResults> lines;
+ Vector<std::pair<String, unsigned>> lines;
lines = BreakLines(node, LayoutUnit(80));
EXPECT_EQ(2u, lines.size());
- EXPECT_EQ("123456", ToString(lines[0], node));
- EXPECT_EQ("789", ToString(lines[1], node));
+ EXPECT_EQ("123456", lines[0].first);
+ EXPECT_EQ("789", lines[1].first);
lines = BreakLines(node, LayoutUnit(50));
EXPECT_EQ(2u, lines.size());
- EXPECT_EQ("123456", ToString(lines[0], node));
- EXPECT_EQ("789", ToString(lines[1], node));
+ EXPECT_EQ("123456", lines[0].first);
+ EXPECT_EQ("789", lines[1].first);
lines = BreakLines(node, LayoutUnit(20));
EXPECT_EQ(2u, lines.size());
- EXPECT_EQ("123456", ToString(lines[0], node));
- EXPECT_EQ("789", ToString(lines[1], node));
+ EXPECT_EQ("123456", lines[0].first);
+ EXPECT_EQ("789", lines[1].first);
}
struct WhitespaceStateTestData {
@@ -451,7 +453,7 @@ TEST_P(NGWhitespaceStateTest, WhitespaceState) {
R"HTML(</div>
)HTML");
- Vector<NGLineInfo> line_infos = BreakToLineInfo(node, LayoutUnit(50));
+ BreakLines(node, LayoutUnit(50));
EXPECT_EQ(trailing_whitespaces_[0], data.expected);
}
@@ -512,13 +514,11 @@ TEST_P(NGTrailingSpaceWidthTest, TrailingSpaceWidth) {
R"HTML(</div>
)HTML");
- Vector<NGLineInfo> line_infos = BreakToLineInfo(node, LayoutUnit(50));
- const NGLineInfo& line_info = line_infos[0];
- if (line_info.ShouldHangTrailingSpaces()) {
- EXPECT_EQ(line_info.HangWidth(),
- LayoutUnit(10) * data.trailing_space_width);
+ BreakLines(node, LayoutUnit(50), true);
+ if (first_should_hang_trailing_space_) {
+ EXPECT_EQ(first_hang_width_, LayoutUnit(10) * data.trailing_space_width);
} else {
- EXPECT_EQ(line_info.HangWidth(), LayoutUnit());
+ EXPECT_EQ(first_hang_width_, LayoutUnit());
}
}
@@ -535,9 +535,9 @@ TEST_F(NGLineBreakerTest, MinMaxWithTrailingSpaces) {
<div id=container>12345 6789 </div>
)HTML");
- auto size = node.ComputeMinMaxSize(
+ auto size = node.ComputeMinMaxSizes(
WritingMode::kHorizontalTb,
- MinMaxSizeInput(/* percentage_resolution_block_size */ (LayoutUnit())));
+ MinMaxSizesInput(/* percentage_resolution_block_size */ (LayoutUnit())));
EXPECT_EQ(size.min_size, LayoutUnit(60));
EXPECT_EQ(size.max_size, LayoutUnit(110));
}
@@ -559,9 +559,9 @@ TEST_F(NGLineBreakerTest, TableCellWidthCalculationQuirkOutOfFlow) {
GetDocument().SetCompatibilityMode(Document::kQuirksMode);
EXPECT_TRUE(node.GetDocument().InQuirksMode());
- node.ComputeMinMaxSize(
+ node.ComputeMinMaxSizes(
WritingMode::kHorizontalTb,
- MinMaxSizeInput(/* percentage_resolution_block_size */ LayoutUnit()));
+ MinMaxSizesInput(/* percentage_resolution_block_size */ LayoutUnit()));
// Pass if |ComputeMinMaxSize| doesn't hit DCHECK failures.
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc
index 0014fe382c4..0306094c1f4 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc
@@ -14,112 +14,366 @@
namespace blink {
+namespace {
+
+bool IsLeftMostOffset(const ShapeResult& shape_result, unsigned offset) {
+ if (shape_result.Rtl())
+ return offset == shape_result.NumCharacters();
+ return offset == 0;
+}
+
+bool IsRightMostOffset(const ShapeResult& shape_result, unsigned offset) {
+ if (shape_result.Rtl())
+ return offset == 0;
+ return offset == shape_result.NumCharacters();
+}
+
+} // namespace
+
NGLineTruncator::NGLineTruncator(const NGLineInfo& line_info)
: line_style_(&line_info.LineStyle()),
- available_width_(line_info.AvailableWidth()),
+ available_width_(line_info.AvailableWidth() - line_info.TextIndent()),
line_direction_(line_info.BaseDirection()) {}
-LayoutUnit NGLineTruncator::TruncateLine(
- LayoutUnit line_width,
- NGLineBoxFragmentBuilder::ChildList* line_box,
- NGInlineLayoutStateStack* box_states) {
- // Shape the ellipsis and compute its inline size.
+const ComputedStyle& NGLineTruncator::EllipsisStyle() const {
// The ellipsis is styled according to the line style.
// https://drafts.csswg.org/css-ui/#ellipsing-details
- const ComputedStyle* ellipsis_style = line_style_.get();
- const Font& font = ellipsis_style->GetFont();
- const SimpleFontData* font_data = font.PrimaryFont();
- DCHECK(font_data);
- String ellipsis_text =
- font_data && font_data->GlyphForCharacter(kHorizontalEllipsisCharacter)
+ return *line_style_;
+}
+
+void NGLineTruncator::SetupEllipsis() {
+ const Font& font = EllipsisStyle().GetFont();
+ ellipsis_font_data_ = font.PrimaryFont();
+ DCHECK(ellipsis_font_data_);
+ ellipsis_text_ =
+ ellipsis_font_data_ && ellipsis_font_data_->GlyphForCharacter(
+ kHorizontalEllipsisCharacter)
? String(&kHorizontalEllipsisCharacter, 1)
: String(u"...");
- HarfBuzzShaper shaper(ellipsis_text);
- scoped_refptr<ShapeResultView> ellipsis_shape_result =
+ HarfBuzzShaper shaper(ellipsis_text_);
+ ellipsis_shape_result_ =
ShapeResultView::Create(shaper.Shape(&font, line_direction_).get());
- LayoutUnit ellipsis_width = ellipsis_shape_result->SnappedWidth();
+ ellipsis_width_ = ellipsis_shape_result_->SnappedWidth();
+}
+
+LayoutUnit NGLineTruncator::PlaceEllipsisNextTo(
+ NGLineBoxFragmentBuilder::ChildList* line_box,
+ NGLineBoxFragmentBuilder::Child* ellipsized_child) {
+ // Create the ellipsis, associating it with the ellipsized child.
+ DCHECK(ellipsized_child->HasInFlowFragment());
+ LayoutObject* ellipsized_layout_object =
+ ellipsized_child->PhysicalFragment()->GetMutableLayoutObject();
+ DCHECK(ellipsized_layout_object);
+ DCHECK(ellipsized_layout_object->IsInline());
+ DCHECK(ellipsized_layout_object->IsText() ||
+ ellipsized_layout_object->IsAtomicInlineLevel());
+ NGTextFragmentBuilder builder(line_style_->GetWritingMode());
+ builder.SetText(ellipsized_layout_object, ellipsis_text_, &EllipsisStyle(),
+ true /* is_ellipsis_style */,
+ std::move(ellipsis_shape_result_));
+
+ // Now the offset of the ellpisis is determined. Place the ellpisis into the
+ // line box.
+ LayoutUnit ellipsis_inline_offset =
+ IsLtr(line_direction_)
+ ? ellipsized_child->InlineOffset() + ellipsized_child->inline_size
+ : ellipsized_child->InlineOffset() - ellipsis_width_;
+ LayoutUnit ellpisis_ascent;
+ DCHECK(ellipsis_font_data_);
+ if (ellipsis_font_data_) {
+ FontBaseline baseline_type = line_style_->GetFontBaseline();
+ NGLineHeightMetrics ellipsis_metrics(ellipsis_font_data_->GetFontMetrics(),
+ baseline_type);
+ ellpisis_ascent = ellipsis_metrics.ascent;
+ }
+ line_box->AddChild(builder.ToTextFragment(),
+ LogicalOffset{ellipsis_inline_offset, -ellpisis_ascent},
+ ellipsis_width_, 0);
+ return ellipsis_inline_offset;
+}
+
+wtf_size_t NGLineTruncator::AddTruncatedChild(
+ wtf_size_t source_index,
+ bool leave_one_character,
+ LayoutUnit position,
+ TextDirection edge,
+ NGLineBoxFragmentBuilder::ChildList* line_box,
+ NGInlineLayoutStateStack* box_states) {
+ NGLineBoxFragmentBuilder::ChildList& line = *line_box;
+
+ scoped_refptr<ShapeResult> shape_result =
+ line[source_index].fragment->TextShapeResult()->CreateShapeResult();
+ unsigned text_offset = shape_result->OffsetToFit(position, edge);
+ if (IsLtr(edge) ? IsLeftMostOffset(*shape_result, text_offset)
+ : IsRightMostOffset(*shape_result, text_offset)) {
+ if (!leave_one_character)
+ return kDidNotAddChild;
+ text_offset =
+ shape_result->OffsetToFit(shape_result->PositionForOffset(
+ IsRtl(edge) == shape_result->Rtl()
+ ? 1
+ : shape_result->NumCharacters() - 1),
+ edge);
+ }
+
+ const auto& fragment = line[source_index].fragment;
+ const bool keep_start = edge == fragment->ResolvedDirection();
+ scoped_refptr<const NGPhysicalTextFragment> truncated_fragment =
+ keep_start ? fragment->TrimText(fragment->StartOffset(),
+ fragment->StartOffset() + text_offset)
+ : fragment->TrimText(fragment->StartOffset() + text_offset,
+ fragment->EndOffset());
+ wtf_size_t new_index = line.size();
+ line.AddChild();
+ box_states->ChildInserted(new_index);
+ line[new_index] = line[source_index];
+ line[new_index].inline_size = line_style_->IsHorizontalWritingMode()
+ ? truncated_fragment->Size().width
+ : truncated_fragment->Size().height;
+ line[new_index].fragment = std::move(truncated_fragment);
+ return new_index;
+}
+
+LayoutUnit NGLineTruncator::TruncateLine(
+ LayoutUnit line_width,
+ NGLineBoxFragmentBuilder::ChildList* line_box,
+ NGInlineLayoutStateStack* box_states) {
+ // Shape the ellipsis and compute its inline size.
+ SetupEllipsis();
// Loop children from the logical last to the logical first to determine where
// to place the ellipsis. Children maybe truncated or moved as part of the
// process.
- NGLineBoxFragmentBuilder::Child* ellpisized_child = nullptr;
+ NGLineBoxFragmentBuilder::Child* ellipsized_child = nullptr;
scoped_refptr<const NGPhysicalTextFragment> truncated_fragment;
if (IsLtr(line_direction_)) {
NGLineBoxFragmentBuilder::Child* first_child = line_box->FirstInFlowChild();
for (auto it = line_box->rbegin(); it != line_box->rend(); it++) {
auto& child = *it;
- if (EllipsizeChild(line_width, ellipsis_width, &child == first_child,
+ if (EllipsizeChild(line_width, ellipsis_width_, &child == first_child,
&child, &truncated_fragment)) {
- ellpisized_child = &child;
+ ellipsized_child = &child;
break;
}
}
} else {
NGLineBoxFragmentBuilder::Child* first_child = line_box->LastInFlowChild();
for (auto& child : *line_box) {
- if (EllipsizeChild(line_width, ellipsis_width, &child == first_child,
+ if (EllipsizeChild(line_width, ellipsis_width_, &child == first_child,
&child, &truncated_fragment)) {
- ellpisized_child = &child;
+ ellipsized_child = &child;
break;
}
}
}
// Abort if ellipsis could not be placed.
- if (!ellpisized_child)
+ if (!ellipsized_child)
return line_width;
// Truncate the text fragment if needed.
if (truncated_fragment) {
- DCHECK(ellpisized_child->fragment);
+ DCHECK(ellipsized_child->fragment);
// In order to preserve layout information before truncated, hide the
// original fragment and insert a truncated one.
- size_t child_index_to_truncate = ellpisized_child - line_box->begin();
+ size_t child_index_to_truncate = ellipsized_child - line_box->begin();
line_box->InsertChild(child_index_to_truncate + 1);
box_states->ChildInserted(child_index_to_truncate + 1);
NGLineBoxFragmentBuilder::Child* child_to_truncate =
&(*line_box)[child_index_to_truncate];
- ellpisized_child = std::next(child_to_truncate);
- *ellpisized_child = *child_to_truncate;
+ ellipsized_child = std::next(child_to_truncate);
+ *ellipsized_child = *child_to_truncate;
HideChild(child_to_truncate);
LayoutUnit new_inline_size = line_style_->IsHorizontalWritingMode()
? truncated_fragment->Size().width
: truncated_fragment->Size().height;
- DCHECK_LE(new_inline_size, ellpisized_child->inline_size);
+ DCHECK_LE(new_inline_size, ellipsized_child->inline_size);
if (UNLIKELY(IsRtl(line_direction_))) {
- ellpisized_child->offset.inline_offset +=
- ellpisized_child->inline_size - new_inline_size;
+ ellipsized_child->rect.offset.inline_offset +=
+ ellipsized_child->inline_size - new_inline_size;
}
- ellpisized_child->inline_size = new_inline_size;
- ellpisized_child->fragment = std::move(truncated_fragment);
+ ellipsized_child->inline_size = new_inline_size;
+ ellipsized_child->fragment = std::move(truncated_fragment);
}
// Create the ellipsis, associating it with the ellipsized child.
- LayoutObject* ellipsized_layout_object =
- ellpisized_child->PhysicalFragment()->GetMutableLayoutObject();
- DCHECK(ellipsized_layout_object && ellipsized_layout_object->IsInline() &&
- (ellipsized_layout_object->IsText() ||
- ellipsized_layout_object->IsAtomicInlineLevel()));
- NGTextFragmentBuilder builder(line_style_->GetWritingMode());
- builder.SetText(ellipsized_layout_object, ellipsis_text, ellipsis_style,
- true /* is_ellipsis_style */,
- std::move(ellipsis_shape_result));
-
- // Now the offset of the ellpisis is determined. Place the ellpisis into the
- // line box.
LayoutUnit ellipsis_inline_offset =
- IsLtr(line_direction_)
- ? ellpisized_child->offset.inline_offset +
- ellpisized_child->inline_size
- : ellpisized_child->offset.inline_offset - ellipsis_width;
- FontBaseline baseline_type = line_style_->GetFontBaseline();
- NGLineHeightMetrics ellipsis_metrics(font_data->GetFontMetrics(),
- baseline_type);
- line_box->AddChild(
- builder.ToTextFragment(),
- LogicalOffset{ellipsis_inline_offset, -ellipsis_metrics.ascent},
- ellipsis_width, 0);
- return std::max(ellipsis_inline_offset + ellipsis_width, line_width);
+ PlaceEllipsisNextTo(line_box, ellipsized_child);
+ return std::max(ellipsis_inline_offset + ellipsis_width_, line_width);
+}
+
+// This function was designed to work only with <input type=file>.
+// We assume the line box contains:
+// (Optional) children without in-flow fragments
+// Children with in-flow fragments, and
+// (Optional) children without in-flow fragments
+// in this order, and the children with in-flow fragments have no padding,
+// no border, and no margin.
+// Children with IsPlaceholder() can appear anywhere.
+LayoutUnit NGLineTruncator::TruncateLineInTheMiddle(
+ LayoutUnit line_width,
+ NGLineBoxFragmentBuilder::ChildList* line_box,
+ NGInlineLayoutStateStack* box_states) {
+ // Shape the ellipsis and compute its inline size.
+ SetupEllipsis();
+
+ NGLineBoxFragmentBuilder::ChildList& line = *line_box;
+ wtf_size_t initial_index_left = kNotFound;
+ wtf_size_t initial_index_right = kNotFound;
+ for (wtf_size_t i = 0; i < line_box->size(); ++i) {
+ auto& child = line[i];
+ if (!child.fragment && child.IsPlaceholder())
+ continue;
+ if (child.HasOutOfFlowFragment() || !child.fragment ||
+ !child.fragment->TextShapeResult()) {
+ if (initial_index_right != kNotFound)
+ break;
+ continue;
+ }
+ if (initial_index_left == kNotFound)
+ initial_index_left = i;
+ initial_index_right = i;
+ }
+ // There are no truncatable children.
+ if (initial_index_left == kNotFound)
+ return line_width;
+ DCHECK_NE(initial_index_right, kNotFound);
+ DCHECK(line[initial_index_left].HasInFlowFragment());
+ DCHECK(line[initial_index_right].HasInFlowFragment());
+
+ // line[]:
+ // s s s p f f p f f s s
+ // ^ ^
+ // initial_index_left |
+ // initial_index_right
+ // s: child without in-flow fragment
+ // p: placeholder child
+ // f: child with in-flow fragment
+
+ const LayoutUnit static_width_left = line[initial_index_left].InlineOffset();
+ LayoutUnit static_width_right = LayoutUnit(0);
+ for (wtf_size_t i = initial_index_right + 1; i < line.size(); ++i)
+ static_width_right += line[i].inline_size;
+ const LayoutUnit available_width =
+ available_width_ - static_width_left - static_width_right;
+ if (available_width <= ellipsis_width_)
+ return line_width;
+ LayoutUnit available_width_left = (available_width - ellipsis_width_) / 2;
+ LayoutUnit available_width_right = available_width_left;
+
+ // Children for ellipsis and truncated fragments will have index which
+ // is >= new_child_start.
+ const wtf_size_t new_child_start = line.size();
+
+ wtf_size_t index_left = initial_index_left;
+ wtf_size_t index_right = initial_index_right;
+
+ if (IsLtr(line_direction_)) {
+ // Find truncation point at the left, truncate, and add an ellipsis.
+ while (available_width_left >= line[index_left].inline_size)
+ available_width_left -= line[index_left++].inline_size;
+ DCHECK_LE(index_left, index_right);
+ DCHECK(!line[index_left].IsPlaceholder());
+ wtf_size_t new_index = AddTruncatedChild(
+ index_left, index_left == initial_index_left, available_width_left,
+ TextDirection::kLtr, line_box, box_states);
+ if (new_index == kDidNotAddChild) {
+ DCHECK_GT(index_left, initial_index_left);
+ DCHECK_GT(index_left, 0u);
+ wtf_size_t i = index_left;
+ while (!line[--i].HasInFlowFragment())
+ DCHECK(line[i].IsPlaceholder());
+ PlaceEllipsisNextTo(line_box, &line[i]);
+ available_width_right += available_width_left;
+ } else {
+ PlaceEllipsisNextTo(line_box, &line[new_index]);
+ available_width_right +=
+ available_width_left - line[new_index].inline_size;
+ }
+
+ // Find truncation point at the right.
+ while (available_width_right >= line[index_right].inline_size)
+ available_width_right -= line[index_right--].inline_size;
+ LayoutUnit new_modified_right_offset =
+ line[line.size() - 1].InlineOffset() + ellipsis_width_;
+ DCHECK_LE(index_left, index_right);
+ DCHECK(!line[index_right].IsPlaceholder());
+ if (available_width_right > 0) {
+ new_index = AddTruncatedChild(
+ index_right, false,
+ line[index_right].inline_size - available_width_right,
+ TextDirection::kRtl, line_box, box_states);
+ if (new_index != kDidNotAddChild) {
+ line[new_index].rect.offset.inline_offset = new_modified_right_offset;
+ new_modified_right_offset += line[new_index].inline_size;
+ }
+ }
+ // Shift unchanged children at the right of the truncated child.
+ // It's ok to modify existing children's offsets because they are not
+ // web-exposed.
+ LayoutUnit offset_diff = line[index_right].InlineOffset() +
+ line[index_right].inline_size -
+ new_modified_right_offset;
+ for (wtf_size_t i = index_right + 1; i < new_child_start; ++i)
+ line[i].rect.offset.inline_offset -= offset_diff;
+ line_width -= offset_diff;
+
+ } else {
+ // Find truncation point at the right, truncate, and add an ellipsis.
+ while (available_width_right >= line[index_right].inline_size)
+ available_width_right -= line[index_right--].inline_size;
+ DCHECK_LE(index_left, index_right);
+ DCHECK(!line[index_right].IsPlaceholder());
+ wtf_size_t new_index =
+ AddTruncatedChild(index_right, index_right == initial_index_right,
+ line[index_right].inline_size - available_width_right,
+ TextDirection::kRtl, line_box, box_states);
+ if (new_index == kDidNotAddChild) {
+ DCHECK_LT(index_right, initial_index_right);
+ wtf_size_t i = index_right;
+ while (!line[++i].HasInFlowFragment())
+ DCHECK(line[i].IsPlaceholder());
+ PlaceEllipsisNextTo(line_box, &line[i]);
+ available_width_left += available_width_right;
+ } else {
+ line[new_index].rect.offset.inline_offset +=
+ line[index_right].inline_size - line[new_index].inline_size;
+ PlaceEllipsisNextTo(line_box, &line[new_index]);
+ available_width_left +=
+ available_width_right - line[new_index].inline_size;
+ }
+ LayoutUnit ellipsis_offset = line[line.size() - 1].InlineOffset();
+
+ // Find truncation point at the left.
+ while (available_width_left >= line[index_left].inline_size)
+ available_width_left -= line[index_left++].inline_size;
+ DCHECK_LE(index_left, index_right);
+ DCHECK(!line[index_left].IsPlaceholder());
+ if (available_width_left > 0) {
+ new_index = AddTruncatedChild(index_left, false, available_width_left,
+ TextDirection::kLtr, line_box, box_states);
+ if (new_index != kDidNotAddChild) {
+ line[new_index].rect.offset.inline_offset =
+ ellipsis_offset - line[new_index].inline_size;
+ }
+ }
+
+ // Shift unchanged children at the left of the truncated child.
+ // It's ok to modify existing children's offsets because they are not
+ // web-exposed.
+ LayoutUnit offset_diff =
+ line[line.size() - 1].InlineOffset() - line[index_left].InlineOffset();
+ for (wtf_size_t i = index_left; i > 0; --i)
+ line[i - 1].rect.offset.inline_offset += offset_diff;
+ line_width -= offset_diff;
+ }
+ // Hide left/right truncated children and children between them.
+ for (wtf_size_t i = index_left; i <= index_right; ++i) {
+ if (line[i].HasInFlowFragment())
+ HideChild(&line[i]);
+ }
+
+ return line_width;
}
// Hide this child from being painted. Leaves a hidden fragment so that layout
@@ -147,7 +401,7 @@ void NGLineTruncator::HideChild(NGLineBoxFragmentBuilder::Child* child) {
// paddings, because clipping is at the content box but ellipsizing is at
// the padding box. Just move to the max because we don't know paddings,
// and max should do what we need.
- child->offset.inline_offset = LayoutUnit::NearlyMax();
+ child->rect.offset.inline_offset = LayoutUnit::NearlyMax();
return;
}
@@ -182,8 +436,8 @@ bool NGLineTruncator::EllipsizeChild(
// Can't place ellipsis if this child is completely outside of the box.
LayoutUnit child_inline_offset =
IsLtr(line_direction_)
- ? child->offset.inline_offset
- : line_width - (child->offset.inline_offset + child->inline_size);
+ ? child->InlineOffset()
+ : line_width - (child->InlineOffset() + child->inline_size);
LayoutUnit space_for_child = available_width_ - child_inline_offset;
if (space_for_child <= 0) {
// This child is outside of the content box, but we still need to hide it.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h
index 0c507997ad2..c65fa3ce5a4 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h
@@ -33,7 +33,40 @@ class CORE_EXPORT NGLineTruncator final {
NGLineBoxFragmentBuilder::ChildList* line_box,
NGInlineLayoutStateStack* box_states);
+ LayoutUnit TruncateLineInTheMiddle(
+ LayoutUnit line_width,
+ NGLineBoxFragmentBuilder::ChildList* line_box,
+ NGInlineLayoutStateStack* box_states);
+
private:
+ const ComputedStyle& EllipsisStyle() const;
+
+ // Initialize four ellipsis_*_ data members.
+ void SetupEllipsis();
+
+ // Add a child for ellipsis next to |ellipsized_child|.
+ LayoutUnit PlaceEllipsisNextTo(
+ NGLineBoxFragmentBuilder::ChildList* line_box,
+ NGLineBoxFragmentBuilder::Child* ellipsized_child);
+
+ static constexpr wtf_size_t kDidNotAddChild = WTF::kNotFound;
+ // Add a child with truncated text of (*line_box)[source_index].
+ // This function returns the index of the new child.
+ // If the truncated text is empty, kDidNotAddChild is returned.
+ //
+ // |leave_one_character| - Force to leave at least one character regardless of
+ // |position|.
+ // |position| and |edge| - Indicate truncation point and direction.
+ // If |edge| is TextDirection::kLtr, the left side of
+ // |position| will be copied to the new child.
+ // Otherwise, the right side of |position| will be
+ // copied.
+ wtf_size_t AddTruncatedChild(wtf_size_t source_index,
+ bool leave_one_character,
+ LayoutUnit position,
+ TextDirection edge,
+ NGLineBoxFragmentBuilder::ChildList* line_box,
+ NGInlineLayoutStateStack* box_states);
bool EllipsizeChild(
LayoutUnit line_width,
LayoutUnit ellipsis_width,
@@ -50,6 +83,15 @@ class CORE_EXPORT NGLineTruncator final {
scoped_refptr<const ComputedStyle> line_style_;
LayoutUnit available_width_;
TextDirection line_direction_;
+
+ // The following 3 data members are available after SetupEllipsis().
+ const SimpleFontData* ellipsis_font_data_;
+ String ellipsis_text_;
+ LayoutUnit ellipsis_width_;
+
+ // This data member is available between SetupEllipsis() and
+ // PlaceEllipsisNextTo().
+ scoped_refptr<ShapeResultView> ellipsis_shape_result_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
index 9e5ef9dc4aa..a17617b0d31 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc
@@ -123,8 +123,6 @@ void NGOffsetMappingUnit::AssertValid() const {
#endif
}
-NGOffsetMappingUnit::~NGOffsetMappingUnit() = default;
-
const Node* NGOffsetMappingUnit::AssociatedNode() const {
if (const auto* text_fragment = ToLayoutTextFragmentOrNull(layout_object_))
return text_fragment->AssociatedTextNode();
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h
index 40ab1e60d63..13b2eb52bbb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h
@@ -47,7 +47,6 @@ class CORE_EXPORT NGOffsetMappingUnit {
unsigned dom_end,
unsigned text_content_start,
unsigned text_content_end);
- ~NGOffsetMappingUnit();
// Returns associated node for this unit or null if this unit is associated
// to generated content.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc
index 206226f2b87..3e2c8f22e7d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc
@@ -97,7 +97,6 @@ class NGOffsetMappingTest : public NGLayoutTest {
void SetUp() override {
NGLayoutTest::SetUp();
style_ = ComputedStyle::Create();
- style_->GetFont().Update(nullptr);
}
void SetupHtml(const char* id, String html) {
@@ -1496,7 +1495,8 @@ TEST_P(NGOffsetMappingGetterTest, Get) {
// For the purpose of this test, ensure this is laid out by each layout
// engine.
- DCHECK_EQ(layout_block_flow->IsLayoutNGMixin(), GetParam());
+ DCHECK_EQ(layout_block_flow->IsLayoutNGMixin(),
+ RuntimeEnabledFeatures::LayoutNGEnabled());
const NGOffsetMapping* mapping =
NGInlineNode::GetOffsetMapping(layout_block_flow);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
index cab0866ce4c..ac726c4dea4 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc
@@ -6,9 +6,11 @@
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
@@ -37,11 +39,12 @@ NGPhysicalLineBoxFragment::Create(NGLineBoxFragmentBuilder* builder) {
sizeof(NGPhysicalLineBoxFragment) +
builder->children_.size() * sizeof(NGLink),
::WTF::GetStringWithTypeName<NGPhysicalLineBoxFragment>());
- new (data) NGPhysicalLineBoxFragment(builder);
+ new (data) NGPhysicalLineBoxFragment(PassKey(), builder);
return base::AdoptRef(static_cast<NGPhysicalLineBoxFragment*>(data));
}
NGPhysicalLineBoxFragment::NGPhysicalLineBoxFragment(
+ PassKey key,
NGLineBoxFragmentBuilder* builder)
: NGPhysicalContainerFragment(builder,
builder->GetWritingMode(),
@@ -51,48 +54,51 @@ NGPhysicalLineBoxFragment::NGPhysicalLineBoxFragment(
metrics_(builder->metrics_) {
// A line box must have a metrics unless it's an empty line box.
DCHECK(!metrics_.IsEmpty() || IsEmptyLineBox());
- base_direction_ = static_cast<unsigned>(builder->base_direction_);
+ base_or_resolved_direction_ = static_cast<unsigned>(builder->base_direction_);
has_hanging_ = builder->hang_inline_size_ != 0;
has_propagated_descendants_ = has_floating_descendants_for_paint_ ||
HasOutOfFlowPositionedDescendants() ||
builder->unpositioned_list_marker_;
}
-NGLineHeightMetrics NGPhysicalLineBoxFragment::BaselineMetrics(
- FontBaseline) const {
+NGLineHeightMetrics NGPhysicalLineBoxFragment::BaselineMetrics() const {
// TODO(kojii): Computing other baseline types than the used one is not
// implemented yet.
// TODO(kojii): We might need locale/script to look up OpenType BASE table.
return metrics_;
}
+namespace {
+
+// Include the inline-size of the line-box in the overflow.
+inline void AddInlineSizeToOverflow(const PhysicalRect& rect,
+ const WritingMode container_writing_mode,
+ PhysicalRect* overflow) {
+ PhysicalRect inline_rect;
+ inline_rect.offset = rect.offset;
+ if (IsHorizontalWritingMode(container_writing_mode))
+ inline_rect.size.width = rect.size.width;
+ else
+ inline_rect.size.height = rect.size.height;
+ overflow->UniteEvenIfEmpty(inline_rect);
+}
+
+} // namespace
+
PhysicalRect NGPhysicalLineBoxFragment::ScrollableOverflow(
- const LayoutObject* container,
- const ComputedStyle* container_style,
- PhysicalSize container_physical_size) const {
- WritingMode container_writing_mode = container_style->GetWritingMode();
- TextDirection container_direction = container_style->Direction();
+ const NGPhysicalBoxFragment& container,
+ const ComputedStyle& container_style) const {
+ const WritingMode container_writing_mode = container_style.GetWritingMode();
+ const TextDirection container_direction = container_style.Direction();
PhysicalRect overflow;
for (const auto& child : Children()) {
PhysicalRect child_scroll_overflow =
child->ScrollableOverflowForPropagation(container);
child_scroll_overflow.offset += child.Offset();
- // Chop the hanging part from scrollable overflow. Children overflow in
- // inline direction should hang, which should not cause scroll.
- // TODO(kojii): Should move to text fragment to make this more accurate.
if (UNLIKELY(has_hanging_ && !child->IsFloatingOrOutOfFlowPositioned())) {
- if (IsHorizontalWritingMode(container_writing_mode)) {
- if (child_scroll_overflow.offset.left < 0)
- child_scroll_overflow.offset.left = LayoutUnit();
- if (child_scroll_overflow.Right() > Size().width)
- child_scroll_overflow.ShiftRightEdgeTo(Size().width);
- } else {
- if (child_scroll_overflow.offset.top < 0)
- child_scroll_overflow.offset.top = LayoutUnit();
- if (child_scroll_overflow.Bottom() > Size().height)
- child_scroll_overflow.ShiftBottomEdgeTo(Size().height);
- }
+ AdjustScrollableOverflowForHanging(LocalRect(), container_writing_mode,
+ &child_scroll_overflow);
}
// For implementation reasons, text nodes inherit computed style from their
@@ -102,18 +108,35 @@ PhysicalRect NGPhysicalLineBoxFragment::ScrollableOverflow(
if (!child->IsText()) {
child_scroll_overflow.offset +=
ComputeRelativeOffset(child->Style(), container_writing_mode,
- container_direction, container_physical_size);
+ container_direction, container.Size());
}
overflow.Unite(child_scroll_overflow);
}
// Make sure we include the inline-size of the line-box in the overflow.
- PhysicalRect rect;
- if (IsHorizontalWritingMode(container_writing_mode))
- rect.size.width = Size().width;
- else
- rect.size.height = Size().height;
- overflow.UniteEvenIfEmpty(rect);
+ AddInlineSizeToOverflow(LocalRect(), container_writing_mode, &overflow);
+
+ return overflow;
+}
+
+PhysicalRect NGPhysicalLineBoxFragment::ScrollableOverflowForLine(
+ const NGPhysicalBoxFragment& container,
+ const ComputedStyle& container_style,
+ const NGFragmentItem& line,
+ const NGInlineCursor& cursor) const {
+ DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
+ DCHECK_EQ(&line, cursor.CurrentItem());
+ DCHECK_EQ(line.LineBoxFragment(), this);
+
+ PhysicalRect overflow;
+ AddScrollableOverflowForInlineChild(container, container_style, line,
+ has_hanging_, cursor, &overflow);
+
+ // Make sure we include the inline-size of the line-box in the overflow.
+ // Note, the bottom half-leading should not be included. crbug.com/996847
+ const WritingMode container_writing_mode = container_style.GetWritingMode();
+ AddInlineSizeToOverflow(line.RectInContainerBlock(), container_writing_mode,
+ &overflow);
return overflow;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
index 6ee0a0a81fb..044007e1cde 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h
@@ -13,6 +13,7 @@
namespace blink {
+class NGFragmentItem;
class NGLineBoxFragmentBuilder;
class CORE_EXPORT NGPhysicalLineBoxFragment final
@@ -31,6 +32,9 @@ class CORE_EXPORT NGPhysicalLineBoxFragment final
static scoped_refptr<const NGPhysicalLineBoxFragment> Create(
NGLineBoxFragmentBuilder* builder);
+ using PassKey = util::PassKey<NGPhysicalLineBoxFragment>;
+ NGPhysicalLineBoxFragment(PassKey, NGLineBoxFragmentBuilder* builder);
+
~NGPhysicalLineBoxFragment() {
for (const NGLink& child : Children())
child.fragment->Release();
@@ -50,19 +54,22 @@ class CORE_EXPORT NGPhysicalLineBoxFragment final
// This may be different from the direction of the container box when
// first-line style is used, or when 'unicode-bidi: plaintext' is used.
TextDirection BaseDirection() const {
- return static_cast<TextDirection>(base_direction_);
+ return static_cast<TextDirection>(base_or_resolved_direction_);
}
- // Compute baseline for the specified baseline type.
- NGLineHeightMetrics BaselineMetrics(FontBaseline) const;
+ // Compute the baseline metrics for this linebox.
+ NGLineHeightMetrics BaselineMetrics() const;
// Scrollable overflow. including contents, in the local coordinate.
// |ScrollableOverflow| is not precomputed/cached because it cannot be
// computed when LineBox is generated because it needs container dimensions
// to resolve relative position of its children.
- PhysicalRect ScrollableOverflow(const LayoutObject* container,
- const ComputedStyle* container_style,
- PhysicalSize container_physical_size) const;
+ PhysicalRect ScrollableOverflow(const NGPhysicalBoxFragment& container,
+ const ComputedStyle& container_style) const;
+ PhysicalRect ScrollableOverflowForLine(const NGPhysicalBoxFragment& container,
+ const ComputedStyle& container_style,
+ const NGFragmentItem& line,
+ const NGInlineCursor& cursor) const;
// Whether the content soft-wraps to the next line.
bool HasSoftWrapToNextLine() const;
@@ -72,8 +79,6 @@ class CORE_EXPORT NGPhysicalLineBoxFragment final
const LayoutObject* ContainerLayoutObject() const { return layout_object_; }
private:
- NGPhysicalLineBoxFragment(NGLineBoxFragmentBuilder* builder);
-
NGLineHeightMetrics metrics_;
NGLink children_[];
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc
index 834188b7add..a15a5429402 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc
@@ -32,6 +32,7 @@ static_assert(sizeof(NGPhysicalTextFragment) ==
} // anonymous namespace
NGPhysicalTextFragment::NGPhysicalTextFragment(
+ PassKey key,
const NGPhysicalTextFragment& source,
unsigned start_offset,
unsigned end_offset,
@@ -45,25 +46,29 @@ NGPhysicalTextFragment::NGPhysicalTextFragment(
kFragmentText,
source.TextType()),
text_(source.text_),
- start_offset_(start_offset),
- end_offset_(end_offset),
+ text_offset_(start_offset, end_offset),
shape_result_(std::move(shape_result)) {
- DCHECK_GE(start_offset_, source.StartOffset());
- DCHECK_LE(end_offset_, source.EndOffset());
+ DCHECK_GE(text_offset_.start, source.StartOffset());
+ DCHECK_LE(text_offset_.end, source.EndOffset());
DCHECK(shape_result_ || IsFlowControl()) << *this;
- is_generated_text_ = source.is_generated_text_;
+ base_or_resolved_direction_ = source.base_or_resolved_direction_;
+ is_generated_text_or_math_fraction_ =
+ source.is_generated_text_or_math_fraction_;
ink_overflow_computed_ = false;
+ is_first_for_node_ = source.is_first_for_node_;
}
NGPhysicalTextFragment::NGPhysicalTextFragment(NGTextFragmentBuilder* builder)
: NGPhysicalFragment(builder, kFragmentText, builder->text_type_),
text_(builder->text_),
- start_offset_(builder->start_offset_),
- end_offset_(builder->end_offset_),
+ text_offset_({builder->start_offset_, builder->end_offset_}),
shape_result_(std::move(builder->shape_result_)) {
DCHECK(shape_result_ || IsFlowControl()) << *this;
- is_generated_text_ = builder->IsGeneratedText();
+ base_or_resolved_direction_ =
+ static_cast<unsigned>(builder->ResolvedDirection());
+ is_generated_text_or_math_fraction_ = builder->IsGeneratedText();
ink_overflow_computed_ = false;
+ is_first_for_node_ = builder->is_first_for_node_;
}
LayoutUnit NGPhysicalTextFragment::InlinePositionForOffset(
@@ -214,8 +219,9 @@ scoped_refptr<const NGPhysicalTextFragment> NGPhysicalTextFragment::TrimText(
DCHECK_LE(new_end_offset, EndOffset());
scoped_refptr<ShapeResultView> new_shape_result = ShapeResultView::Create(
shape_result_.get(), new_start_offset, new_end_offset);
- return base::AdoptRef(new NGPhysicalTextFragment(
- *this, new_start_offset, new_end_offset, std::move(new_shape_result)));
+ return base::AdoptRef(
+ new NGPhysicalTextFragment(PassKey(), *this, new_start_offset,
+ new_end_offset, std::move(new_shape_result)));
}
unsigned NGPhysicalTextFragment::TextOffsetForPoint(
@@ -263,10 +269,4 @@ UBiDiLevel NGPhysicalTextFragment::BidiLevel() const {
return containing_item->BidiLevel();
}
-TextDirection NGPhysicalTextFragment::ResolvedDirection() const {
- if (TextShapeResult())
- return TextShapeResult()->Direction();
- return DirectionFromLevel(BidiLevel());
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h
index 7d0adc9bfce..dbd1bae97af 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h
@@ -6,7 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_PHYSICAL_TEXT_FRAGMENT_H_
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_end_effect.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h"
#include "third_party/blink/renderer/core/layout/ng/ng_ink_overflow.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
#include "third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h"
@@ -45,10 +45,18 @@ class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
NGPhysicalTextFragment(NGTextFragmentBuilder*);
+ using PassKey = util::PassKey<NGPhysicalTextFragment>;
+ // For use by TrimText only
+ NGPhysicalTextFragment(PassKey,
+ const NGPhysicalTextFragment& source,
+ unsigned start_offset,
+ unsigned end_offset,
+ scoped_refptr<const ShapeResultView> shape_result);
+
NGTextType TextType() const { return static_cast<NGTextType>(sub_type_); }
// Returns true if the text is generated (from, e.g., list marker,
// pseudo-element, ...) instead of from a DOM text node.
- bool IsGeneratedText() const { return is_generated_text_; }
+ bool IsGeneratedText() const { return is_generated_text_or_math_fraction_; }
// True if this is a forced line break.
bool IsLineBreak() const { return TextType() == kForcedLineBreak; }
// True if this is not for painting; i.e., a forced line break, a tabulation,
@@ -63,18 +71,19 @@ class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
bool IsSymbolMarker() const { return TextType() == kSymbolMarker; }
- unsigned TextLength() const { return end_offset_ - start_offset_; }
- StringView Text() const {
- return StringView(text_, start_offset_, TextLength());
- }
const String& TextContent() const { return text_; }
// ShapeResult may be nullptr if |IsFlowControl()|.
const ShapeResultView* TextShapeResult() const { return shape_result_.get(); }
// Start/end offset to the text of the block container.
- unsigned StartOffset() const { return start_offset_; }
- unsigned EndOffset() const { return end_offset_; }
+ const NGTextOffset& TextOffset() const { return text_offset_; }
+ unsigned StartOffset() const { return text_offset_.start; }
+ unsigned EndOffset() const { return text_offset_.end; }
+ unsigned TextLength() const { return text_offset_.Length(); }
+ StringView Text() const {
+ return StringView(text_, text_offset_.start, TextLength());
+ }
WritingMode GetWritingMode() const { return Style().GetWritingMode(); }
bool IsHorizontal() const {
@@ -113,7 +122,9 @@ class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
unsigned TextOffsetForPoint(const PhysicalOffset&) const;
UBiDiLevel BidiLevel() const;
- TextDirection ResolvedDirection() const;
+ TextDirection ResolvedDirection() const {
+ return static_cast<TextDirection>(base_or_resolved_direction_);
+ }
// Compute line-relative coordinates for given offsets, this is not
// flow-relative:
@@ -123,12 +134,6 @@ class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
unsigned end_offset) const;
private:
- // For use by TrimText only
- NGPhysicalTextFragment(const NGPhysicalTextFragment& source,
- unsigned start_offset,
- unsigned end_offset,
- scoped_refptr<const ShapeResultView> shape_result);
-
LayoutUnit InlinePositionForOffset(unsigned offset,
LayoutUnit (*round)(float),
AdjustMidCluster) const;
@@ -140,8 +145,7 @@ class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
const String text_;
// Start and end offset of the parent block text.
- const unsigned start_offset_;
- const unsigned end_offset_;
+ const NGTextOffset text_offset_;
const scoped_refptr<const ShapeResultView> shape_result_;
// Fragments are immutable but allow certain expensive data, specifically ink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc
index 7de65ceb791..ebb2a5abd83 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment_test.cc
@@ -43,6 +43,8 @@ class NGPhysicalTextFragmentTest : public NGLayoutTest {
};
TEST_F(NGPhysicalTextFragmentTest, LocalRect) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
@@ -59,6 +61,8 @@ TEST_F(NGPhysicalTextFragmentTest, LocalRect) {
}
TEST_F(NGPhysicalTextFragmentTest, LocalRectRTL) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
@@ -81,6 +85,8 @@ TEST_F(NGPhysicalTextFragmentTest, LocalRectRTL) {
}
TEST_F(NGPhysicalTextFragmentTest, LocalRectVLR) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
@@ -98,6 +104,8 @@ TEST_F(NGPhysicalTextFragmentTest, LocalRectVLR) {
}
TEST_F(NGPhysicalTextFragmentTest, LocalRectVRL) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
@@ -115,6 +123,8 @@ TEST_F(NGPhysicalTextFragmentTest, LocalRectVRL) {
}
TEST_F(NGPhysicalTextFragmentTest, NormalTextIsNotAnonymousText) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetBodyInnerHTML("<div id=div>text</div>");
auto text_fragments = CollectTextFragmentsInContainer("div");
@@ -125,6 +135,8 @@ TEST_F(NGPhysicalTextFragmentTest, NormalTextIsNotAnonymousText) {
}
TEST_F(NGPhysicalTextFragmentTest, FirstLetterIsNotAnonymousText) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetBodyInnerHTML(
"<style>::first-letter {color:red}</style>"
"<div id=div>text</div>");
@@ -139,6 +151,8 @@ TEST_F(NGPhysicalTextFragmentTest, FirstLetterIsNotAnonymousText) {
}
TEST_F(NGPhysicalTextFragmentTest, BeforeAndAfterAreAnonymousText) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetBodyInnerHTML(
"<style>::before{content:'x'} ::after{content:'x'}</style>"
"<div id=div>text</div>");
@@ -155,6 +169,8 @@ TEST_F(NGPhysicalTextFragmentTest, BeforeAndAfterAreAnonymousText) {
}
TEST_F(NGPhysicalTextFragmentTest, Ellipsis) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
@@ -191,6 +207,8 @@ TEST_F(NGPhysicalTextFragmentTest, Ellipsis) {
}
TEST_F(NGPhysicalTextFragmentTest, ListMarkerIsGeneratedText) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetBodyInnerHTML(
"<ol style='list-style-position:inside'>"
"<li id=list>text</li>"
@@ -206,6 +224,8 @@ TEST_F(NGPhysicalTextFragmentTest, ListMarkerIsGeneratedText) {
}
TEST_F(NGPhysicalTextFragmentTest, SoftHyphen) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
@@ -234,6 +254,8 @@ TEST_F(NGPhysicalTextFragmentTest, SoftHyphen) {
}
TEST_F(NGPhysicalTextFragmentTest, QuotationMarksAreAnonymousText) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
SetBodyInnerHTML("<div id=div><q>text</q></div>");
auto text_fragments = CollectTextFragmentsInContainer("div");
@@ -248,6 +270,8 @@ TEST_F(NGPhysicalTextFragmentTest, QuotationMarksAreAnonymousText) {
}
TEST_F(NGPhysicalTextFragmentTest, TextOffsetForPointForTabulation) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
@@ -270,6 +294,8 @@ TEST_F(NGPhysicalTextFragmentTest, TextOffsetForPointForTabulation) {
}
TEST_F(NGPhysicalTextFragmentTest, TextOffsetForPointForTabulationRtl) {
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())
+ return;
LoadAhem();
SetBodyInnerHTML(R"HTML(
<style>
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_end_effect.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_end_effect.h
deleted file mode 100644
index 0dbc9f84a77..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_end_effect.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2017 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.
-
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_TEXT_END_EFFECT_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_TEXT_END_EFFECT_H_
-
-namespace blink {
-
-// Effects at the end of text fragments.
-enum class NGTextEndEffect {
- kNone,
- kHyphen,
-
- // When adding new values, ensure NGPhysicalTextFragment has enough bits.
-};
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_TEXT_END_EFFECT_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc
index ea7efc7acb4..0b85af665ca 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc
@@ -36,6 +36,7 @@ void NGTextFragmentBuilder::SetItem(
text_ = items_data.text_content;
start_offset_ = item_result->start_offset;
end_offset_ = item_result->end_offset;
+ resolved_direction_ = item_result->item->Direction();
SetStyle(item_result->item->Style(), item_result->item->StyleVariant());
size_ = {item_result->inline_size, line_height};
shape_result_ = std::move(item_result->shape_result);
@@ -56,6 +57,7 @@ void NGTextFragmentBuilder::SetText(
text_ = text;
start_offset_ = shape_result->StartIndex();
end_offset_ = shape_result->EndIndex();
+ resolved_direction_ = shape_result->Direction();
SetStyle(style, is_ellipsis_style ? NGStyleVariant::kEllipsis
: NGStyleVariant::kStandard);
size_ = {shape_result->SnappedWidth(),
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h
index 422fcd3aa3e..3cb38c1af32 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h
@@ -8,7 +8,6 @@
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_end_effect.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -27,6 +26,8 @@ class CORE_EXPORT NGTextFragmentBuilder final : public NGFragmentBuilder {
NGTextFragmentBuilder(const NGPhysicalTextFragment& fragment);
+ TextDirection ResolvedDirection() const { return resolved_direction_; }
+
// NOTE: Takes ownership of the shape result within the item result.
void SetItem(NGPhysicalTextFragment::NGTextType,
const NGInlineItemsData&,
@@ -56,6 +57,9 @@ class CORE_EXPORT NGTextFragmentBuilder final : public NGFragmentBuilder {
NGPhysicalTextFragment::NGTextType text_type_ =
NGPhysicalTextFragment::kNormalText;
+ // Set from |NGInlineItem| by |SetItem()|.
+ TextDirection resolved_direction_ = TextDirection::kLtr;
+
friend class NGPhysicalTextFragment;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h
index e8132013463..0d6c7251095 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_offset.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_TEXT_OFFSET_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_TEXT_OFFSET_H_
+#include "base/logging.h"
#include "third_party/blink/renderer/core/core_export.h"
namespace blink {
@@ -13,10 +14,13 @@ namespace blink {
struct CORE_EXPORT NGTextOffset {
NGTextOffset() = default;
NGTextOffset(unsigned start, unsigned end) : start(start), end(end) {
- DCHECK_GE(end, start);
+ AssertValid();
}
- unsigned Length() const { return end - start; }
+ unsigned Length() const {
+ AssertValid();
+ return end - start;
+ }
void AssertValid() const { DCHECK_GE(end, start); }
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
index eac09620636..ef990b7ce3f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.cc
@@ -72,21 +72,6 @@ void LayoutNGBlockFlowMixin<Base>::ClearNGInlineNodeData() {
ng_inline_node_data_.reset();
}
-// The current fragment from the last layout cycle for this box.
-// When pre-NG layout calls functions of this block flow, fragment and/or
-// LayoutResult are required to compute the result.
-// TODO(kojii): Use the cached result for now, we may need to reconsider as the
-// cache evolves.
-template <typename Base>
-const NGPhysicalBoxFragment* LayoutNGBlockFlowMixin<Base>::CurrentFragment()
- const {
- const NGLayoutResult* cached_layout_result = Base::GetCachedLayoutResult();
- if (!cached_layout_result)
- return nullptr;
-
- return &To<NGPhysicalBoxFragment>(cached_layout_result->PhysicalFragment());
-}
-
template <typename Base>
void LayoutNGBlockFlowMixin<Base>::AddLayoutOverflowFromChildren() {
if (Base::LayoutBlockedByDisplayLock(DisplayLockLifecycleTarget::kChildren))
@@ -104,83 +89,15 @@ void LayoutNGBlockFlowMixin<Base>::AddLayoutOverflowFromChildren() {
template <typename Base>
void LayoutNGBlockFlowMixin<Base>::AddScrollingOverflowFromChildren() {
-
const NGPhysicalBoxFragment* physical_fragment = CurrentFragment();
DCHECK(physical_fragment);
- if (physical_fragment->Children().empty())
- return;
-
- const ComputedStyle& style = Base::StyleRef();
- const WritingMode writing_mode = style.GetWritingMode();
- const TextDirection direction = style.Direction();
- const LayoutUnit border_inline_start = LayoutUnit(style.BorderStartWidth());
- const LayoutUnit border_block_start = LayoutUnit(style.BorderBeforeWidth());
- const PhysicalSize& size = physical_fragment->Size();
-
- // End and under padding are added to scroll overflow of inline children.
- // https://github.com/w3c/csswg-drafts/issues/129
- base::Optional<NGPhysicalBoxStrut> padding_strut;
- if (Base::HasOverflowClip()) {
- padding_strut = NGBoxStrut(LayoutUnit(), Base::PaddingEnd(), LayoutUnit(),
- Base::PaddingUnder())
- .ConvertToPhysical(writing_mode, direction);
- }
-
- // Rectangles not reachable by scroll should not be added to overflow.
- auto IsRectReachableByScroll = [&border_inline_start, &border_block_start,
- &writing_mode, &direction,
- &size](const PhysicalRect& rect) {
- LogicalOffset rect_logical_end =
- rect.offset.ConvertToLogical(writing_mode, direction, size, rect.size) +
- rect.size.ConvertToLogical(writing_mode);
- return (rect_logical_end.inline_offset > border_inline_start &&
- rect_logical_end.block_offset > border_block_start);
- };
-
- bool children_inline = Base::ChildrenInline();
- PhysicalRect children_overflow;
- base::Optional<PhysicalRect> lineboxes_enclosing_rect;
- // Only add overflow for fragments NG has not reflected into Legacy.
- // These fragments are:
- // - inline fragments,
- // - out of flow fragments whose css container is inline box.
- // TODO(layout-dev) Transforms also need to be applied to compute overflow
- // correctly. NG is not yet transform-aware. crbug.com/855965
- for (const auto& child : physical_fragment->Children()) {
- PhysicalRect child_scrollable_overflow;
- if (child->IsFloatingOrOutOfFlowPositioned()) {
- child_scrollable_overflow = child->ScrollableOverflowForPropagation(this);
- child_scrollable_overflow.offset +=
- ComputeRelativeOffset(child->Style(), writing_mode, direction, size);
- } else if (children_inline && child->IsLineBox()) {
- DCHECK(child->IsLineBox());
- child_scrollable_overflow =
- To<NGPhysicalLineBoxFragment>(*child).ScrollableOverflow(this, &style,
- size);
- if (padding_strut) {
- PhysicalRect linebox_rect(child.Offset(), child->Size());
- if (lineboxes_enclosing_rect)
- lineboxes_enclosing_rect->Unite(linebox_rect);
- else
- lineboxes_enclosing_rect = linebox_rect;
- }
- } else {
- continue;
- }
- child_scrollable_overflow.offset += child.Offset();
- // Do not add overflow if fragment is not reachable by scrolling.
- if (IsRectReachableByScroll(child_scrollable_overflow))
- children_overflow.Unite(child_scrollable_overflow);
- }
- if (lineboxes_enclosing_rect) {
- lineboxes_enclosing_rect->Expand(*padding_strut);
- if (IsRectReachableByScroll(*lineboxes_enclosing_rect))
- children_overflow.Unite(*lineboxes_enclosing_rect);
- }
+ PhysicalRect children_overflow =
+ physical_fragment->ScrollableOverflowFromChildren();
// LayoutOverflow takes flipped blocks coordinates, adjust as needed.
+ const ComputedStyle& style = physical_fragment->Style();
LayoutRect children_flipped_overflow =
- children_overflow.ToLayoutFlippedRect(style, size);
+ children_overflow.ToLayoutFlippedRect(style, physical_fragment->Size());
Base::AddLayoutOverflow(children_flipped_overflow);
}
@@ -193,60 +110,44 @@ void LayoutNGBlockFlowMixin<Base>::AddOutlineRects(
To<NGPhysicalBoxFragment>(PaintFragment()->PhysicalFragment())
.AddSelfOutlineRects(additional_offset, include_block_overflows,
&rects);
- } else {
- Base::AddOutlineRects(rects, additional_offset, include_block_overflows);
+ return;
}
-}
-
-template <typename Base>
-bool LayoutNGBlockFlowMixin<
- Base>::PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
- // LayoutNGBlockFlowMixin is in charge of paint invalidation of the first
- // line.
- if (PaintFragment())
- return false;
- if (Base::StyleRef().HasColumnRule())
- return false;
+ if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
+ if (fragment->HasItems()) {
+ fragment->AddSelfOutlineRects(additional_offset, include_block_overflows,
+ &rects);
+ return;
+ }
+ }
- return Base::PaintedOutputOfObjectHasNoEffectRegardlessOfSize();
+ Base::AddOutlineRects(rects, additional_offset, include_block_overflows);
}
// Retrieve NGBaseline from the current fragment.
template <typename Base>
-base::Optional<LayoutUnit> LayoutNGBlockFlowMixin<Base>::FragmentBaseline(
- NGBaselineAlgorithmType type) const {
+base::Optional<LayoutUnit> LayoutNGBlockFlowMixin<Base>::FragmentBaseline()
+ const {
if (Base::ShouldApplyLayoutContainment())
return base::nullopt;
- if (const NGPhysicalFragment* physical_fragment = CurrentFragment()) {
- FontBaseline baseline_type = Base::StyleRef().GetFontBaseline();
- return To<NGPhysicalBoxFragment>(physical_fragment)
- ->Baseline({type, baseline_type});
- }
+ if (const NGPhysicalFragment* physical_fragment = CurrentFragment())
+ return To<NGPhysicalBoxFragment>(physical_fragment)->Baseline();
return base::nullopt;
}
template <typename Base>
LayoutUnit LayoutNGBlockFlowMixin<Base>::FirstLineBoxBaseline() const {
- if (Base::ChildrenInline()) {
- if (base::Optional<LayoutUnit> offset =
- FragmentBaseline(NGBaselineAlgorithmType::kFirstLine)) {
- return *offset;
- }
- }
+ if (base::Optional<LayoutUnit> offset = FragmentBaseline())
+ return *offset;
return Base::FirstLineBoxBaseline();
}
template <typename Base>
LayoutUnit LayoutNGBlockFlowMixin<Base>::InlineBlockBaseline(
LineDirectionMode line_direction) const {
- if (Base::ChildrenInline()) {
- if (base::Optional<LayoutUnit> offset =
- FragmentBaseline(NGBaselineAlgorithmType::kAtomicInline)) {
- return *offset;
- }
- }
+ if (base::Optional<LayoutUnit> offset = FragmentBaseline())
+ return *offset;
return Base::InlineBlockBaseline(line_direction);
}
@@ -300,11 +201,9 @@ void LayoutNGBlockFlowMixin<Base>::Paint(const PaintInfo& paint_info) const {
return;
}
- if (RuntimeEnabledFeatures::LayoutNGFragmentPaintEnabled()) {
- if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
- NGBoxFragmentPainter(*fragment).Paint(paint_info);
- return;
- }
+ if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
+ NGBoxFragmentPainter(*fragment).Paint(paint_info);
+ return;
}
Base::Paint(paint_info);
@@ -317,7 +216,7 @@ bool LayoutNGBlockFlowMixin<Base>::NodeAtPoint(
const PhysicalOffset& accumulated_offset,
HitTestAction action) {
if (const NGPaintFragment* paint_fragment = PaintFragment()) {
- if (!this->IsEffectiveRootScroller()) {
+ if (!Base::IsEffectiveRootScroller()) {
// Check if we need to do anything at all.
// If we have clipping, then we can't have any spillout.
PhysicalRect overflow_box = Base::HasOverflowClip()
@@ -338,7 +237,11 @@ bool LayoutNGBlockFlowMixin<Base>::NodeAtPoint(
if (UNLIKELY(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled())) {
if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
- if (fragment->HasItems()) {
+ if (fragment->HasItems() ||
+ // Check descendants of this fragment because floats may be in the
+ // |NGFragmentItems| of the descendants.
+ (action == kHitTestFloat &&
+ fragment->HasFloatingDescendantsForPaint())) {
return NGBoxFragmentPainter(*fragment).NodeAtPoint(
result, hit_test_location, accumulated_offset, action);
}
@@ -370,15 +273,18 @@ PositionWithAffinity LayoutNGBlockFlowMixin<Base>::PositionForPoint(
if (const PositionWithAffinity position =
paint_fragment->PositionForPoint(point_in_contents))
return position;
- } else if (const NGFragmentItems* items = Base::FragmentItems()) {
- // The given offset is relative to this |LayoutBlockFlow|. Convert to the
- // contents offset.
- PhysicalOffset point_in_contents = point;
- Base::OffsetForContents(point_in_contents);
- NGInlineCursor cursor(*items);
- if (const PositionWithAffinity position =
- cursor.PositionForPoint(point_in_contents))
- return position;
+ } else if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
+ if (const NGFragmentItems* items = fragment->Items()) {
+ // The given offset is relative to this |LayoutBlockFlow|. Convert to the
+ // contents offset.
+ PhysicalOffset point_in_contents = point;
+ Base::OffsetForContents(point_in_contents);
+ NGInlineCursor cursor(*items);
+ if (const PositionWithAffinity position =
+ cursor.PositionForPointInInlineFormattingContext(
+ point_in_contents, *fragment))
+ return position;
+ }
}
return Base::CreatePositionWithAffinity(0);
@@ -402,26 +308,16 @@ void LayoutNGBlockFlowMixin<Base>::UpdateNGBlockLayout() {
LayoutAnalyzer::BlockScope analyzer(*this);
if (Base::IsOutOfFlowPositioned()) {
- this->UpdateOutOfFlowBlockLayout();
+ LayoutNGMixin<Base>::UpdateOutOfFlowBlockLayout();
return;
}
- NGConstraintSpace constraint_space =
- NGConstraintSpace::CreateFromLayoutObject(
- *this, !Base::View()->GetLayoutState()->Next() /* is_layout_root */);
-
- scoped_refptr<const NGLayoutResult> result =
- NGBlockNode(this).Layout(constraint_space);
-
- for (const auto& descendant :
- result->PhysicalFragment().OutOfFlowPositionedDescendants())
- descendant.node.UseLegacyOutOfFlowPositioning();
- this->UpdateMargins(constraint_space);
+ LayoutNGMixin<Base>::UpdateInFlowBlockLayout();
+ UpdateMargins();
}
template <typename Base>
-void LayoutNGBlockFlowMixin<Base>::UpdateMargins(
- const NGConstraintSpace& space) {
+void LayoutNGBlockFlowMixin<Base>::UpdateMargins() {
const LayoutBlock* containing_block = Base::ContainingBlock();
if (!containing_block || !containing_block->IsLayoutBlockFlow())
return;
@@ -434,13 +330,13 @@ void LayoutNGBlockFlowMixin<Base>::UpdateMargins(
const ComputedStyle& cb_style = containing_block->StyleRef();
const auto writing_mode = cb_style.GetWritingMode();
const auto direction = cb_style.Direction();
- LayoutUnit percentage_resolution_size =
- space.PercentageResolutionInlineSizeForParentWritingMode();
- NGBoxStrut margins = ComputePhysicalMargins(style, percentage_resolution_size)
+ LayoutUnit available_logical_width =
+ LayoutBoxUtils::AvailableLogicalWidth(*this, containing_block);
+ NGBoxStrut margins = ComputePhysicalMargins(style, available_logical_width)
.ConvertToLogical(writing_mode, direction);
- ResolveInlineMargins(style, cb_style, space.AvailableSize().inline_size,
+ ResolveInlineMargins(style, cb_style, available_logical_width,
Base::LogicalWidth(), &margins);
- this->SetMargin(margins.ConvertToPhysical(writing_mode, direction));
+ Base::SetMargin(margins.ConvertToPhysical(writing_mode, direction));
}
template class CORE_TEMPLATE_EXPORT LayoutNGBlockFlowMixin<LayoutBlockFlow>;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h
index 6b5d874ce5d..2e808c039bb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h
@@ -60,20 +60,18 @@ class LayoutNGBlockFlowMixin : public LayoutNGMixin<Base> {
void SetPaintFragment(const NGBlockBreakToken*,
scoped_refptr<const NGPhysicalFragment>) final;
+ using LayoutNGMixin<Base>::CurrentFragment;
+
protected:
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
- const NGPhysicalBoxFragment* CurrentFragment() const final;
-
void AddLayoutOverflowFromChildren() final;
void AddOutlineRects(Vector<PhysicalRect>&,
const PhysicalOffset& additional_offset,
NGOutlineType) const final;
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const final;
-
- base::Optional<LayoutUnit> FragmentBaseline(NGBaselineAlgorithmType) const;
+ base::Optional<LayoutUnit> FragmentBaseline() const;
void DirtyLinesFromChangedChild(LayoutObject* child,
MarkingBehavior marking_behavior) final;
@@ -89,7 +87,7 @@ class LayoutNGBlockFlowMixin : public LayoutNGMixin<Base> {
private:
void AddScrollingOverflowFromChildren();
- void UpdateMargins(const NGConstraintSpace& space);
+ void UpdateMargins();
};
// If you edit these export templates, also update templates in
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc
index a39b2b4dee0..907d45bb278 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.cc
@@ -73,17 +73,4 @@ bool LayoutNGFieldset::IsOfType(LayoutObjectType type) const {
return type == kLayoutObjectNGFieldset || LayoutNGBlockFlow::IsOfType(type);
}
-void LayoutNGFieldset::Paint(const PaintInfo& paint_info) const {
- // TODO(crbug.com/988015): This override should not be needed when painting
- // fragment is enabled in parent classes.
- if (!RuntimeEnabledFeatures::LayoutNGFragmentPaintEnabled()) {
- if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
- NGBoxFragmentPainter(*fragment, PaintFragment()).Paint(paint_info);
- return;
- }
- }
-
- LayoutNGBlockFlow::Paint(paint_info);
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h
index 4076cdbc70f..5178d12f26d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_fieldset.h
@@ -21,14 +21,10 @@ class CORE_EXPORT LayoutNGFieldset final : public LayoutNGBlockFlow {
bool CreatesNewFormattingContext() const final { return true; }
- void Paint(const PaintInfo&) const final;
-
protected:
bool IsOfType(LayoutObjectType) const override;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGFieldset, IsLayoutNGFieldset());
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FIELDSET_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc
index dddadee04b5..a74fdfe086d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc
@@ -17,6 +17,21 @@ namespace blink {
LayoutNGFlexibleBox::LayoutNGFlexibleBox(Element* element)
: LayoutNGMixin<LayoutBlock>(element) {}
+bool LayoutNGFlexibleBox::HasTopOverflow() const {
+ if (IsHorizontalWritingMode())
+ return StyleRef().ResolvedIsColumnReverseFlexDirection();
+ return StyleRef().IsLeftToRightDirection() ==
+ StyleRef().ResolvedIsRowReverseFlexDirection();
+}
+
+bool LayoutNGFlexibleBox::HasLeftOverflow() const {
+ if (IsHorizontalWritingMode()) {
+ return StyleRef().IsLeftToRightDirection() ==
+ StyleRef().ResolvedIsRowReverseFlexDirection();
+ }
+ return StyleRef().ResolvedIsColumnReverseFlexDirection();
+}
+
void LayoutNGFlexibleBox::UpdateBlockLayout(bool relayout_children) {
LayoutAnalyzer::BlockScope analyzer(*this);
@@ -25,16 +40,34 @@ void LayoutNGFlexibleBox::UpdateBlockLayout(bool relayout_children) {
return;
}
- NGConstraintSpace constraint_space =
- NGConstraintSpace::CreateFromLayoutObject(
- *this, !View()->GetLayoutState()->Next() /* is_layout_root */);
+ UpdateInFlowBlockLayout();
+}
+
+namespace {
+
+void MergeAnonymousFlexItems(LayoutObject* remove_child) {
+ // When we remove a flex item, and the previous and next siblings of the item
+ // are text nodes wrapped in anonymous flex items, the adjacent text nodes
+ // need to be merged into the same flex item.
+ LayoutObject* prev = remove_child->PreviousSibling();
+ if (!prev || !prev->IsAnonymousBlock())
+ return;
+ LayoutObject* next = remove_child->NextSibling();
+ if (!next || !next->IsAnonymousBlock())
+ return;
+ ToLayoutBoxModelObject(next)->MoveAllChildrenTo(ToLayoutBoxModelObject(prev));
+ To<LayoutBlockFlow>(next)->DeleteLineBoxTree();
+ next->Destroy();
+}
+
+} // namespace
- scoped_refptr<const NGLayoutResult> result =
- NGBlockNode(this).Layout(constraint_space);
+void LayoutNGFlexibleBox::RemoveChild(LayoutObject* child) {
+ if (!DocumentBeingDestroyed() &&
+ !StyleRef().IsDeprecatedFlexboxUsingFlexLayout())
+ MergeAnonymousFlexItems(child);
- for (const auto& descendant :
- result->PhysicalFragment().OutOfFlowPositionedDescendants())
- descendant.node.UseLegacyOutOfFlowPositioning();
+ LayoutBlock::RemoveChild(child);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h
index c4c0fcfd227..f1a361e1b56 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h
@@ -15,6 +15,9 @@ class CORE_EXPORT LayoutNGFlexibleBox : public LayoutNGMixin<LayoutBlock> {
public:
explicit LayoutNGFlexibleBox(Element*);
+ bool HasTopOverflow() const override;
+ bool HasLeftOverflow() const override;
+
void UpdateBlockLayout(bool relayout_children) override;
bool IsFlexibleBoxIncludingDeprecatedAndNG() const final { return true; }
@@ -22,6 +25,8 @@ class CORE_EXPORT LayoutNGFlexibleBox : public LayoutNGMixin<LayoutBlock> {
const char* GetName() const override { return "LayoutNGFlexibleBox"; }
protected:
+ void RemoveChild(LayoutObject*) override;
+
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectNGFlexibleBox ||
LayoutNGMixin<LayoutBlock>::IsOfType(type);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
index bc31a16375c..89ad70133c1 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc
@@ -11,9 +11,11 @@
#include "third_party/blink/renderer/core/layout/ng/layout_box_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
namespace blink {
@@ -30,27 +32,65 @@ template <typename Base>
LayoutNGMixin<Base>::~LayoutNGMixin() = default;
template <typename Base>
+void LayoutNGMixin<Base>::Paint(const PaintInfo& paint_info) const {
+ // Avoid painting dirty objects because descendants maybe already destroyed.
+ if (UNLIKELY(Base::NeedsLayout() &&
+ !Base::LayoutBlockedByDisplayLock(
+ DisplayLockLifecycleTarget::kChildren))) {
+ NOTREACHED();
+ return;
+ }
+
+ if (const NGPhysicalBoxFragment* fragment = CurrentFragment())
+ NGBoxFragmentPainter(*fragment).Paint(paint_info);
+}
+
+template <typename Base>
+bool LayoutNGMixin<Base>::NodeAtPoint(HitTestResult& result,
+ const HitTestLocation& hit_test_location,
+ const PhysicalOffset& accumulated_offset,
+ HitTestAction action) {
+ if (const NGPhysicalBoxFragment* fragment = CurrentFragment()) {
+ DCHECK_EQ(Base::PhysicalFragmentCount(), 1u);
+ return NGBoxFragmentPainter(*fragment).NodeAtPoint(
+ result, hit_test_location, accumulated_offset, action);
+ }
+
+ return false;
+}
+
+// The current fragment from the last layout cycle for this box.
+// When pre-NG layout calls functions of this block flow, fragment and/or
+// LayoutResult are required to compute the result.
+// TODO(kojii): Use the cached result for now, we may need to reconsider as the
+// cache evolves.
+template <typename Base>
+const NGPhysicalBoxFragment* LayoutNGMixin<Base>::CurrentFragment() const {
+ const NGLayoutResult* cached_layout_result = Base::GetCachedLayoutResult();
+ if (!cached_layout_result)
+ return nullptr;
+
+ return &To<NGPhysicalBoxFragment>(cached_layout_result->PhysicalFragment());
+}
+
+template <typename Base>
bool LayoutNGMixin<Base>::IsOfType(LayoutObject::LayoutObjectType type) const {
return type == LayoutObject::kLayoutObjectNGMixin || Base::IsOfType(type);
}
template <typename Base>
-void LayoutNGMixin<Base>::ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const {
+MinMaxSizes LayoutNGMixin<Base>::ComputeIntrinsicLogicalWidths() const {
NGBlockNode node(const_cast<LayoutNGMixin<Base>*>(this));
- if (!node.CanUseNewLayout()) {
- Base::ComputeIntrinsicLogicalWidths(min_logical_width, max_logical_width);
- return;
- }
+ if (!node.CanUseNewLayout())
+ return Base::ComputeIntrinsicLogicalWidths();
LayoutUnit available_logical_height =
LayoutBoxUtils::AvailableLogicalHeight(*this, Base::ContainingBlock());
- MinMaxSizeInput input(available_logical_height);
- // This function returns content-box plus scrollbar.
- input.size_type = NGMinMaxSizeType::kContentBoxSize;
- MinMaxSize sizes =
- node.ComputeMinMaxSize(node.Style().GetWritingMode(), input);
+
+ NGConstraintSpace space = ConstraintSpaceForMinMaxSizes();
+ MinMaxSizes sizes = node.ComputeMinMaxSizes(
+ node.Style().GetWritingMode(), MinMaxSizesInput(available_logical_height),
+ &space);
if (Base::IsTableCell()) {
// If a table cell, or the column that it belongs to, has a specified fixed
@@ -61,14 +101,34 @@ void LayoutNGMixin<Base>::ComputeIntrinsicLogicalWidths(
Length table_cell_width = cell->StyleOrColLogicalWidth();
if (table_cell_width.IsFixed() && table_cell_width.Value() > 0) {
sizes.max_size = std::max(sizes.min_size,
- Base::AdjustContentBoxLogicalWidthForBoxSizing(
+ Base::AdjustBorderBoxLogicalWidthForBoxSizing(
LayoutUnit(table_cell_width.Value())));
}
}
- sizes += LayoutUnit(Base::ScrollbarLogicalWidth());
- min_logical_width = sizes.min_size;
- max_logical_width = sizes.max_size;
+ return sizes;
+}
+
+template <typename Base>
+NGConstraintSpace LayoutNGMixin<Base>::ConstraintSpaceForMinMaxSizes() const {
+ const ComputedStyle& style = Base::StyleRef();
+ const WritingMode writing_mode = style.GetWritingMode();
+
+ NGConstraintSpaceBuilder builder(writing_mode, writing_mode,
+ /* is_new_fc */ true);
+ builder.SetTextDirection(style.Direction());
+ builder.SetAvailableSize(
+ {Base::ContainingBlockLogicalWidthForContent(), kIndefiniteSize});
+
+ // Table cells borders may be collapsed, we can't calculate these directly
+ // from the style.
+ if (Base::IsTableCell()) {
+ builder.SetIsTableCell(true);
+ builder.SetTableCellBorders({Base::BorderStart(), Base::BorderEnd(),
+ Base::BorderBefore(), Base::BorderAfter()});
+ }
+
+ return builder.ToConstraintSpace();
}
template <typename Base>
@@ -79,8 +139,7 @@ void LayoutNGMixin<Base>::UpdateOutOfFlowBlockLayout() {
: Base::ContainingBlock();
const ComputedStyle* container_style = container->Style();
NGConstraintSpace constraint_space =
- NGConstraintSpace::CreateFromLayoutObject(*this,
- false /* is_layout_root */);
+ NGConstraintSpace::CreateFromLayoutObject(*this);
// As this is part of the Legacy->NG bridge, the container_builder is used
// for indicating the resolved size of the OOF-positioned containing-block
@@ -97,7 +156,7 @@ void LayoutNGMixin<Base>::UpdateOutOfFlowBlockLayout() {
container_node.CreatesNewFormattingContext());
NGFragmentGeometry fragment_geometry;
- fragment_geometry.border = ComputeBorders(constraint_space, container_node);
+ fragment_geometry.border = ComputeBorders(constraint_space, *container_style);
fragment_geometry.scrollbar =
ComputeScrollbars(constraint_space, container_node);
fragment_geometry.padding =
@@ -141,8 +200,9 @@ void LayoutNGMixin<Base>::UpdateOutOfFlowBlockLayout() {
NGBlockNode(this), static_position, ToLayoutInlineOrNull(css_container));
base::Optional<LogicalSize> initial_containing_block_fixed_size;
- if (container->IsLayoutView() && !Base::GetDocument().Printing()) {
- if (LocalFrameView* frame_view = ToLayoutView(container)->GetFrameView()) {
+ auto* layout_view = DynamicTo<LayoutView>(container);
+ if (layout_view && !Base::GetDocument().Printing()) {
+ if (LocalFrameView* frame_view = layout_view->GetFrameView()) {
IntSize size =
frame_view->LayoutViewport()->ExcludeScrollbars(frame_view->Size());
PhysicalSize physical_size(size);
@@ -190,6 +250,29 @@ void LayoutNGMixin<Base>::UpdateOutOfFlowBlockLayout() {
Base::SetIsLegacyInitiatedOutOfFlowLayout(true);
}
+template <typename Base>
+scoped_refptr<const NGLayoutResult>
+LayoutNGMixin<Base>::UpdateInFlowBlockLayout() {
+ const auto* previous_result = Base::GetCachedLayoutResult();
+ bool is_layout_root = !Base::View()->GetLayoutState()->Next();
+
+ // If we are a layout root, use the previous space if available. This will
+ // include any stretched sizes if applicable.
+ NGConstraintSpace constraint_space =
+ is_layout_root && previous_result
+ ? previous_result->GetConstraintSpaceForCaching()
+ : NGConstraintSpace::CreateFromLayoutObject(*this);
+
+ scoped_refptr<const NGLayoutResult> result =
+ NGBlockNode(this).Layout(constraint_space);
+
+ for (const auto& descendant :
+ result->PhysicalFragment().OutOfFlowPositionedDescendants())
+ descendant.node.UseLegacyOutOfFlowPositioning();
+
+ return result;
+}
+
template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutBlock>;
template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutBlockFlow>;
template class CORE_TEMPLATE_EXPORT LayoutNGMixin<LayoutProgress>;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
index e75f321437e..a6194724268 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h
@@ -23,16 +23,25 @@ class LayoutNGMixin : public Base {
explicit LayoutNGMixin(Element* element);
~LayoutNGMixin() override;
+ void Paint(const PaintInfo&) const override;
+
+ bool NodeAtPoint(HitTestResult&,
+ const HitTestLocation&,
+ const PhysicalOffset& accumulated_offset,
+ HitTestAction) override;
+
bool IsLayoutNGObject() const final { return true; }
+ const NGPhysicalBoxFragment* CurrentFragment() const final;
+
protected:
bool IsOfType(LayoutObject::LayoutObjectType) const override;
- void ComputeIntrinsicLogicalWidths(
- LayoutUnit& min_logical_width,
- LayoutUnit& max_logical_width) const override;
+ MinMaxSizes ComputeIntrinsicLogicalWidths() const override;
+ NGConstraintSpace ConstraintSpaceForMinMaxSizes() const;
void UpdateOutOfFlowBlockLayout();
+ scoped_refptr<const NGLayoutResult> UpdateInFlowBlockLayout();
};
extern template class CORE_EXTERN_TEMPLATE_EXPORT LayoutNGMixin<LayoutBlock>;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_progress.h b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_progress.h
index 7ad4c0c18d7..86d6850fdd5 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_progress.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_progress.h
@@ -25,8 +25,6 @@ class CORE_EXPORT LayoutNGProgress
bool IsOfType(LayoutObjectType type) const override;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGProgress, IsLayoutNGProgress());
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_PROGRESS_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc
index 5d5418d2916..2a611c31d3a 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc
@@ -57,23 +57,9 @@ void LayoutNGTableCaption::UpdateBlockLayout(bool relayout_children) {
DCHECK(!IsOutOfFlowPositioned()) << "Out of flow captions are blockified.";
- NGConstraintSpace constraint_space =
- NGConstraintSpace::CreateFromLayoutObject(
- *this, !View()->GetLayoutState()->Next() /* is_layout_root */);
-
- scoped_refptr<const NGLayoutResult> result =
- NGBlockNode(this).Layout(constraint_space);
-
- CalculateAndSetMargins(constraint_space, result->PhysicalFragment());
-
- // Tell legacy layout there were abspos descendents we couldn't place. We know
- // we have to pass up to legacy here because this method is legacy's entry
- // point to LayoutNG. If our parent were LayoutNG, it wouldn't have called
- // UpdateBlockLayout, it would have packaged this LayoutObject into
- // NGBlockNode and called Layout on that.
- for (const auto& descendant :
- result->PhysicalFragment().OutOfFlowPositionedDescendants())
- descendant.node.UseLegacyOutOfFlowPositioning();
+ scoped_refptr<const NGLayoutResult> result = UpdateInFlowBlockLayout();
+ CalculateAndSetMargins(result->GetConstraintSpaceForCaching(),
+ result->PhysicalFragment());
// The parent table sometimes changes the caption's position after laying it
// out. So there's no point in setting the fragment's offset here;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc
index da93f774221..87eec6dff43 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc
@@ -22,17 +22,7 @@ void LayoutNGTableCell::UpdateBlockLayout(bool relayout_children) {
LayoutAnalyzer::BlockScope analyzer(*this);
SetOverrideLogicalWidth(LogicalWidth());
-
- NGConstraintSpace constraint_space =
- NGConstraintSpace::CreateFromLayoutObject(
- *this, !View()->GetLayoutState()->Next() /* is_layout_root */);
-
- scoped_refptr<const NGLayoutResult> result =
- NGBlockNode(this).Layout(constraint_space);
-
- for (const auto& descendant :
- result->PhysicalFragment().OutOfFlowPositionedDescendants())
- descendant.node.UseLegacyOutOfFlowPositioning();
+ UpdateInFlowBlockLayout();
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/README.md b/chromium/third_party/blink/renderer/core/layout/ng/list/README.md
index 9dbe472eaac..b8380c16919 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/README.md
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/README.md
@@ -41,7 +41,7 @@ When the content is inline level and therefore generates line boxes:
generates a box tree of:
- LayoutNGListItem
- - LayoutNGListMarker
+ - LayoutNGOutsideListMarker
- LayoutText (1.)
- LayoutText (sample text)
@@ -56,7 +56,7 @@ When the content is block level:
```
- LayoutNGListItem
- - LayoutNGListMarker
+ - LayoutNGOutsideListMarker
- LayoutText (1.)
- LayoutNGBlockFlow (div)
- LayoutText (sample text)
@@ -74,7 +74,7 @@ When the content is mixed:
```
- LayoutNGListItem
- - LayoutNGListMarker
+ - LayoutNGOutsideListMarker
- LayoutText (1.)
- LayoutNGBlockFlow (anonymous)
- LayoutText (inline text)
@@ -134,7 +134,8 @@ and still easy to implement across implementations.
[marker positioning]: https://drafts.csswg.org/css-lists-3/#positioning
[LayoutNGListItem]: layout_ng_list_item.h
-[LayoutNGListMarker]: layout_ng_list_marker.h
+[LayoutNGInsideListMarker]: layout_ng_inside_list_marker.h
+[LayoutNGOutsideListMarker]: layout_ng_outside_list_marker.h
[NGBlockLayoutAlgorithm]: ../ng_block_layout_algorithm.h
[NGInlineItem]: ../inline/ng_inline_item.h
[NGInlineLayoutAlgorithm]: ../inline/ng_inline_layout_algorithm.h
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.cc
index 5cdeb8d9124..626ba03e22b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.cc
@@ -5,20 +5,12 @@
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h"
#include "third_party/blink/renderer/core/layout/layout_text.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
namespace blink {
LayoutNGInsideListMarker::LayoutNGInsideListMarker(Element* element)
: LayoutInline(element) {}
-LayoutNGInsideListMarker* LayoutNGInsideListMarker::CreateAnonymous(
- Document* document) {
- LayoutNGInsideListMarker* object = new LayoutNGInsideListMarker(nullptr);
- object->SetDocumentForAnonymous(document);
- return object;
-}
-
bool LayoutNGInsideListMarker::IsOfType(LayoutObjectType type) const {
return type == kLayoutObjectNGInsideListMarker ||
LayoutInline::IsOfType(type);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h
index 0ce5f756adb..5702a72422c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h
@@ -7,23 +7,24 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
+#include "third_party/blink/renderer/core/layout/ng/list/list_marker.h"
namespace blink {
-class Document;
-
// A LayoutObject subclass for inside-positioned list markers in LayoutNG.
class CORE_EXPORT LayoutNGInsideListMarker final : public LayoutInline {
public:
explicit LayoutNGInsideListMarker(Element*);
- static LayoutNGInsideListMarker* CreateAnonymous(Document*);
const char* GetName() const override { return "LayoutNGInsideListMarker"; }
+ const ListMarker& Marker() const { return list_marker_; }
+ ListMarker& Marker() { return list_marker_; }
+
#if DCHECK_IS_ON()
void AddChild(LayoutObject* new_child, LayoutObject* before_child) override {
- // Anonymous list marker should have at most one child.
- DCHECK(GetNode() || !FirstChild());
+ // List markers with 'content: normal' should have at most one child.
+ DCHECK(!StyleRef().ContentBehavesAsNormal() || !FirstChild());
LayoutInline::AddChild(new_child, before_child);
}
#endif
@@ -31,6 +32,8 @@ class CORE_EXPORT LayoutNGInsideListMarker final : public LayoutInline {
private:
bool IsOfType(LayoutObjectType) const override;
PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
+
+ ListMarker list_marker_;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGInsideListMarker,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc
index 826c41c3da0..c3a6d3f0b9f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.cc
@@ -4,21 +4,12 @@
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
-#include "third_party/blink/renderer/core/layout/layout_image_resource_style_image.h"
-#include "third_party/blink/renderer/core/layout/layout_inline.h"
-#include "third_party/blink/renderer/core/layout/layout_list_marker.h"
-#include "third_party/blink/renderer/core/layout/list_marker_text.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.h"
-#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/list/list_marker.h"
namespace blink {
LayoutNGListItem::LayoutNGListItem(Element* element)
- : LayoutNGBlockFlow(element),
- marker_type_(kStatic),
- is_marker_text_updated_(false) {
+ : LayoutNGBlockFlow(element) {
SetInline(false);
SetConsumesSubtreeChangeNotification();
@@ -29,12 +20,6 @@ bool LayoutNGListItem::IsOfType(LayoutObjectType type) const {
return type == kLayoutObjectNGListItem || LayoutNGBlockFlow::IsOfType(type);
}
-void LayoutNGListItem::WillBeDestroyed() {
- DestroyMarker();
-
- LayoutNGBlockFlow::WillBeDestroyed();
-}
-
void LayoutNGListItem::InsertedIntoTree() {
LayoutNGBlockFlow::InsertedIntoTree();
@@ -51,200 +36,52 @@ void LayoutNGListItem::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) {
LayoutNGBlockFlow::StyleDidChange(diff, old_style);
- UpdateMarker();
+ LayoutObject* marker = Marker();
+ ListMarker* list_marker = ListMarker::Get(marker);
+ if (!list_marker)
+ return;
+
+ list_marker->UpdateMarkerContentIfNeeded(*marker);
if (old_style && (old_style->ListStyleType() != StyleRef().ListStyleType() ||
(StyleRef().ListStyleType() == EListStyleType::kString &&
old_style->ListStyleStringValue() !=
StyleRef().ListStyleStringValue())))
- ListStyleTypeChanged();
-}
-
-// If the value of ListStyleType changed, we need to the marker text has been
-// updated.
-void LayoutNGListItem::ListStyleTypeChanged() {
- if (!is_marker_text_updated_)
- return;
-
- is_marker_text_updated_ = false;
- if (marker_) {
- marker_->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
- layout_invalidation_reason::kListStyleTypeChange);
- }
+ list_marker->ListStyleTypeChanged(*marker);
}
void LayoutNGListItem::OrdinalValueChanged() {
- if (marker_type_ == kOrdinalValue && is_marker_text_updated_) {
- is_marker_text_updated_ = false;
-
- // |marker_| can be a nullptr, for example, in the case of :after list item
- // elements.
- if (marker_) {
- marker_->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
- layout_invalidation_reason::kListValueChange);
- }
- }
+ LayoutObject* marker = Marker();
+ if (ListMarker* list_marker = ListMarker::Get(marker))
+ list_marker->OrdinalValueChanged(*marker);
}
void LayoutNGListItem::SubtreeDidChange() {
- if (!marker_)
- return;
-
- if (ordinal_.NotInListChanged()) {
- UpdateMarker();
- ordinal_.SetNotInListChanged(false);
+ LayoutObject* marker = Marker();
+ ListMarker* list_marker = ListMarker::Get(marker);
+ if (!list_marker)
return;
- }
- // Make sure outside marker is the direct child of ListItem.
- if (!IsInside() && marker_->Parent() != this) {
- marker_->Remove();
- AddChild(marker_, FirstChild());
+ // Make sure an outside marker is a direct child of the list item (not nested
+ // inside an anonymous box), and that a marker originated by a ::before or
+ // ::after precedes the generated contents.
+ if ((marker->IsLayoutNGOutsideListMarker() && marker->Parent() != this) ||
+ (IsPseudoElement() && marker != FirstChild())) {
+ marker->Remove();
+ AddChild(marker, FirstChild());
}
- UpdateMarkerContentIfNeeded();
+ list_marker->UpdateMarkerContentIfNeeded(*marker);
}
void LayoutNGListItem::WillCollectInlines() {
UpdateMarkerTextIfNeeded();
}
-// Returns true if this is 'list-style-position: inside', or should be laid out
-// as 'inside'.
-bool LayoutNGListItem::IsInside() const {
- return ordinal_.NotInList() ||
- StyleRef().ListStylePosition() == EListStylePosition::kInside;
-}
-
-// Destroy the list marker objects if exists.
-void LayoutNGListItem::DestroyMarker() {
- if (marker_) {
- marker_->Destroy();
- marker_ = nullptr;
- }
-}
-
-void LayoutNGListItem::UpdateMarkerText(LayoutText* text) {
- DCHECK(text);
- StringBuilder marker_text_builder;
- marker_type_ = MarkerText(&marker_text_builder, kWithSuffix);
- text->SetTextIfNeeded(marker_text_builder.ToString().ReleaseImpl());
- is_marker_text_updated_ = true;
-}
-
-void LayoutNGListItem::UpdateMarkerText() {
- DCHECK(marker_);
- UpdateMarkerText(ToLayoutText(marker_->SlowFirstChild()));
-}
-
-void LayoutNGListItem::UpdateMarker() {
- const ComputedStyle& style = StyleRef();
- if (style.ListStyleType() == EListStyleType::kNone && !IsMarkerImage()) {
- DestroyMarker();
- marker_type_ = kStatic;
- is_marker_text_updated_ = true;
- return;
- }
-
- // Create a marker box if it does not exist yet.
- Node* list_item = GetNode();
- const ComputedStyle* cached_marker_style =
- list_item->IsPseudoElement()
- ? nullptr
- : ToElement(list_item)->CachedStyleForPseudoElement(kPseudoIdMarker);
- if (cached_marker_style && cached_marker_style->GetContentData()) {
- // Don't create an anonymous layout for the marker, it will be generated
- // by the ::marker pseudo-element.
- DestroyMarker();
- marker_type_ = kStatic;
- is_marker_text_updated_ = true;
- return;
- }
- scoped_refptr<ComputedStyle> marker_style;
- if (cached_marker_style) {
- marker_style = ComputedStyle::Clone(*cached_marker_style);
- } else {
- marker_style = ComputedStyle::Create();
- marker_style->InheritFrom(style);
- marker_style->SetStyleType(kPseudoIdMarker);
- marker_style->SetUnicodeBidi(UnicodeBidi::kIsolate);
- marker_style->SetFontVariantNumericSpacing(
- FontVariantNumeric::kTabularNums);
- }
- if (IsInside()) {
- if (marker_ && !marker_->IsLayoutInline())
- DestroyMarker();
- if (!marker_)
- marker_ = LayoutNGInsideListMarker::CreateAnonymous(&GetDocument());
- marker_style->SetDisplay(EDisplay::kInline);
- auto margins =
- LayoutListMarker::InlineMarginsForInside(style, IsMarkerImage());
- marker_style->SetMarginStart(Length::Fixed(margins.first));
- marker_style->SetMarginEnd(Length::Fixed(margins.second));
- } else {
- if (marker_ && !marker_->IsLayoutBlockFlow())
- DestroyMarker();
- if (!marker_)
- marker_ = LayoutNGListMarker::CreateAnonymous(&GetDocument());
- marker_style->SetDisplay(EDisplay::kInlineBlock);
- // Do not break inside the marker, and honor the trailing spaces.
- marker_style->SetWhiteSpace(EWhiteSpace::kPre);
- // Compute margins for 'outside' during layout, because it requires the
- // layout size of the marker.
- // TODO(kojii): absolute position looks more reasonable, and maybe required
- // in some cases, but this is currently blocked by crbug.com/734554
- // marker_style->SetPosition(EPosition::kAbsolute);
- // marker_->SetPositionState(EPosition::kAbsolute);
- }
- marker_->SetStyle(std::move(marker_style));
-
- UpdateMarkerContentIfNeeded();
-
- LayoutObject* first_child = FirstChild();
- if (first_child != marker_) {
- marker_->Remove();
- AddChild(marker_, FirstChild());
- }
-}
-
-LayoutNGListItem* LayoutNGListItem::FromMarker(const LayoutObject& marker) {
- DCHECK(marker.IsLayoutNGListMarkerIncludingInside());
- for (LayoutObject* parent = marker.Parent(); parent;
- parent = parent->Parent()) {
- if (parent->IsLayoutNGListItem()) {
-#if DCHECK_IS_ON()
- LayoutObject* parent_marker = ToLayoutNGListItem(parent)->Marker();
- if (parent_marker) {
- DCHECK(!marker.GetNode());
- DCHECK_EQ(ToLayoutNGListItem(parent)->Marker(), &marker);
- } else {
- DCHECK(marker.GetNode()->IsMarkerPseudoElement());
- DCHECK_EQ(marker.GetNode()->parentElement()->GetLayoutBox(), parent);
- }
-#endif
- return ToLayoutNGListItem(parent);
- }
- // These DCHECKs are not critical but to ensure we cover all cases we know.
- DCHECK(parent->IsAnonymous());
- DCHECK(parent->IsLayoutBlockFlow() || parent->IsLayoutFlowThread());
- }
- return nullptr;
-}
-
-LayoutNGListItem* LayoutNGListItem::FromMarkerOrMarkerContent(
- const LayoutObject& object) {
- DCHECK(object.IsAnonymous());
-
- if (object.IsLayoutNGListMarkerIncludingInside())
- return FromMarker(object);
-
- // Check if this is a marker content.
- if (const LayoutObject* parent = object.Parent()) {
- if (parent->IsLayoutNGListMarkerIncludingInside())
- return FromMarker(*parent);
- }
-
- return nullptr;
+void LayoutNGListItem::UpdateMarkerTextIfNeeded() {
+ LayoutObject* marker = Marker();
+ if (ListMarker* list_marker = ListMarker::Get(marker))
+ list_marker->UpdateMarkerTextIfNeeded(*marker);
}
int LayoutNGListItem::Value() const {
@@ -252,190 +89,16 @@ int LayoutNGListItem::Value() const {
return ordinal_.Value(*GetNode());
}
-LayoutNGListItem::MarkerType LayoutNGListItem::MarkerText(
- StringBuilder* text,
- MarkerTextFormat format) const {
- if (IsMarkerImage()) {
- if (format == kWithSuffix)
- text->Append(' ');
- return kStatic;
- }
-
- const ComputedStyle& style = StyleRef();
- switch (style.ListStyleType()) {
- case EListStyleType::kNone:
- return kStatic;
- case EListStyleType::kString: {
- text->Append(style.ListStyleStringValue());
- return kStatic;
- }
- case EListStyleType::kDisc:
- case EListStyleType::kCircle:
- case EListStyleType::kSquare:
- // value is ignored for these types
- text->Append(list_marker_text::GetText(style.ListStyleType(), 0));
- if (format == kWithSuffix)
- text->Append(' ');
- return kSymbolValue;
- case EListStyleType::kArabicIndic:
- case EListStyleType::kArmenian:
- case EListStyleType::kBengali:
- case EListStyleType::kCambodian:
- case EListStyleType::kCjkIdeographic:
- case EListStyleType::kCjkEarthlyBranch:
- case EListStyleType::kCjkHeavenlyStem:
- case EListStyleType::kDecimalLeadingZero:
- case EListStyleType::kDecimal:
- case EListStyleType::kDevanagari:
- case EListStyleType::kEthiopicHalehame:
- case EListStyleType::kEthiopicHalehameAm:
- case EListStyleType::kEthiopicHalehameTiEr:
- case EListStyleType::kEthiopicHalehameTiEt:
- case EListStyleType::kGeorgian:
- case EListStyleType::kGujarati:
- case EListStyleType::kGurmukhi:
- case EListStyleType::kHangul:
- case EListStyleType::kHangulConsonant:
- case EListStyleType::kHebrew:
- case EListStyleType::kHiragana:
- case EListStyleType::kHiraganaIroha:
- case EListStyleType::kKannada:
- case EListStyleType::kKatakana:
- case EListStyleType::kKatakanaIroha:
- case EListStyleType::kKhmer:
- case EListStyleType::kKoreanHangulFormal:
- case EListStyleType::kKoreanHanjaFormal:
- case EListStyleType::kKoreanHanjaInformal:
- case EListStyleType::kLao:
- case EListStyleType::kLowerAlpha:
- case EListStyleType::kLowerArmenian:
- case EListStyleType::kLowerGreek:
- case EListStyleType::kLowerLatin:
- case EListStyleType::kLowerRoman:
- case EListStyleType::kMalayalam:
- case EListStyleType::kMongolian:
- case EListStyleType::kMyanmar:
- case EListStyleType::kOriya:
- case EListStyleType::kPersian:
- case EListStyleType::kSimpChineseFormal:
- case EListStyleType::kSimpChineseInformal:
- case EListStyleType::kTelugu:
- case EListStyleType::kThai:
- case EListStyleType::kTibetan:
- case EListStyleType::kTradChineseFormal:
- case EListStyleType::kTradChineseInformal:
- case EListStyleType::kUpperAlpha:
- case EListStyleType::kUpperArmenian:
- case EListStyleType::kUpperLatin:
- case EListStyleType::kUpperRoman:
- case EListStyleType::kUrdu: {
- int value = Value();
- text->Append(list_marker_text::GetText(style.ListStyleType(), value));
- if (format == kWithSuffix) {
- text->Append(list_marker_text::Suffix(style.ListStyleType(), value));
- text->Append(' ');
- }
- return kOrdinalValue;
- }
- }
- NOTREACHED();
- return kStatic;
-}
-
-String LayoutNGListItem::MarkerTextWithSuffix() const {
- StringBuilder text;
- MarkerText(&text, kWithSuffix);
- return text.ToString();
-}
-
-String LayoutNGListItem::MarkerTextWithoutSuffix() const {
- StringBuilder text;
- MarkerText(&text, kWithoutSuffix);
- return text.ToString();
-}
-
-String LayoutNGListItem::TextAlternative(const LayoutObject& marker) {
- // For accessibility, return the marker string in the logical order even in
- // RTL, reflecting speech order.
- if (LayoutNGListItem* list_item = FromMarker(marker))
- return list_item->MarkerTextWithSuffix();
- return g_empty_string;
-}
-
-void LayoutNGListItem::UpdateMarkerContentIfNeeded() {
- DCHECK(marker_);
-
- LayoutObject* child = marker_->SlowFirstChild();
- // There should be at most one child.
- DCHECK(!child || !child->SlowFirstChild());
- if (IsMarkerImage()) {
- StyleImage* list_style_image = StyleRef().ListStyleImage();
- if (child) {
- // If the url of `list-style-image` changed, create a new LayoutImage.
- if (!child->IsLayoutImage() ||
- ToLayoutImage(child)->ImageResource()->ImagePtr() !=
- list_style_image->Data()) {
- child->Destroy();
- child = nullptr;
- }
- }
- if (!child) {
- LayoutNGListMarkerImage* image =
- LayoutNGListMarkerImage::CreateAnonymous(&GetDocument());
- scoped_refptr<ComputedStyle> image_style =
- ComputedStyle::CreateAnonymousStyleWithDisplay(marker_->StyleRef(),
- EDisplay::kInline);
- image->SetStyle(image_style);
- image->SetImageResource(
- MakeGarbageCollected<LayoutImageResourceStyleImage>(
- list_style_image));
- image->SetIsGeneratedContent();
- marker_->AddChild(image);
- }
- } else {
- // Create a LayoutText in it.
- LayoutText* text = nullptr;
- // |text_style| should be as same as style propagated in
- // |LayoutObject::PropagateStyleToAnonymousChildren()| to avoid unexpected
- // full layout due by style difference. See http://crbug.com/980399
- scoped_refptr<ComputedStyle> text_style =
- ComputedStyle::CreateAnonymousStyleWithDisplay(
- marker_->StyleRef(), marker_->StyleRef().Display());
- if (child) {
- if (child->IsText()) {
- text = ToLayoutText(child);
- text->SetStyle(text_style);
- } else {
- child->Destroy();
- child = nullptr;
- }
- }
- if (!child) {
- text = LayoutText::CreateEmptyAnonymous(GetDocument(), text_style,
- LegacyLayout::kAuto);
- marker_->AddChild(text);
- is_marker_text_updated_ = false;
- }
- }
-}
-
-LayoutObject* LayoutNGListItem::SymbolMarkerLayoutText() const {
- if (marker_type_ != kSymbolValue)
- return nullptr;
- DCHECK(marker_);
- return marker_->SlowFirstChild();
-}
-
const LayoutObject* LayoutNGListItem::FindSymbolMarkerLayoutText(
const LayoutObject* object) {
if (!object)
return nullptr;
- if (object->IsLayoutNGListItem())
- return ToLayoutNGListItem(object)->SymbolMarkerLayoutText();
+ if (const ListMarker* list_marker = ListMarker::Get(object))
+ return list_marker->SymbolMarkerLayoutText(*object);
- if (object->IsLayoutNGListMarker())
- return ToLayoutNGListMarker(object)->SymbolMarkerLayoutText();
+ if (object->IsLayoutNGListItem())
+ return FindSymbolMarkerLayoutText(ToLayoutNGListItem(object)->Marker());
if (object->IsAnonymousBlock())
return FindSymbolMarkerLayoutText(object->Parent());
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h
index d6fd7b52ee1..c236130315a 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h
@@ -19,62 +19,30 @@ class CORE_EXPORT LayoutNGListItem final : public LayoutNGBlockFlow {
ListItemOrdinal& Ordinal() { return ordinal_; }
int Value() const;
- String MarkerTextWithSuffix() const;
- String MarkerTextWithoutSuffix() const;
- // Marker text with suffix, e.g. "1. ", for use in accessibility.
- static String TextAlternative(const LayoutObject& marker);
-
- LayoutObject* Marker() const { return marker_; }
- bool IsMarkerImage() const {
- return StyleRef().ListStyleImage() &&
- !StyleRef().ListStyleImage()->ErrorOccurred();
+ LayoutObject* Marker() const {
+ Element* list_item = To<Element>(GetNode());
+ return list_item->PseudoElementLayoutObject(kPseudoIdMarker);
}
- void UpdateMarkerTextIfNeeded() {
- if (marker_ && !is_marker_text_updated_ && !IsMarkerImage())
- UpdateMarkerText();
- }
- void UpdateMarkerContentIfNeeded();
+ void UpdateMarkerTextIfNeeded();
void OrdinalValueChanged();
void WillCollectInlines() override;
- LayoutObject* SymbolMarkerLayoutText() const;
static const LayoutObject* FindSymbolMarkerLayoutText(const LayoutObject*);
- // Find the LayoutNGListItem from a marker.
- static LayoutNGListItem* FromMarker(const LayoutObject& marker);
- static LayoutNGListItem* FromMarkerOrMarkerContent(const LayoutObject&);
-
const char* GetName() const override { return "LayoutNGListItem"; }
private:
bool IsOfType(LayoutObjectType) const override;
- void WillBeDestroyed() override;
void InsertedIntoTree() override;
void WillBeRemovedFromTree() override;
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
void SubtreeDidChange() final;
- bool IsInside() const;
-
- enum MarkerTextFormat { kWithSuffix, kWithoutSuffix };
- enum MarkerType { kStatic, kOrdinalValue, kSymbolValue };
- MarkerType MarkerText(StringBuilder*, MarkerTextFormat) const;
- void UpdateMarkerText();
- void UpdateMarkerText(LayoutText*);
- void UpdateMarker();
- void DestroyMarker();
-
- void ListStyleTypeChanged();
-
ListItemOrdinal ordinal_;
- LayoutObject* marker_ = nullptr;
-
- unsigned marker_type_ : 2; // MarkerType
- unsigned is_marker_text_updated_ : 1;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGListItem, IsLayoutNGListItem());
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.cc
deleted file mode 100644
index a477149ad5d..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.cc
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright 2017 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/ng/list/layout_ng_list_marker.h"
-
-#include "third_party/blink/renderer/core/layout/layout_text.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
-
-namespace blink {
-
-LayoutNGListMarker::LayoutNGListMarker(Element* element)
- : LayoutNGBlockFlowMixin<LayoutBlockFlow>(element) {}
-
-LayoutNGListMarker* LayoutNGListMarker::CreateAnonymous(Document* document) {
- LayoutNGListMarker* object = new LayoutNGListMarker(nullptr);
- object->SetDocumentForAnonymous(document);
- return object;
-}
-
-bool LayoutNGListMarker::IsOfType(LayoutObjectType type) const {
- return type == kLayoutObjectNGListMarker ||
- LayoutNGMixin<LayoutBlockFlow>::IsOfType(type);
-}
-
-void LayoutNGListMarker::WillCollectInlines() {
- if (LayoutNGListItem* list_item = LayoutNGListItem::FromMarker(*this))
- list_item->UpdateMarkerTextIfNeeded();
-}
-
-bool LayoutNGListMarker::IsContentImage() const {
- if (LayoutNGListItem* list_item = LayoutNGListItem::FromMarker(*this))
- return list_item->IsMarkerImage();
- return false;
-}
-
-LayoutObject* LayoutNGListMarker::SymbolMarkerLayoutText() const {
- if (LayoutNGListItem* list_item = LayoutNGListItem::FromMarker(*this))
- return list_item->SymbolMarkerLayoutText();
- return nullptr;
-}
-
-bool LayoutNGListMarker::NeedsOccupyWholeLine() const {
- if (!GetDocument().InQuirksMode())
- return false;
-
- LayoutObject* next_sibling = NextSibling();
- if (next_sibling && next_sibling->GetNode() &&
- (IsA<HTMLUListElement>(*next_sibling->GetNode()) ||
- IsA<HTMLOListElement>(*next_sibling->GetNode())))
- return true;
-
- return false;
-}
-
-PositionWithAffinity LayoutNGListMarker::PositionForPoint(
- const PhysicalOffset&) const {
- return CreatePositionWithAffinity(0);
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.cc b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.cc
index 65a6f555531..0ff22412114 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.cc
@@ -3,7 +3,9 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.h"
+
#include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
#include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
namespace blink {
@@ -22,21 +24,6 @@ bool LayoutNGListMarkerImage::IsOfType(LayoutObjectType type) const {
return type == kLayoutObjectNGListMarkerImage || LayoutImage::IsOfType(type);
}
-Node* LayoutNGListMarkerImage::NodeForHitTest() const {
- // In LayoutNG tree, image list marker is structured like this:
- // <li> (LayoutListItem)
- // <anonymous block> (LayoutNGListMarker or LayoutNGInsideListMarker)
- // <anonymous img> (LayoutNGListMarkerImage)
- // Hit testing should return the list-item node.
- DCHECK(!GetNode());
- for (const LayoutObject* parent = Parent(); parent;
- parent = parent->Parent()) {
- if (Node* node = parent->GetNode())
- return node;
- }
- return nullptr;
-}
-
// Because ImageResource() is always LayoutImageResourceStyleImage. So we could
// use StyleImage::ImageSize to determine the concrete object size with
// default object size(ascent/2 x ascent/2).
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.h b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.h
index 6ebae9a91d7..86bdb5ec592 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.h
@@ -19,8 +19,6 @@ class CORE_EXPORT LayoutNGListMarkerImage final : public LayoutImage {
bool IsLayoutNGObject() const override { return true; }
- Node* NodeForHitTest() const final;
-
private:
bool IsOfType(LayoutObjectType) const override;
@@ -28,9 +26,6 @@ class CORE_EXPORT LayoutNGListMarkerImage final : public LayoutImage {
void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const final;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGListMarkerImage,
- IsLayoutNGListMarkerImage());
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LIST_LAYOUT_NG_LIST_MARKER_IMAGE_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc
new file mode 100644
index 00000000000..4507904c341
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.cc
@@ -0,0 +1,41 @@
+// Copyright 2017 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/ng/list/layout_ng_outside_list_marker.h"
+
+#include "third_party/blink/renderer/core/layout/layout_text.h"
+
+namespace blink {
+
+LayoutNGOutsideListMarker::LayoutNGOutsideListMarker(Element* element)
+ : LayoutNGBlockFlowMixin<LayoutBlockFlow>(element) {}
+
+bool LayoutNGOutsideListMarker::IsOfType(LayoutObjectType type) const {
+ return type == kLayoutObjectNGOutsideListMarker ||
+ LayoutNGMixin<LayoutBlockFlow>::IsOfType(type);
+}
+
+void LayoutNGOutsideListMarker::WillCollectInlines() {
+ list_marker_.UpdateMarkerTextIfNeeded(*this);
+}
+
+bool LayoutNGOutsideListMarker::NeedsOccupyWholeLine() const {
+ if (!GetDocument().InQuirksMode())
+ return false;
+
+ LayoutObject* next_sibling = NextSibling();
+ if (next_sibling && next_sibling->GetNode() &&
+ (IsA<HTMLUListElement>(*next_sibling->GetNode()) ||
+ IsA<HTMLOListElement>(*next_sibling->GetNode())))
+ return true;
+
+ return false;
+}
+
+PositionWithAffinity LayoutNGOutsideListMarker::PositionForPoint(
+ const PhysicalOffset&) const {
+ return CreatePositionWithAffinity(0);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h
index d317122a3a8..3b30f46349b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h
@@ -2,41 +2,41 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LIST_LAYOUT_NG_LIST_MARKER_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LIST_LAYOUT_NG_LIST_MARKER_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LIST_LAYOUT_NG_OUTSIDE_LIST_MARKER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LIST_LAYOUT_NG_OUTSIDE_LIST_MARKER_H_
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow_mixin.h"
+#include "third_party/blink/renderer/core/layout/ng/list/list_marker.h"
namespace blink {
-class Document;
-
// A LayoutObject subclass for outside-positioned list markers in LayoutNG.
-class CORE_EXPORT LayoutNGListMarker final
+class CORE_EXPORT LayoutNGOutsideListMarker final
: public LayoutNGBlockFlowMixin<LayoutBlockFlow> {
public:
- explicit LayoutNGListMarker(Element*);
- static LayoutNGListMarker* CreateAnonymous(Document*);
+ explicit LayoutNGOutsideListMarker(Element*);
void WillCollectInlines() override;
- bool IsContentImage() const;
-
- LayoutObject* SymbolMarkerLayoutText() const;
-
- const char* GetName() const override { return "LayoutNGListMarker"; }
+ const char* GetName() const override { return "LayoutNGOutsideListMarker"; }
bool NeedsOccupyWholeLine() const;
+ const ListMarker& Marker() const { return list_marker_; }
+ ListMarker& Marker() { return list_marker_; }
+
private:
bool IsOfType(LayoutObjectType) const override;
PositionWithAffinity PositionForPoint(const PhysicalOffset&) const override;
+
+ ListMarker list_marker_;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGListMarker, IsLayoutNGListMarker());
+DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGOutsideListMarker,
+ IsLayoutNGOutsideListMarker());
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LIST_LAYOUT_NG_LIST_MARKER_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LIST_LAYOUT_NG_OUTSIDE_LIST_MARKER_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/list_marker.cc b/chromium/third_party/blink/renderer/core/layout/ng/list/list_marker.cc
new file mode 100644
index 00000000000..b2533d42d7a
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/list_marker.cc
@@ -0,0 +1,256 @@
+// Copyright 2020 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/ng/list/list_marker.h"
+
+#include "third_party/blink/renderer/core/layout/layout_image_resource_style_image.h"
+#include "third_party/blink/renderer/core/layout/list_marker_text.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_inside_list_marker.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h"
+
+namespace blink {
+
+ListMarker::ListMarker() : marker_text_type_(kNotText) {}
+
+const ListMarker* ListMarker::Get(const LayoutObject* object) {
+ if (!object)
+ return nullptr;
+ if (object->IsLayoutNGOutsideListMarker())
+ return &ToLayoutNGOutsideListMarker(object)->Marker();
+ if (object->IsLayoutNGInsideListMarker())
+ return &ToLayoutNGInsideListMarker(object)->Marker();
+ return nullptr;
+}
+
+ListMarker* ListMarker::Get(LayoutObject* object) {
+ return const_cast<ListMarker*>(
+ ListMarker::Get(static_cast<const LayoutObject*>(object)));
+}
+
+// If the value of ListStyleType changed, we need to the marker text has been
+// updated.
+void ListMarker::ListStyleTypeChanged(LayoutObject& marker) {
+ if (marker_text_type_ == kNotText || marker_text_type_ == kUnresolved)
+ return;
+
+ marker_text_type_ = kUnresolved;
+ marker.SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
+ layout_invalidation_reason::kListStyleTypeChange);
+}
+
+void ListMarker::OrdinalValueChanged(LayoutObject& marker) {
+ if (marker_text_type_ == kOrdinalValue) {
+ marker_text_type_ = kUnresolved;
+ marker.SetNeedsLayoutAndIntrinsicWidthsRecalcAndFullPaintInvalidation(
+ layout_invalidation_reason::kListValueChange);
+ }
+}
+
+void ListMarker::UpdateMarkerText(LayoutObject& marker, LayoutText* text) {
+ DCHECK(text);
+ DCHECK_EQ(marker_text_type_, kUnresolved);
+ StringBuilder marker_text_builder;
+ marker_text_type_ = MarkerText(marker, &marker_text_builder, kWithSuffix);
+ text->SetTextIfNeeded(marker_text_builder.ToString().ReleaseImpl());
+ DCHECK_NE(marker_text_type_, kNotText);
+ DCHECK_NE(marker_text_type_, kUnresolved);
+}
+
+void ListMarker::UpdateMarkerText(LayoutObject& marker) {
+ UpdateMarkerText(marker, ToLayoutText(marker.SlowFirstChild()));
+}
+
+LayoutNGListItem* ListMarker::ListItem(const LayoutObject& marker) {
+ return ToLayoutNGListItem(marker.GetNode()->parentNode()->GetLayoutObject());
+}
+
+ListMarker::MarkerTextType ListMarker::MarkerText(
+ const LayoutObject& marker,
+ StringBuilder* text,
+ MarkerTextFormat format) const {
+ if (IsMarkerImage(marker)) {
+ if (format == kWithSuffix)
+ text->Append(' ');
+ return kNotText;
+ }
+
+ LayoutNGListItem* list_item = ListItem(marker);
+ const ComputedStyle& style = list_item->StyleRef();
+ switch (style.ListStyleType()) {
+ case EListStyleType::kNone:
+ return kNotText;
+ case EListStyleType::kString: {
+ text->Append(style.ListStyleStringValue());
+ return kStatic;
+ }
+ case EListStyleType::kDisc:
+ case EListStyleType::kCircle:
+ case EListStyleType::kSquare:
+ // value is ignored for these types
+ text->Append(list_marker_text::GetText(style.ListStyleType(), 0));
+ if (format == kWithSuffix)
+ text->Append(' ');
+ return kSymbolValue;
+ case EListStyleType::kArabicIndic:
+ case EListStyleType::kArmenian:
+ case EListStyleType::kBengali:
+ case EListStyleType::kCambodian:
+ case EListStyleType::kCjkIdeographic:
+ case EListStyleType::kCjkEarthlyBranch:
+ case EListStyleType::kCjkHeavenlyStem:
+ case EListStyleType::kDecimalLeadingZero:
+ case EListStyleType::kDecimal:
+ case EListStyleType::kDevanagari:
+ case EListStyleType::kEthiopicHalehame:
+ case EListStyleType::kEthiopicHalehameAm:
+ case EListStyleType::kEthiopicHalehameTiEr:
+ case EListStyleType::kEthiopicHalehameTiEt:
+ case EListStyleType::kGeorgian:
+ case EListStyleType::kGujarati:
+ case EListStyleType::kGurmukhi:
+ case EListStyleType::kHangul:
+ case EListStyleType::kHangulConsonant:
+ case EListStyleType::kHebrew:
+ case EListStyleType::kHiragana:
+ case EListStyleType::kHiraganaIroha:
+ case EListStyleType::kKannada:
+ case EListStyleType::kKatakana:
+ case EListStyleType::kKatakanaIroha:
+ case EListStyleType::kKhmer:
+ case EListStyleType::kKoreanHangulFormal:
+ case EListStyleType::kKoreanHanjaFormal:
+ case EListStyleType::kKoreanHanjaInformal:
+ case EListStyleType::kLao:
+ case EListStyleType::kLowerAlpha:
+ case EListStyleType::kLowerArmenian:
+ case EListStyleType::kLowerGreek:
+ case EListStyleType::kLowerLatin:
+ case EListStyleType::kLowerRoman:
+ case EListStyleType::kMalayalam:
+ case EListStyleType::kMongolian:
+ case EListStyleType::kMyanmar:
+ case EListStyleType::kOriya:
+ case EListStyleType::kPersian:
+ case EListStyleType::kSimpChineseFormal:
+ case EListStyleType::kSimpChineseInformal:
+ case EListStyleType::kTelugu:
+ case EListStyleType::kThai:
+ case EListStyleType::kTibetan:
+ case EListStyleType::kTradChineseFormal:
+ case EListStyleType::kTradChineseInformal:
+ case EListStyleType::kUpperAlpha:
+ case EListStyleType::kUpperArmenian:
+ case EListStyleType::kUpperLatin:
+ case EListStyleType::kUpperRoman:
+ case EListStyleType::kUrdu: {
+ int value = list_item->Value();
+ text->Append(list_marker_text::GetText(style.ListStyleType(), value));
+ if (format == kWithSuffix) {
+ text->Append(list_marker_text::Suffix(style.ListStyleType(), value));
+ text->Append(' ');
+ }
+ return kOrdinalValue;
+ }
+ }
+ NOTREACHED();
+ return kStatic;
+}
+
+String ListMarker::MarkerTextWithSuffix(const LayoutObject& marker) const {
+ StringBuilder text;
+ MarkerText(marker, &text, kWithSuffix);
+ return text.ToString();
+}
+
+String ListMarker::MarkerTextWithoutSuffix(const LayoutObject& marker) const {
+ StringBuilder text;
+ MarkerText(marker, &text, kWithoutSuffix);
+ return text.ToString();
+}
+
+String ListMarker::TextAlternative(const LayoutObject& marker) const {
+ // For accessibility, return the marker string in the logical order even in
+ // RTL, reflecting speech order.
+ return MarkerTextWithSuffix(marker);
+}
+
+void ListMarker::UpdateMarkerContentIfNeeded(LayoutObject& marker) {
+ LayoutNGListItem* list_item = ListItem(marker);
+
+ if (!marker.StyleRef().ContentBehavesAsNormal()) {
+ marker_text_type_ = kNotText;
+ return;
+ }
+
+ // There should be at most one child.
+ LayoutObject* child = marker.SlowFirstChild();
+ DCHECK(!child || !child->NextSibling());
+
+ if (IsMarkerImage(marker)) {
+ StyleImage* list_style_image = list_item->StyleRef().ListStyleImage();
+ if (child) {
+ // If the url of `list-style-image` changed, create a new LayoutImage.
+ if (!child->IsLayoutImage() ||
+ ToLayoutImage(child)->ImageResource()->ImagePtr() !=
+ list_style_image->Data()) {
+ child->Destroy();
+ child = nullptr;
+ }
+ }
+ if (!child) {
+ LayoutNGListMarkerImage* image =
+ LayoutNGListMarkerImage::CreateAnonymous(&marker.GetDocument());
+ scoped_refptr<ComputedStyle> image_style =
+ ComputedStyle::CreateAnonymousStyleWithDisplay(marker.StyleRef(),
+ EDisplay::kInline);
+ image->SetStyle(image_style);
+ image->SetImageResource(
+ MakeGarbageCollected<LayoutImageResourceStyleImage>(
+ list_style_image));
+ image->SetIsGeneratedContent();
+ marker.AddChild(image);
+ }
+ marker_text_type_ = kNotText;
+ return;
+ }
+
+ if (list_item->StyleRef().ListStyleType() == EListStyleType::kNone) {
+ marker_text_type_ = kNotText;
+ return;
+ }
+
+ // Create a LayoutText in it.
+ LayoutText* text = nullptr;
+ // |text_style| should be as same as style propagated in
+ // |LayoutObject::PropagateStyleToAnonymousChildren()| to avoid unexpected
+ // full layout due by style difference. See http://crbug.com/980399
+ scoped_refptr<ComputedStyle> text_style =
+ ComputedStyle::CreateAnonymousStyleWithDisplay(
+ marker.StyleRef(), marker.StyleRef().Display());
+ if (child) {
+ if (child->IsText()) {
+ text = ToLayoutText(child);
+ text->SetStyle(text_style);
+ } else {
+ child->Destroy();
+ child = nullptr;
+ }
+ }
+ if (!child) {
+ text = LayoutText::CreateEmptyAnonymous(marker.GetDocument(), text_style,
+ LegacyLayout::kAuto);
+ marker.AddChild(text);
+ marker_text_type_ = kUnresolved;
+ }
+}
+
+LayoutObject* ListMarker::SymbolMarkerLayoutText(
+ const LayoutObject& marker) const {
+ if (marker_text_type_ != kSymbolValue)
+ return nullptr;
+ return marker.SlowFirstChild();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/list_marker.h b/chromium/third_party/blink/renderer/core/layout/ng/list/list_marker.h
new file mode 100644
index 00000000000..0ecf1844689
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/list_marker.h
@@ -0,0 +1,71 @@
+// Copyright 2020 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LIST_LIST_MARKER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LIST_LIST_MARKER_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
+
+namespace blink {
+
+// This class holds code shared among LayoutNG classes for list markers.
+class CORE_EXPORT ListMarker {
+ friend class LayoutNGListItem;
+
+ public:
+ explicit ListMarker();
+
+ static const ListMarker* Get(const LayoutObject*);
+ static ListMarker* Get(LayoutObject*);
+
+ static LayoutNGListItem* ListItem(const LayoutObject&);
+
+ String MarkerTextWithSuffix(const LayoutObject&) const;
+ String MarkerTextWithoutSuffix(const LayoutObject&) const;
+
+ // Marker text with suffix, e.g. "1. ", for use in accessibility.
+ String TextAlternative(const LayoutObject&) const;
+
+ static bool IsMarkerImage(const LayoutObject& marker) {
+ return ListItem(marker)->StyleRef().GeneratesMarkerImage();
+ }
+
+ void UpdateMarkerTextIfNeeded(LayoutObject& marker) {
+ if (marker_text_type_ == kUnresolved)
+ UpdateMarkerText(marker);
+ }
+ void UpdateMarkerContentIfNeeded(LayoutObject&);
+
+ void OrdinalValueChanged(LayoutObject&);
+
+ LayoutObject* SymbolMarkerLayoutText(const LayoutObject&) const;
+
+ private:
+ enum MarkerTextFormat { kWithSuffix, kWithoutSuffix };
+ enum MarkerTextType {
+ kNotText, // The marker doesn't have a LayoutText, either because it has
+ // not been created yet or because 'list-style-type' is 'none',
+ // 'list-style-image' is not 'none', or 'content' is not
+ // 'normal'.
+ kUnresolved, // The marker has a LayoutText that needs to be updated.
+ kOrdinalValue, // The marker text depends on the ordinal.
+ kStatic, // The marker text doesn't depend on the ordinal.
+ kSymbolValue, // Like kStatic, but the marker is painted as a symbol.
+ };
+ MarkerTextType MarkerText(const LayoutObject&,
+ StringBuilder*,
+ MarkerTextFormat) const;
+ void UpdateMarkerText(LayoutObject&);
+ void UpdateMarkerText(LayoutObject&, LayoutText*);
+
+ void ListStyleTypeChanged(LayoutObject&);
+
+ unsigned marker_text_type_ : 3; // MarkerTextType
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LIST_LIST_MARKER_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc b/chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc
index 710824388d4..e0e08726a1f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc
@@ -7,7 +7,7 @@
#include "third_party/blink/renderer/core/layout/layout_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
@@ -15,16 +15,18 @@
namespace blink {
-NGUnpositionedListMarker::NGUnpositionedListMarker(LayoutNGListMarker* marker)
+NGUnpositionedListMarker::NGUnpositionedListMarker(
+ LayoutNGOutsideListMarker* marker)
: marker_layout_object_(marker) {}
NGUnpositionedListMarker::NGUnpositionedListMarker(const NGBlockNode& node)
- : NGUnpositionedListMarker(ToLayoutNGListMarker(node.GetLayoutBox())) {}
+ : NGUnpositionedListMarker(
+ ToLayoutNGOutsideListMarker(node.GetLayoutBox())) {}
// Returns true if this is an image marker.
bool NGUnpositionedListMarker::IsImage() const {
DCHECK(marker_layout_object_);
- return marker_layout_object_->IsContentImage();
+ return marker_layout_object_->Marker().IsMarkerImage(*marker_layout_object_);
}
// Compute the inline offset of the marker, relative to the list item.
@@ -45,24 +47,21 @@ scoped_refptr<const NGLayoutResult> NGUnpositionedListMarker::Layout(
FontBaseline baseline_type) const {
DCHECK(marker_layout_object_);
NGBlockNode marker_node(marker_layout_object_);
+
+ // We need the first-line baseline from the list-marker, instead of the
+ // typical atomic-inline baseline.
scoped_refptr<const NGLayoutResult> marker_layout_result =
- marker_node.LayoutAtomicInline(parent_space, parent_style, baseline_type,
- parent_space.UseFirstLineStyle());
+ marker_node.LayoutAtomicInline(parent_space, parent_style,
+ parent_space.UseFirstLineStyle(),
+ NGBaselineAlgorithmType::kFirstLine);
DCHECK(marker_layout_result);
return marker_layout_result;
}
-bool NGUnpositionedListMarker::CanAddToBox(
+base::Optional<LayoutUnit> NGUnpositionedListMarker::ContentAlignmentBaseline(
const NGConstraintSpace& space,
FontBaseline baseline_type,
- const NGPhysicalFragment& content,
- NGLineHeightMetrics* content_metrics) const {
- DCHECK(content_metrics);
-
- // Baselines from two different writing-mode cannot be aligned.
- if (UNLIKELY(space.GetWritingMode() != content.Style().GetWritingMode()))
- return false;
-
+ const NGPhysicalFragment& content) const {
// Compute the baseline of the child content.
if (content.IsLineBox()) {
const auto& line_box = To<NGPhysicalLineBoxFragment>(content);
@@ -71,22 +70,17 @@ bool NGUnpositionedListMarker::CanAddToBox(
// with the next non-empty line box produced. (This can occur with floats
// producing empty line-boxes).
if (line_box.IsEmptyLineBox() && !line_box.BreakToken()->IsFinished())
- return false;
+ return base::nullopt;
- *content_metrics = line_box.Metrics();
- } else {
- NGBoxFragment content_fragment(space.GetWritingMode(), space.Direction(),
- To<NGPhysicalBoxFragment>(content));
- *content_metrics = content_fragment.BaselineMetricsWithoutSynthesize(
- {NGBaselineAlgorithmType::kFirstLine, baseline_type});
-
- // If this child content does not have any line boxes, the list marker
- // should be aligned to the first line box of next child.
- // https://github.com/w3c/csswg-drafts/issues/2417
- if (content_metrics->IsEmpty())
- return false;
+ return line_box.Metrics().ascent;
}
- return true;
+
+ // If this child content does not have any line boxes, the list marker
+ // should be aligned to the first line box of next child.
+ // https://github.com/w3c/csswg-drafts/issues/2417
+ return NGBoxFragment(space.GetWritingMode(), space.Direction(),
+ To<NGPhysicalBoxFragment>(content))
+ .FirstBaseline();
}
void NGUnpositionedListMarker::AddToBox(
@@ -94,12 +88,10 @@ void NGUnpositionedListMarker::AddToBox(
FontBaseline baseline_type,
const NGPhysicalFragment& content,
const NGBoxStrut& border_scrollbar_padding,
- const NGLineHeightMetrics& content_metrics,
const NGLayoutResult& marker_layout_result,
+ LayoutUnit content_baseline,
LogicalOffset* content_offset,
NGBoxFragmentBuilder* container_builder) const {
- DCHECK(!content_metrics.IsEmpty());
-
const NGPhysicalBoxFragment& marker_physical_fragment =
To<NGPhysicalBoxFragment>(marker_layout_result.PhysicalFragment());
@@ -111,8 +103,8 @@ void NGUnpositionedListMarker::AddToBox(
// Adjust the block offset to align baselines of the marker and the content.
NGLineHeightMetrics marker_metrics = marker_fragment.BaselineMetrics(
- {NGBaselineAlgorithmType::kAtomicInline, baseline_type}, space);
- LayoutUnit baseline_adjust = content_metrics.ascent - marker_metrics.ascent;
+ /* margins */ NGLineBoxStrut(), baseline_type);
+ LayoutUnit baseline_adjust = content_baseline - marker_metrics.ascent;
if (baseline_adjust >= 0) {
marker_offset.block_offset += baseline_adjust;
} else {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h b/chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h
index 8305cac2cf6..5c5e6e3091f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h
@@ -14,7 +14,7 @@
namespace blink {
class ComputedStyle;
-class LayoutNGListMarker;
+class LayoutNGOutsideListMarker;
class LayoutUnit;
class NGBlockNode;
class NGConstraintSpace;
@@ -23,7 +23,6 @@ class NGLayoutResult;
class NGPhysicalFragment;
struct LogicalOffset;
-struct NGLineHeightMetrics;
// Represents an unpositioned list marker.
//
@@ -37,8 +36,8 @@ struct NGLineHeightMetrics;
//
// In order to adjust with the other content of LI, marker will be handled
// after other children.
-// First, try to find the adjusted content_metrics for the marker. See
-// |CanAddToBox()| for details.
+// First, try to find the alignment-baseline for the marker. See
+// |ContentAlignmentBaseline()| for details.
// If found, layout marker, compute the content adjusted offset and float
// intuded offset. See |AddToBox()| for details.
// If not, layout marker and deal with it in |AddToBoxWithoutLineBoxes()|.
@@ -52,25 +51,27 @@ class CORE_EXPORT NGUnpositionedListMarker final {
public:
NGUnpositionedListMarker() : marker_layout_object_(nullptr) {}
- explicit NGUnpositionedListMarker(LayoutNGListMarker*);
+ explicit NGUnpositionedListMarker(LayoutNGOutsideListMarker*);
explicit NGUnpositionedListMarker(const NGBlockNode&);
explicit operator bool() const { return marker_layout_object_; }
- // Returns true if the list marker can be added to box. False indicates
- // that the child content does not have a baseline to align to, and that
- // caller should try next child, or "WithoutLineBoxes" version.
- bool CanAddToBox(const NGConstraintSpace&,
- FontBaseline,
- const NGPhysicalFragment& content,
- NGLineHeightMetrics* content_metrics) const;
+ // Returns the baseline that the list-marker should place itself along.
+ //
+ // |base::nullopt| indicates that the child |content| does not have a baseline
+ // to align to, and that caller should try next child, or use the
+ // |AddToBoxWithoutLineBoxes()| method.
+ base::Optional<LayoutUnit> ContentAlignmentBaseline(
+ const NGConstraintSpace&,
+ FontBaseline,
+ const NGPhysicalFragment& content) const;
// Add a fragment for an outside list marker.
void AddToBox(const NGConstraintSpace&,
FontBaseline,
const NGPhysicalFragment& content,
const NGBoxStrut&,
- const NGLineHeightMetrics& content_metrics,
const NGLayoutResult& marker_layout_result,
+ LayoutUnit content_baseline,
LogicalOffset* content_offset,
NGBoxFragmentBuilder*) const;
@@ -105,7 +106,7 @@ class CORE_EXPORT NGUnpositionedListMarker final {
const NGBoxStrut&,
LayoutUnit) const;
- LayoutNGListMarker* marker_layout_object_;
+ LayoutNGOutsideListMarker* marker_layout_object_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/layout_ng_mathml_block.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/layout_ng_mathml_block.cc
new file mode 100644
index 00000000000..161826f1cff
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/layout_ng_mathml_block.cc
@@ -0,0 +1,46 @@
+// Copyright 2019 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/ng/mathml/layout_ng_mathml_block.h"
+
+#include "third_party/blink/renderer/core/layout/layout_analyzer.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
+
+namespace blink {
+
+LayoutNGMathMLBlock::LayoutNGMathMLBlock(MathMLElement* element)
+ : LayoutNGMixin<LayoutBlock>(element) {
+ DCHECK(element);
+}
+
+void LayoutNGMathMLBlock::UpdateBlockLayout(bool relayout_children) {
+ LayoutAnalyzer::BlockScope analyzer(*this);
+
+ if (IsOutOfFlowPositioned()) {
+ UpdateOutOfFlowBlockLayout();
+ return;
+ }
+
+ UpdateInFlowBlockLayout();
+}
+
+bool LayoutNGMathMLBlock::IsOfType(LayoutObjectType type) const {
+ return type == kLayoutObjectMathML ||
+ (type == kLayoutObjectMathMLRoot && GetNode() &&
+ GetNode()->HasTagName(mathml_names::kMathTag)) ||
+ LayoutNGMixin<LayoutBlock>::IsOfType(type);
+}
+
+bool LayoutNGMathMLBlock::IsChildAllowed(LayoutObject* child,
+ const ComputedStyle&) const {
+ return child->GetNode() && child->GetNode()->IsMathMLElement();
+}
+
+bool LayoutNGMathMLBlock::CanHaveChildren() const {
+ if (GetNode() && GetNode()->HasTagName(mathml_names::kMspaceTag))
+ return false;
+ return LayoutNGMixin<LayoutBlock>::CanHaveChildren();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/layout_ng_mathml_block.h b/chromium/third_party/blink/renderer/core/layout/ng/mathml/layout_ng_mathml_block.h
new file mode 100644
index 00000000000..bc9dc975643
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/layout_ng_mathml_block.h
@@ -0,0 +1,29 @@
+// Copyright 2019 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_LAYOUT_NG_MATHML_BLOCK_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_LAYOUT_NG_MATHML_BLOCK_H_
+
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h"
+#include "third_party/blink/renderer/core/mathml/mathml_element.h"
+
+namespace blink {
+
+class LayoutNGMathMLBlock : public LayoutNGMixin<LayoutBlock> {
+ public:
+ explicit LayoutNGMathMLBlock(MathMLElement*);
+
+ const char* GetName() const override { return "LayoutNGMathMLBlock"; }
+
+ private:
+ void UpdateBlockLayout(bool relayout_children) final;
+
+ bool IsOfType(LayoutObjectType) const final;
+ bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const final;
+ bool CanHaveChildren() const final;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_LAYOUT_NG_MATHML_BLOCK_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.cc
new file mode 100644
index 00000000000..9deb2e3c49f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.cc
@@ -0,0 +1,323 @@
+// Copyright 2020 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/ng/mathml/ng_math_fraction_layout_algorithm.h"
+
+#include "third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.h"
+
+namespace blink {
+namespace {
+
+// Describes the amount to shift the numerator/denominator of the fraction when
+// a fraction bar is present. Data is populated from the OpenType MATH table.
+// If the OpenType MATH table is not present fallback values are used.
+// https://mathml-refresh.github.io/mathml-core/#fraction-with-nonzero-line-thickness
+struct FractionParameters {
+ LayoutUnit numerator_gap_min;
+ LayoutUnit denominator_gap_min;
+ LayoutUnit numerator_min_shift_up;
+ LayoutUnit denominator_min_shift_down;
+};
+
+FractionParameters GetFractionParameters(const ComputedStyle& style) {
+ FractionParameters parameters;
+
+ bool has_display_style = HasDisplayStyle(style);
+
+ // We try and read constants to draw the fraction from the OpenType MATH and
+ // use fallback values otherwise.
+ // The MATH table specification suggests default rule thickness or (in
+ // displaystyle) 3 times default rule thickness for the gaps.
+ parameters.numerator_gap_min = LayoutUnit(
+ MathConstant(
+ style,
+ has_display_style
+ ? OpenTypeMathSupport::MathConstants::
+ kFractionNumDisplayStyleGapMin
+ : OpenTypeMathSupport::MathConstants::kFractionNumeratorGapMin)
+ .value_or((has_display_style ? 3 : 1) *
+ RuleThicknessFallback(style)));
+ parameters.denominator_gap_min = LayoutUnit(
+ MathConstant(
+ style,
+ has_display_style
+ ? OpenTypeMathSupport::MathConstants::
+ kFractionDenomDisplayStyleGapMin
+ : OpenTypeMathSupport::MathConstants::kFractionDenominatorGapMin)
+ .value_or(parameters.numerator_gap_min));
+
+ // TODO(crbug.com/1058369): The MATH table specification does not suggest
+ // any values for shifts, so we leave them at zero for now.
+ parameters.numerator_min_shift_up = LayoutUnit(
+ MathConstant(
+ style,
+ has_display_style
+ ? OpenTypeMathSupport::MathConstants::
+ kFractionNumeratorDisplayStyleShiftUp
+ : OpenTypeMathSupport::MathConstants::kFractionNumeratorShiftUp)
+ .value_or(0));
+ parameters.denominator_min_shift_down = LayoutUnit(
+ MathConstant(style, has_display_style
+ ? OpenTypeMathSupport::MathConstants::
+ kFractionDenominatorDisplayStyleShiftDown
+ : OpenTypeMathSupport::MathConstants::
+ kFractionDenominatorShiftDown)
+ .value_or(0));
+
+ return parameters;
+}
+
+// Describes the amount to shift the numerator/denominator of the fraction when
+// a fraction bar is not present. Data is populated from the OpenType MATH
+// table. If the OpenType MATH table is not present fallback values are used.
+// https://mathml-refresh.github.io/mathml-core/#fraction-with-zero-line-thickness
+struct FractionStackParameters {
+ LayoutUnit gap_min;
+ LayoutUnit top_shift_up;
+ LayoutUnit bottom_shift_down;
+};
+
+FractionStackParameters GetFractionStackParameters(const ComputedStyle& style) {
+ FractionStackParameters parameters;
+
+ bool has_display_style = HasDisplayStyle(style);
+
+ // We try and read constants to draw the stack from the OpenType MATH and use
+ // fallback values otherwise.
+ // We use the fallback values suggested in the MATH table specification.
+ parameters.gap_min = LayoutUnit(
+ MathConstant(
+ style,
+ has_display_style
+ ? OpenTypeMathSupport::MathConstants::kStackDisplayStyleGapMin
+ : OpenTypeMathSupport::MathConstants::kStackGapMin)
+ .value_or((has_display_style ? 7 : 3) *
+ RuleThicknessFallback(style)));
+ // The MATH table specification does not suggest any values for shifts, so
+ // we leave them at zero.
+ parameters.top_shift_up = LayoutUnit(
+ MathConstant(
+ style,
+ has_display_style
+ ? OpenTypeMathSupport::MathConstants::kStackTopDisplayStyleShiftUp
+ : OpenTypeMathSupport::MathConstants::kStackTopShiftUp)
+ .value_or(0));
+ parameters.bottom_shift_down = LayoutUnit(
+ MathConstant(
+ style,
+ has_display_style
+ ? OpenTypeMathSupport::MathConstants::
+ kStackBottomDisplayStyleShiftDown
+ : OpenTypeMathSupport::MathConstants::kStackBottomShiftDown)
+ .value_or(0));
+
+ return parameters;
+}
+
+} // namespace
+
+NGMathFractionLayoutAlgorithm::NGMathFractionLayoutAlgorithm(
+ const NGLayoutAlgorithmParams& params)
+ : NGLayoutAlgorithm(params),
+ border_scrollbar_padding_(params.fragment_geometry.border +
+ params.fragment_geometry.padding +
+ params.fragment_geometry.scrollbar) {
+ DCHECK(params.space.IsNewFormattingContext());
+ container_builder_.SetIsNewFormattingContext(
+ params.space.IsNewFormattingContext());
+ container_builder_.SetInitialFragmentGeometry(params.fragment_geometry);
+ container_builder_.SetIsMathMLFraction();
+}
+
+void NGMathFractionLayoutAlgorithm::GatherChildren(NGBlockNode* numerator,
+ NGBlockNode* denominator) {
+ for (NGLayoutInputNode child = Node().FirstChild(); child;
+ child = child.NextSibling()) {
+ NGBlockNode block_child = To<NGBlockNode>(child);
+ if (child.IsOutOfFlowPositioned()) {
+ container_builder_.AddOutOfFlowChildCandidate(
+ block_child, {border_scrollbar_padding_.inline_start,
+ border_scrollbar_padding_.block_start});
+ continue;
+ }
+ if (!*numerator) {
+ *numerator = block_child;
+ continue;
+ }
+ if (!*denominator) {
+ *denominator = block_child;
+ continue;
+ }
+
+ NOTREACHED();
+ }
+
+ DCHECK(*numerator);
+ DCHECK(*denominator);
+}
+
+scoped_refptr<const NGLayoutResult> NGMathFractionLayoutAlgorithm::Layout() {
+ DCHECK(!BreakToken());
+
+ NGBlockNode numerator = nullptr;
+ NGBlockNode denominator = nullptr;
+ GatherChildren(&numerator, &denominator);
+
+ const LogicalSize border_box_size = container_builder_.InitialBorderBoxSize();
+ auto child_available_size =
+ ShrinkAvailableSize(border_box_size, border_scrollbar_padding_);
+ auto numerator_space = CreateConstraintSpaceForMathChild(
+ Node(), child_available_size, ConstraintSpace(), numerator);
+ scoped_refptr<const NGLayoutResult> numerator_layout_result =
+ numerator.Layout(numerator_space);
+ auto numerator_margins =
+ ComputeMarginsFor(numerator_space, numerator.Style(), ConstraintSpace());
+ auto denominator_space = CreateConstraintSpaceForMathChild(
+ Node(), child_available_size, ConstraintSpace(), denominator);
+ scoped_refptr<const NGLayoutResult> denominator_layout_result =
+ denominator.Layout(denominator_space);
+ auto denominator_margins = ComputeMarginsFor(
+ denominator_space, denominator.Style(), ConstraintSpace());
+
+ NGBoxFragment numerator_fragment(
+ ConstraintSpace().GetWritingMode(), ConstraintSpace().Direction(),
+ To<NGPhysicalBoxFragment>(numerator_layout_result->PhysicalFragment()));
+ NGBoxFragment denominator_fragment(
+ ConstraintSpace().GetWritingMode(), ConstraintSpace().Direction(),
+ To<NGPhysicalBoxFragment>(denominator_layout_result->PhysicalFragment()));
+
+ LayoutUnit content_inline_size = std::max(
+ numerator_fragment.InlineSize() + numerator_margins.InlineSum(),
+ denominator_fragment.InlineSize() + denominator_margins.InlineSum());
+
+ LayoutUnit numerator_ascent =
+ numerator_margins.block_start +
+ numerator_fragment.Baseline().value_or(numerator_fragment.BlockSize());
+ LayoutUnit numerator_descent = numerator_fragment.BlockSize() +
+ numerator_margins.BlockSum() -
+ numerator_ascent;
+ LayoutUnit denominator_ascent = denominator_margins.block_start +
+ denominator_fragment.Baseline().value_or(
+ denominator_fragment.BlockSize());
+ LayoutUnit denominator_descent = denominator_fragment.BlockSize() +
+ denominator_margins.BlockSum() -
+ denominator_ascent;
+
+ LayoutUnit numerator_shift, denominator_shift;
+ LayoutUnit thickness = FractionLineThickness(Style());
+ if (thickness) {
+ LayoutUnit axis_height = MathAxisHeight(Style());
+ FractionParameters parameters = GetFractionParameters(Style());
+ numerator_shift =
+ std::max(parameters.numerator_min_shift_up,
+ axis_height + thickness / 2 + parameters.numerator_gap_min +
+ numerator_descent);
+ denominator_shift =
+ std::max(parameters.denominator_min_shift_down,
+ thickness / 2 + parameters.denominator_gap_min +
+ denominator_ascent - axis_height);
+ } else {
+ FractionStackParameters parameters = GetFractionStackParameters(Style());
+ numerator_shift = parameters.top_shift_up;
+ denominator_shift = parameters.bottom_shift_down;
+ LayoutUnit gap = denominator_shift - denominator_ascent + numerator_shift -
+ numerator_descent;
+ if (gap < parameters.gap_min) {
+ LayoutUnit diff = parameters.gap_min - gap;
+ LayoutUnit delta = diff / 2;
+ numerator_shift += delta;
+ denominator_shift += diff - delta;
+ }
+ }
+
+ LayoutUnit fraction_ascent =
+ std::max(numerator_shift + numerator_ascent,
+ -denominator_shift + denominator_ascent);
+ LayoutUnit fraction_descent =
+ std::max(-numerator_shift + numerator_descent,
+ denominator_shift + denominator_descent);
+ fraction_ascent += border_scrollbar_padding_.block_start;
+ fraction_descent += border_scrollbar_padding_.block_end;
+ LayoutUnit total_block_size = fraction_ascent + fraction_descent;
+
+ container_builder_.SetBaseline(fraction_ascent);
+
+ LogicalOffset numerator_offset;
+ LogicalOffset denominator_offset;
+ numerator_offset.inline_offset =
+ border_scrollbar_padding_.inline_start + numerator_margins.inline_start +
+ (content_inline_size -
+ (numerator_fragment.InlineSize() + numerator_margins.InlineSum())) /
+ 2;
+ denominator_offset.inline_offset =
+ border_scrollbar_padding_.inline_start +
+ denominator_margins.inline_start +
+ (content_inline_size -
+ (denominator_fragment.InlineSize() + denominator_margins.InlineSum())) /
+ 2;
+
+ numerator_offset.block_offset = numerator_margins.block_start +
+ fraction_ascent - numerator_shift -
+ numerator_ascent;
+ denominator_offset.block_offset = denominator_margins.block_start +
+ fraction_ascent + denominator_shift -
+ denominator_ascent;
+
+ container_builder_.AddChild(numerator_layout_result->PhysicalFragment(),
+ numerator_offset);
+ container_builder_.AddChild(denominator_layout_result->PhysicalFragment(),
+ denominator_offset);
+
+ numerator.StoreMargins(ConstraintSpace(), numerator_margins);
+ denominator.StoreMargins(ConstraintSpace(), denominator_margins);
+
+ LayoutUnit block_size = ComputeBlockSizeForFragment(
+ ConstraintSpace(), Style(), border_scrollbar_padding_, total_block_size);
+
+ container_builder_.SetIntrinsicBlockSize(total_block_size);
+ container_builder_.SetBlockSize(block_size);
+
+ NGOutOfFlowLayoutPart(Node(), ConstraintSpace(), container_builder_.Borders(),
+ &container_builder_)
+ .Run();
+
+ return container_builder_.ToBoxFragment();
+}
+
+base::Optional<MinMaxSizes> NGMathFractionLayoutAlgorithm::ComputeMinMaxSizes(
+ const MinMaxSizesInput& input) const {
+ base::Optional<MinMaxSizes> sizes =
+ CalculateMinMaxSizesIgnoringChildren(Node(), border_scrollbar_padding_);
+ if (sizes)
+ return sizes;
+
+ sizes.emplace();
+ LayoutUnit child_percentage_resolution_block_size =
+ CalculateChildPercentageBlockSizeForMinMax(
+ ConstraintSpace(), Node(), border_scrollbar_padding_,
+ input.percentage_resolution_block_size);
+
+ MinMaxSizesInput child_input(child_percentage_resolution_block_size);
+
+ for (NGLayoutInputNode child = Node().FirstChild(); child;
+ child = child.NextSibling()) {
+ if (child.IsOutOfFlowPositioned())
+ continue;
+ auto child_sizes =
+ ComputeMinAndMaxContentContribution(Style(), child, child_input);
+ NGBoxStrut margins = ComputeMinMaxMargins(Style(), child);
+ child_sizes += margins.InlineSum();
+ sizes->Encompass(child_sizes);
+ }
+
+ *sizes += border_scrollbar_padding_.InlineSum();
+ return sizes;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.h
new file mode 100644
index 00000000000..d645439465f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.h
@@ -0,0 +1,31 @@
+// Copyright 2020 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_NG_MATH_FRACTION_LAYOUT_ALGORITHM_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_NG_MATH_FRACTION_LAYOUT_ALGORITHM_H_
+
+#include "third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.h"
+
+namespace blink {
+
+class CORE_EXPORT NGMathFractionLayoutAlgorithm
+ : public NGLayoutAlgorithm<NGBlockNode,
+ NGBoxFragmentBuilder,
+ NGBlockBreakToken> {
+ public:
+ explicit NGMathFractionLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
+
+ private:
+ scoped_refptr<const NGLayoutResult> Layout() final;
+
+ base::Optional<MinMaxSizes> ComputeMinMaxSizes(
+ const MinMaxSizesInput&) const final;
+
+ void GatherChildren(NGBlockNode* numerator, NGBlockNode* denominator);
+ const NGBoxStrut border_scrollbar_padding_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_NG_MATH_FRACTION_LAYOUT_ALGORITHM_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc
new file mode 100644
index 00000000000..44f6ed8d617
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.cc
@@ -0,0 +1,97 @@
+// Copyright 2019 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/ng/mathml/ng_math_layout_utils.h"
+
+#include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
+#include "third_party/blink/renderer/core/mathml/mathml_fraction_element.h"
+
+namespace blink {
+
+NGConstraintSpace CreateConstraintSpaceForMathChild(
+ const NGBlockNode& parent_node,
+ const LogicalSize& child_available_size,
+ const NGConstraintSpace& parent_constraint_space,
+ const NGLayoutInputNode& child) {
+ const ComputedStyle& parent_style = parent_node.Style();
+ const ComputedStyle& child_style = child.Style();
+ DCHECK(child.CreatesNewFormattingContext());
+ NGConstraintSpaceBuilder space_builder(parent_constraint_space,
+ child_style.GetWritingMode(),
+ true /* is_new_fc */);
+ SetOrthogonalFallbackInlineSizeIfNeeded(parent_style, child, &space_builder);
+
+ space_builder.SetAvailableSize(child_available_size);
+ space_builder.SetPercentageResolutionSize(child_available_size);
+ space_builder.SetReplacedPercentageResolutionSize(child_available_size);
+
+ space_builder.SetIsShrinkToFit(child_style.LogicalWidth().IsAuto());
+
+ // TODO(rbuis): add target stretch sizes.
+
+ space_builder.SetTextDirection(child_style.Direction());
+
+ // TODO(rbuis): add ink baselines?
+ space_builder.SetNeedsBaseline(true);
+ return space_builder.ToConstraintSpace();
+}
+
+NGLayoutInputNode FirstChildInFlow(const NGBlockNode& node) {
+ NGLayoutInputNode child = node.FirstChild();
+ while (child && child.IsOutOfFlowPositioned())
+ child = child.NextSibling();
+ return child;
+}
+
+NGLayoutInputNode NextSiblingInFlow(const NGBlockNode& node) {
+ NGLayoutInputNode sibling = node.NextSibling();
+ while (sibling && sibling.IsOutOfFlowPositioned())
+ sibling = sibling.NextSibling();
+ return sibling;
+}
+
+inline bool InFlowChildCountIs(const NGBlockNode& node, unsigned count) {
+ DCHECK(count == 2 || count == 3);
+ auto child = To<NGBlockNode>(FirstChildInFlow(node));
+ while (count && child) {
+ child = To<NGBlockNode>(NextSiblingInFlow(child));
+ count--;
+ }
+ return !count && !child;
+}
+
+bool IsValidMathMLFraction(const NGBlockNode& node) {
+ return InFlowChildCountIs(node, 2);
+}
+
+namespace {
+
+inline LayoutUnit DefaultFractionLineThickness(const ComputedStyle& style) {
+ return LayoutUnit(
+ MathConstant(style,
+ OpenTypeMathSupport::MathConstants::kFractionRuleThickness)
+ .value_or(RuleThicknessFallback(style)));
+}
+
+} // namespace
+
+LayoutUnit MathAxisHeight(const ComputedStyle& style) {
+ return LayoutUnit(
+ MathConstant(style, OpenTypeMathSupport::MathConstants::kAxisHeight)
+ .value_or(style.GetFont().PrimaryFont()->GetFontMetrics().XHeight() /
+ 2));
+}
+
+LayoutUnit FractionLineThickness(const ComputedStyle& style) {
+ return std::max<LayoutUnit>(
+ ValueForLength(style.GetMathFractionBarThickness(),
+ DefaultFractionLineThickness(style)),
+ LayoutUnit());
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.h
new file mode 100644
index 00000000000..366e1a81171
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.h
@@ -0,0 +1,54 @@
+// Copyright 2019 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_NG_MATH_LAYOUT_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_NG_MATH_LAYOUT_UTILS_H_
+
+#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/fonts/opentype/open_type_math_support.h"
+
+namespace blink {
+
+struct LogicalSize;
+class NGBlockNode;
+class NGConstraintSpace;
+class NGLayoutInputNode;
+
+// Creates a new constraint space for the current child.
+NGConstraintSpace CreateConstraintSpaceForMathChild(
+ const NGBlockNode& parent_node,
+ const LogicalSize& child_available_size,
+ const NGConstraintSpace& parent_constraint_space,
+ const NGLayoutInputNode&);
+
+NGLayoutInputNode FirstChildInFlow(const NGBlockNode&);
+NGLayoutInputNode NextSiblingInFlow(const NGBlockNode&);
+
+bool IsValidMathMLFraction(const NGBlockNode&);
+
+inline float RuleThicknessFallback(const ComputedStyle& style) {
+ // This function returns a value for the default rule thickness (TeX's
+ // \xi_8) to be used as a fallback when we lack a MATH table.
+ return 0.05f * style.FontSize();
+}
+
+LayoutUnit MathAxisHeight(const ComputedStyle& style);
+
+inline base::Optional<float> MathConstant(
+ const ComputedStyle& style,
+ OpenTypeMathSupport::MathConstants constant) {
+ return OpenTypeMathSupport::MathConstant(
+ style.GetFont().PrimaryFont()->PlatformData().GetHarfBuzzFace(),
+ constant);
+}
+
+LayoutUnit FractionLineThickness(const ComputedStyle& style);
+
+inline bool HasDisplayStyle(const ComputedStyle& style) {
+ return style.MathStyle() == EMathStyle::kDisplay;
+}
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_NG_MATH_LAYOUT_UTILS_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.cc
new file mode 100644
index 00000000000..6fe8785a1cc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.cc
@@ -0,0 +1,180 @@
+// Copyright 2019 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/ng/mathml/ng_math_row_layout_algorithm.h"
+
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_child_layout_context.h"
+#include "third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/core/mathml/mathml_element.h"
+
+namespace blink {
+namespace {
+
+inline LayoutUnit InlineOffsetForDisplayMathCentering(
+ bool is_display_math,
+ LayoutUnit available_inline_size,
+ LayoutUnit max_row_inline_size) {
+ if (is_display_math)
+ return (available_inline_size - max_row_inline_size) / 2;
+ return LayoutUnit();
+}
+
+} // namespace
+
+NGMathRowLayoutAlgorithm::NGMathRowLayoutAlgorithm(
+ const NGLayoutAlgorithmParams& params)
+ : NGLayoutAlgorithm(params),
+ border_padding_(params.fragment_geometry.border +
+ params.fragment_geometry.padding),
+ border_scrollbar_padding_(border_padding_ +
+ params.fragment_geometry.scrollbar) {
+ DCHECK(params.space.IsNewFormattingContext());
+ DCHECK(!ConstraintSpace().HasBlockFragmentation());
+ container_builder_.SetIsNewFormattingContext(
+ params.space.IsNewFormattingContext());
+ container_builder_.SetInitialFragmentGeometry(params.fragment_geometry);
+}
+
+void NGMathRowLayoutAlgorithm::LayoutRowItems(
+ NGContainerFragmentBuilder::ChildrenVector* children,
+ LayoutUnit* max_row_block_baseline,
+ LogicalSize* row_total_size) {
+ LayoutUnit inline_offset, max_row_ascent, max_row_descent;
+ for (NGLayoutInputNode child = Node().FirstChild(); child;
+ child = child.NextSibling()) {
+ if (child.IsOutOfFlowPositioned()) {
+ // TODO(rbuis): OOF should be "where child would have been if not
+ // absolutely positioned".
+ // Issue: https://github.com/mathml-refresh/mathml/issues/16
+ container_builder_.AddOutOfFlowChildCandidate(
+ To<NGBlockNode>(child), {border_scrollbar_padding_.inline_start,
+ border_scrollbar_padding_.block_start});
+ continue;
+ }
+ const ComputedStyle& child_style = child.Style();
+ NGConstraintSpace child_space = CreateConstraintSpaceForMathChild(
+ Node(), child_available_size_, ConstraintSpace(), child);
+ scoped_refptr<const NGLayoutResult> result =
+ To<NGBlockNode>(child).Layout(child_space, nullptr /* break token */);
+ const NGPhysicalContainerFragment& physical_fragment =
+ result->PhysicalFragment();
+ NGBoxFragment fragment(ConstraintSpace().GetWritingMode(),
+ ConstraintSpace().Direction(),
+ To<NGPhysicalBoxFragment>(physical_fragment));
+
+ NGBoxStrut margins =
+ ComputeMarginsFor(child_space, child_style, ConstraintSpace());
+ inline_offset += margins.inline_start;
+
+ LayoutUnit ascent = margins.block_start +
+ fragment.Baseline().value_or(fragment.BlockSize());
+ *max_row_block_baseline = std::max(*max_row_block_baseline, ascent);
+
+ // TODO(rbuis): Operators can add lspace and rspace.
+
+ children->emplace_back(
+ LogicalOffset{inline_offset, margins.block_start - ascent},
+ &physical_fragment);
+
+ inline_offset += fragment.InlineSize() + margins.inline_end;
+
+ max_row_ascent = std::max(max_row_ascent, ascent + margins.block_start);
+ max_row_descent = std::max(
+ max_row_descent, fragment.BlockSize() + margins.block_end - ascent);
+ row_total_size->inline_size =
+ std::max(row_total_size->inline_size, inline_offset);
+ }
+ row_total_size->block_size = max_row_ascent + max_row_descent;
+}
+
+scoped_refptr<const NGLayoutResult> NGMathRowLayoutAlgorithm::Layout() {
+ DCHECK(!BreakToken());
+
+ bool is_display_math =
+ Node().IsMathRoot() && Style().Display() == EDisplay::kMath;
+
+ LogicalSize max_row_size;
+ LayoutUnit max_row_block_baseline;
+
+ const LogicalSize border_box_size = container_builder_.InitialBorderBoxSize();
+ child_available_size_ =
+ ShrinkAvailableSize(border_box_size, border_scrollbar_padding_);
+
+ NGContainerFragmentBuilder::ChildrenVector children;
+ LayoutRowItems(&children, &max_row_block_baseline, &max_row_size);
+
+ // Add children taking into account centering, baseline and
+ // border/scrollbar/padding.
+ LayoutUnit center_offset = InlineOffsetForDisplayMathCentering(
+ is_display_math, container_builder_.InlineSize(),
+ max_row_size.inline_size);
+ LogicalOffset adjust_offset(
+ border_scrollbar_padding_.inline_start + center_offset,
+ border_scrollbar_padding_.block_start + max_row_block_baseline);
+ for (auto& child : children) {
+ child.offset += adjust_offset;
+ container_builder_.AddChild(
+ To<NGPhysicalContainerFragment>(*child.fragment), child.offset);
+ }
+
+ container_builder_.SetBaseline(border_scrollbar_padding_.block_start +
+ max_row_block_baseline);
+
+ auto block_size = ComputeBlockSizeForFragment(
+ ConstraintSpace(), Style(), border_padding_,
+ max_row_size.block_size + border_scrollbar_padding_.BlockSum());
+ container_builder_.SetBlockSize(block_size);
+
+ NGOutOfFlowLayoutPart(
+ Node(), ConstraintSpace(),
+ container_builder_.Borders() + container_builder_.Scrollbar(),
+ &container_builder_)
+ .Run();
+
+ return container_builder_.ToBoxFragment();
+}
+
+base::Optional<MinMaxSizes> NGMathRowLayoutAlgorithm::ComputeMinMaxSizes(
+ const MinMaxSizesInput& input) const {
+ base::Optional<MinMaxSizes> sizes =
+ CalculateMinMaxSizesIgnoringChildren(Node(), border_scrollbar_padding_);
+ if (sizes)
+ return sizes;
+
+ sizes.emplace();
+ LayoutUnit child_percentage_resolution_block_size =
+ CalculateChildPercentageBlockSizeForMinMax(
+ ConstraintSpace(), Node(), border_padding_,
+ input.percentage_resolution_block_size);
+
+ MinMaxSizesInput child_input(child_percentage_resolution_block_size);
+
+ for (NGLayoutInputNode child = Node().FirstChild(); child;
+ child = child.NextSibling()) {
+ if (child.IsOutOfFlowPositioned())
+ continue;
+ MinMaxSizes child_min_max_sizes =
+ ComputeMinAndMaxContentContribution(Style(), child, child_input);
+ NGBoxStrut child_margins = ComputeMinMaxMargins(Style(), child);
+ child_min_max_sizes += child_margins.InlineSum();
+ sizes->max_size += child_min_max_sizes.max_size;
+ sizes->min_size += child_min_max_sizes.min_size;
+
+ // TODO(rbuis): Operators can add lspace and rspace.
+ }
+ sizes->max_size = std::max(sizes->max_size, sizes->min_size);
+
+ // Due to negative margins, it is possible that we calculated a negative
+ // intrinsic width. Make sure that we never return a negative width.
+ sizes->Encompass(LayoutUnit());
+ *sizes += border_scrollbar_padding_.InlineSum();
+ return sizes;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.h
new file mode 100644
index 00000000000..72b8dd10b40
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.h
@@ -0,0 +1,42 @@
+// Copyright 2019 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_NG_MATH_ROW_LAYOUT_ALGORITHM_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_NG_MATH_ROW_LAYOUT_ALGORITHM_H_
+
+#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h"
+
+namespace blink {
+
+class LayoutUnit;
+
+class CORE_EXPORT NGMathRowLayoutAlgorithm
+ : public NGLayoutAlgorithm<NGBlockNode,
+ NGBoxFragmentBuilder,
+ NGBlockBreakToken> {
+ public:
+ NGMathRowLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
+
+ protected:
+ void LayoutRowItems(NGContainerFragmentBuilder::ChildrenVector*,
+ LayoutUnit* max_row_block_baseline,
+ LogicalSize* row_total_size);
+
+ private:
+ scoped_refptr<const NGLayoutResult> Layout() final;
+
+ base::Optional<MinMaxSizes> ComputeMinMaxSizes(
+ const MinMaxSizesInput&) const final;
+
+ LogicalSize child_available_size_;
+ const NGBoxStrut border_padding_;
+ const NGBoxStrut border_scrollbar_padding_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_NG_MATH_ROW_LAYOUT_ALGORITHM_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.cc
new file mode 100644
index 00000000000..4abfa765870
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.cc
@@ -0,0 +1,42 @@
+// Copyright 2020 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/ng/mathml/ng_math_space_layout_algorithm.h"
+
+#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
+
+namespace blink {
+
+NGMathSpaceLayoutAlgorithm::NGMathSpaceLayoutAlgorithm(
+ const NGLayoutAlgorithmParams& params)
+ : NGLayoutAlgorithm(params),
+ border_padding_(params.fragment_geometry.border +
+ params.fragment_geometry.padding) {
+ DCHECK(params.fragment_geometry.scrollbar.IsEmpty());
+ container_builder_.SetIsNewFormattingContext(true);
+ container_builder_.SetInitialFragmentGeometry(params.fragment_geometry);
+}
+
+scoped_refptr<const NGLayoutResult> NGMathSpaceLayoutAlgorithm::Layout() {
+ DCHECK(!BreakToken());
+
+ LayoutUnit block_size = ComputeBlockSizeForFragment(
+ ConstraintSpace(), Style(), border_padding_, border_padding_.BlockSum());
+
+ container_builder_.SetIntrinsicBlockSize(border_padding_.BlockSum());
+ container_builder_.SetBlockSize(block_size);
+
+ container_builder_.SetBaseline(
+ border_padding_.block_start +
+ ValueForLength(Style().GetMathBaseline(), LayoutUnit()));
+ return container_builder_.ToBoxFragment();
+}
+
+base::Optional<MinMaxSizes> NGMathSpaceLayoutAlgorithm::ComputeMinMaxSizes(
+ const MinMaxSizesInput& input) const {
+ return CalculateMinMaxSizesIgnoringChildren(Node(), border_padding_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.h
new file mode 100644
index 00000000000..7b493ef0b17
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.h
@@ -0,0 +1,31 @@
+// Copyright 2020 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_NG_MATH_SPACE_LAYOUT_ALGORITHM_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_NG_MATH_SPACE_LAYOUT_ALGORITHM_H_
+
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h"
+
+namespace blink {
+
+class CORE_EXPORT NGMathSpaceLayoutAlgorithm
+ : public NGLayoutAlgorithm<NGBlockNode,
+ NGBoxFragmentBuilder,
+ NGBlockBreakToken> {
+ public:
+ explicit NGMathSpaceLayoutAlgorithm(const NGLayoutAlgorithmParams& params);
+
+ private:
+ scoped_refptr<const NGLayoutResult> Layout() final;
+
+ base::Optional<MinMaxSizes> ComputeMinMaxSizes(
+ const MinMaxSizesInput&) const final;
+
+ const NGBoxStrut border_padding_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_MATHML_NG_MATH_SPACE_LAYOUT_ALGORITHM_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
index d6c66b0b708..fd2180c4c50 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc
@@ -31,7 +31,7 @@ bool IsLogicalWidthTreatedAsAuto(const ComputedStyle& style) {
return IsTable(style) || style.LogicalWidth().IsAuto();
}
-bool IsLogicalHeightTreatAsAuto(const ComputedStyle& style) {
+bool IsLogicalHeightTreatedAsAuto(const ComputedStyle& style) {
return IsTable(style) || style.LogicalHeight().IsAuto();
}
@@ -111,11 +111,11 @@ inline LayoutUnit StaticPositionEndInset(StaticPositionEdge edge,
}
LayoutUnit ComputeShrinkToFitSize(
- const base::Optional<MinMaxSize>& child_minmax,
+ const base::Optional<MinMaxSizes>& min_max_sizes,
LayoutUnit computed_available_size,
LayoutUnit margin_start,
LayoutUnit margin_end) {
- return child_minmax->ShrinkToFit(
+ return min_max_sizes->ShrinkToFit(
(computed_available_size - margin_start - margin_end)
.ClampNegativeToZero());
}
@@ -123,10 +123,10 @@ LayoutUnit ComputeShrinkToFitSize(
// Implement the absolute size resolution algorithm.
// https://www.w3.org/TR/css-position-3/#abs-non-replaced-width
// https://www.w3.org/TR/css-position-3/#abs-non-replaced-height
-// |child_minmax| can have no value if an element is replaced, and has no
+// |min_max_sizes| can have no value if an element is replaced, and has no
// intrinsic width or height, but has an aspect ratio.
void ComputeAbsoluteSize(const LayoutUnit border_padding_size,
- const base::Optional<MinMaxSize>& child_minmax,
+ const base::Optional<MinMaxSizes>& min_max_sizes,
const LayoutUnit margin_percentage_resolution_size,
const LayoutUnit available_size,
const Length& margin_start_length,
@@ -199,7 +199,7 @@ void ComputeAbsoluteSize(const LayoutUnit border_padding_size,
computed_available_size = static_position_offset;
break;
}
- size = ComputeShrinkToFitSize(child_minmax, computed_available_size,
+ size = ComputeShrinkToFitSize(min_max_sizes, computed_available_size,
*margin_start, *margin_end);
LayoutUnit margin_size = *size + *margin_start + *margin_end;
if (is_start_dominant) {
@@ -259,7 +259,7 @@ void ComputeAbsoluteSize(const LayoutUnit border_padding_size,
// Rule 1: left/width are unknown.
DCHECK(inset_end.has_value());
LayoutUnit computed_available_size = available_size - *inset_end;
- size = ComputeShrinkToFitSize(child_minmax, computed_available_size,
+ size = ComputeShrinkToFitSize(min_max_sizes, computed_available_size,
*margin_start, *margin_end);
} else if (!inset_start && !inset_end) {
// Rule 2.
@@ -276,7 +276,7 @@ void ComputeAbsoluteSize(const LayoutUnit border_padding_size,
} else if (!size && !inset_end) {
// Rule 3.
LayoutUnit computed_available_size = available_size - *inset_start;
- size = ComputeShrinkToFitSize(child_minmax, computed_available_size,
+ size = ComputeShrinkToFitSize(min_max_sizes, computed_available_size,
*margin_start, *margin_end);
}
@@ -300,7 +300,7 @@ void ComputeAbsoluteSize(const LayoutUnit border_padding_size,
// is safe to recursively call ourselves here because on the second call it
// is guaranteed to be within |min_size| and |max_size|.
ComputeAbsoluteSize(
- border_padding_size, child_minmax, margin_percentage_resolution_size,
+ border_padding_size, min_max_sizes, margin_percentage_resolution_size,
available_size, margin_start_length, margin_end_length,
inset_start_length, inset_end_length, min_size, max_size,
static_position_offset, static_position_edge, is_start_dominant,
@@ -334,7 +334,7 @@ bool AbsoluteNeedsChildBlockSize(const ComputedStyle& style) {
return is_logical_height_intrinsic ||
style.LogicalMinHeight().IsIntrinsic() ||
style.LogicalMaxHeight().IsIntrinsic() ||
- (IsLogicalHeightTreatAsAuto(style) &&
+ (IsLogicalHeightTreatedAsAuto(style) &&
(style.LogicalTop().IsAuto() || style.LogicalBottom().IsAuto()));
}
@@ -382,30 +382,31 @@ base::Optional<LayoutUnit> ComputeAbsoluteDialogYPosition(
return top;
}
-NGLogicalOutOfFlowPosition ComputePartialAbsoluteWithChildInlineSize(
+void ComputeOutOfFlowInlineDimensions(
const NGConstraintSpace& space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const NGLogicalStaticPosition& static_position,
- const base::Optional<MinMaxSize>& child_minmax,
+ const base::Optional<MinMaxSizes>& min_max_sizes,
const base::Optional<LogicalSize>& replaced_size,
const WritingMode container_writing_mode,
- const TextDirection container_direction) {
- NGLogicalOutOfFlowPosition position;
+ const TextDirection container_direction,
+ NGLogicalOutOfFlowDimensions* dimensions) {
+ DCHECK(dimensions);
base::Optional<LayoutUnit> inline_size;
if (!IsLogicalWidthTreatedAsAuto(style)) {
inline_size = ResolveMainInlineLength(space, style, border_padding,
- child_minmax, style.LogicalWidth());
+ min_max_sizes, style.LogicalWidth());
} else if (replaced_size.has_value()) {
inline_size = replaced_size->inline_size;
}
LayoutUnit min_inline_size = ResolveMinInlineLength(
- space, style, border_padding, child_minmax, style.LogicalMinWidth(),
+ space, style, border_padding, min_max_sizes, style.LogicalMinWidth(),
LengthResolvePhase::kLayout);
LayoutUnit max_inline_size = ResolveMaxInlineLength(
- space, style, border_padding, child_minmax, style.LogicalMaxWidth(),
+ space, style, border_padding, min_max_sizes, style.LogicalMaxWidth(),
LengthResolvePhase::kLayout);
// Tables use the inline-size as a minimum.
@@ -413,7 +414,7 @@ NGLogicalOutOfFlowPosition ComputePartialAbsoluteWithChildInlineSize(
min_inline_size =
std::max(min_inline_size,
ResolveMainInlineLength(space, style, border_padding,
- child_minmax, style.LogicalWidth()));
+ min_max_sizes, style.LogicalWidth()));
}
bool is_start_dominant;
@@ -428,20 +429,19 @@ NGLogicalOutOfFlowPosition ComputePartialAbsoluteWithChildInlineSize(
}
ComputeAbsoluteSize(
- border_padding.InlineSum(), child_minmax,
+ border_padding.InlineSum(), min_max_sizes,
space.PercentageResolutionInlineSizeForParentWritingMode(),
space.AvailableSize().inline_size, style.MarginStart(), style.MarginEnd(),
style.LogicalInlineStart(), style.LogicalInlineEnd(), min_inline_size,
max_inline_size, static_position.offset.inline_offset,
GetStaticPositionEdge(static_position.inline_edge), is_start_dominant,
- false /* is_block_direction */, inline_size, &position.size.inline_size,
- &position.inset.inline_start, &position.inset.inline_end,
- &position.margins.inline_start, &position.margins.inline_end);
-
- return position;
+ false /* is_block_direction */, inline_size,
+ &dimensions->size.inline_size, &dimensions->inset.inline_start,
+ &dimensions->inset.inline_end, &dimensions->margins.inline_start,
+ &dimensions->margins.inline_end);
}
-void ComputeFullAbsoluteWithChildBlockSize(
+void ComputeOutOfFlowBlockDimensions(
const NGConstraintSpace& space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
@@ -450,20 +450,20 @@ void ComputeFullAbsoluteWithChildBlockSize(
const base::Optional<LogicalSize>& replaced_size,
const WritingMode container_writing_mode,
const TextDirection container_direction,
- NGLogicalOutOfFlowPosition* position) {
+ NGLogicalOutOfFlowDimensions* dimensions) {
// After partial size has been computed, child block size is either unknown,
// or fully computed, there is no minmax. To express this, a 'fixed' minmax
// is created where min and max are the same.
- base::Optional<MinMaxSize> child_minmax;
+ base::Optional<MinMaxSizes> min_max_sizes;
if (child_block_size.has_value()) {
- child_minmax = MinMaxSize{*child_block_size, *child_block_size};
+ min_max_sizes = MinMaxSizes{*child_block_size, *child_block_size};
}
LayoutUnit child_block_size_or_indefinite =
child_block_size.value_or(kIndefiniteSize);
base::Optional<LayoutUnit> block_size;
- if (!IsLogicalHeightTreatAsAuto(style)) {
+ if (!IsLogicalHeightTreatedAsAuto(style)) {
block_size = ResolveMainBlockLength(
space, style, border_padding, style.LogicalHeight(),
child_block_size_or_indefinite, LengthResolvePhase::kLayout);
@@ -473,10 +473,10 @@ void ComputeFullAbsoluteWithChildBlockSize(
LayoutUnit min_block_size = ResolveMinBlockLength(
space, style, border_padding, style.LogicalMinHeight(),
- child_block_size_or_indefinite, LengthResolvePhase::kLayout);
+ LengthResolvePhase::kLayout);
LayoutUnit max_block_size = ResolveMaxBlockLength(
space, style, border_padding, style.LogicalMaxHeight(),
- child_block_size_or_indefinite, LengthResolvePhase::kLayout);
+ LengthResolvePhase::kLayout);
bool is_start_dominant;
if (style.GetWritingMode() == WritingMode::kHorizontalTb) {
@@ -490,15 +490,15 @@ void ComputeFullAbsoluteWithChildBlockSize(
}
ComputeAbsoluteSize(
- border_padding.BlockSum(), child_minmax,
+ border_padding.BlockSum(), min_max_sizes,
space.PercentageResolutionInlineSizeForParentWritingMode(),
space.AvailableSize().block_size, style.MarginBefore(),
style.MarginAfter(), style.LogicalTop(), style.LogicalBottom(),
min_block_size, max_block_size, static_position.offset.block_offset,
GetStaticPositionEdge(static_position.block_edge), is_start_dominant,
- true /* is_block_direction */, block_size, &position->size.block_size,
- &position->inset.block_start, &position->inset.block_end,
- &position->margins.block_start, &position->margins.block_end);
+ true /* is_block_direction */, block_size, &dimensions->size.block_size,
+ &dimensions->inset.block_start, &dimensions->inset.block_end,
+ &dimensions->margins.block_start, &dimensions->margins.block_end);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h
index bcfa41fc6a7..5c2f3694cb8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h
@@ -9,7 +9,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
-#include "third_party/blink/renderer/core/layout/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
namespace blink {
@@ -19,7 +19,7 @@ class LayoutObject;
class NGConstraintSpace;
struct NGLogicalStaticPosition;
-struct CORE_EXPORT NGLogicalOutOfFlowPosition {
+struct CORE_EXPORT NGLogicalOutOfFlowDimensions {
NGBoxStrut inset;
LogicalSize size;
NGBoxStrut margins;
@@ -36,43 +36,43 @@ CORE_EXPORT base::Optional<LayoutUnit> ComputeAbsoluteDialogYPosition(
// The following routines implement the absolute size resolution algorithm.
// https://www.w3.org/TR/css-position-3/#abs-non-replaced-width
//
-// The size is computed as |NGLogicalOutOfFlowPosition|.
+// The size is computed as |NGLogicalOutOfFlowDimensions|.
// It needs to be computed in 4 stages:
// 1. If |AbsoluteNeedsChildInlineSize| is true, compute estimated inline_size
-// using |NGBlockNode::MinMaxSize|.
-// 2. Compute part of the |NGLogicalOutOfFlowPosition| which depends on the
-// child inline-size with |ComputePartialAbsoluteWithChildInlineSize|.
+// using |NGBlockNode::ComputeMinMaxSize|.
+// 2. Compute part of the |NGLogicalOutOfFlowDimensions| which depends on the
+// child inline-size with |ComputeOutOfFlowInlineDimensions|.
// 3. If |AbsoluteNeedsChildBlockSize| is true, compute estimated block_size by
// performing layout with the inline_size calculated from (2).
-// 4. Compute the full |NGLogicalOutOfFlowPosition| with
-// |ComputeFullAbsoluteWithChildBlockSize|.
+// 4. Compute the full |NGLogicalOutOfFlowDimensions| with
+// |ComputeOutOfFlowBlockDimensions|.
-// Returns true if |ComputePartialAbsoluteWithChildInlineSize| will need an
-// estimated inline-size.
+// Returns true if |ComputeOutOfFlowInlineDimensions| will need an estimated
+// inline-size.
CORE_EXPORT bool AbsoluteNeedsChildInlineSize(const ComputedStyle&);
-// Returns true if |ComputeFullAbsoluteWithChildBlockSize| will need an
-// estimated block-size.
+// Returns true if |ComputeOutOfFlowBlockDimensions| will need an estimated
+// block-size.
CORE_EXPORT bool AbsoluteNeedsChildBlockSize(const ComputedStyle&);
// Computes part of the absolute position which depends on the child's
// inline-size.
// |replaced_size| should be set if and only if element is replaced element.
// Returns the partially filled position.
-CORE_EXPORT NGLogicalOutOfFlowPosition
-ComputePartialAbsoluteWithChildInlineSize(
+CORE_EXPORT void ComputeOutOfFlowInlineDimensions(
const NGConstraintSpace&,
const ComputedStyle&,
const NGBoxStrut& border_padding,
const NGLogicalStaticPosition&,
- const base::Optional<MinMaxSize>& child_minmax,
+ const base::Optional<MinMaxSizes>& child_minmax,
const base::Optional<LogicalSize>& replaced_size,
const WritingMode container_writing_mode,
- const TextDirection container_direction);
+ const TextDirection container_direction,
+ NGLogicalOutOfFlowDimensions* dimensions);
// Computes the rest of the absolute position which depends on child's
// block-size.
-CORE_EXPORT void ComputeFullAbsoluteWithChildBlockSize(
+CORE_EXPORT void ComputeOutOfFlowBlockDimensions(
const NGConstraintSpace&,
const ComputedStyle&,
const NGBoxStrut& border_padding,
@@ -81,7 +81,7 @@ CORE_EXPORT void ComputeFullAbsoluteWithChildBlockSize(
const base::Optional<LogicalSize>& replaced_size,
const WritingMode container_writing_mode,
const TextDirection container_direction,
- NGLogicalOutOfFlowPosition* position);
+ NGLogicalOutOfFlowDimensions* dimensions);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils_test.cc
index 86af90137d8..dac7b8f79c4 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils_test.cc
@@ -118,10 +118,10 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
LayoutUnit width =
container_size_.inline_size - left - margin_left - right - margin_right;
- base::Optional<MinMaxSize> estimated_inline;
+ base::Optional<MinMaxSizes> estimated_inline;
base::Optional<LayoutUnit> estimated_block;
- MinMaxSize minmax_60{LayoutUnit(60) + horizontal_border_padding,
- LayoutUnit(60) + horizontal_border_padding};
+ MinMaxSizes min_max_60{LayoutUnit(60) + horizontal_border_padding,
+ LayoutUnit(60) + horizontal_border_padding};
style_->SetBorderLeftWidth(border_left.ToInt());
style_->SetBorderRightWidth(border_right.ToInt());
@@ -154,151 +154,154 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
// Tests.
//
- NGLogicalOutOfFlowPosition p;
+ NGLogicalOutOfFlowDimensions dimensions;
// All auto => width is estimated_inline, left is 0.
SetHorizontalStyle(NGAuto, NGAuto, NGAuto, NGAuto, NGAuto);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), true);
- estimated_inline = minmax_60;
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(minmax_60.min_size, p.size.inline_size);
- EXPECT_EQ(LayoutUnit(0), p.inset.inline_start);
+ estimated_inline = min_max_60;
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(min_max_60.min_size, dimensions.size.inline_size);
+ EXPECT_EQ(LayoutUnit(0), dimensions.inset.inline_start);
// All auto => width is estimated_inline, static_position is right
SetHorizontalStyle(NGAuto, NGAuto, NGAuto, NGAuto, NGAuto);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), true);
- estimated_inline = minmax_60;
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position_inline_end,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(minmax_60.min_size, p.size.inline_size);
- EXPECT_EQ(container_size_.inline_size, p.inset.inline_end);
+ estimated_inline = min_max_60;
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position_inline_end, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(min_max_60.min_size, dimensions.size.inline_size);
+ EXPECT_EQ(container_size_.inline_size, dimensions.inset.inline_end);
// All auto + RTL.
- p = ComputePartialAbsoluteWithChildInlineSize(
- rtl_space_, *style_, rtl_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(minmax_60.min_size, p.size.inline_size);
- EXPECT_EQ(container_size_.inline_size - minmax_60.min_size,
- p.inset.inline_end);
+ ComputeOutOfFlowInlineDimensions(rtl_space_, *style_, rtl_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(min_max_60.min_size, dimensions.size.inline_size);
+ EXPECT_EQ(container_size_.inline_size - min_max_60.min_size,
+ dimensions.inset.inline_end);
// left, right, and left are known, compute margins.
SetHorizontalStyle(left, NGAuto, width, NGAuto, right);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- LayoutUnit margin_space =
- (container_size_.inline_size - left - right - p.size.inline_size) / 2;
- EXPECT_EQ(left + margin_space, p.inset.inline_start);
- EXPECT_EQ(right + margin_space, p.inset.inline_end);
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ LayoutUnit margin_space = (container_size_.inline_size - left - right -
+ dimensions.size.inline_size) /
+ 2;
+ EXPECT_EQ(left + margin_space, dimensions.inset.inline_start);
+ EXPECT_EQ(right + margin_space, dimensions.inset.inline_end);
// left, right, and left are known, compute margins, writing mode vertical_lr.
SetHorizontalStyle(left, NGAuto, width, NGAuto, right,
WritingMode::kVerticalLr);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
estimated_inline.reset();
- ComputeFullAbsoluteWithChildBlockSize(
- vlr_space_, *style_, vlr_border_padding, static_position, estimated_block,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(left + margin_space, p.inset.block_start);
- EXPECT_EQ(right + margin_space, p.inset.block_end);
+ ComputeOutOfFlowBlockDimensions(vlr_space_, *style_, vlr_border_padding,
+ static_position, estimated_block,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(left + margin_space, dimensions.inset.block_start);
+ EXPECT_EQ(right + margin_space, dimensions.inset.block_end);
// left, right, and left are known, compute margins, writing mode vertical_rl.
SetHorizontalStyle(left, NGAuto, width, NGAuto, right,
WritingMode::kVerticalRl);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
estimated_inline.reset();
- ComputeFullAbsoluteWithChildBlockSize(
- vrl_space_, *style_, vrl_border_padding, static_position, estimated_block,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(left + margin_space, p.inset.block_end);
- EXPECT_EQ(right + margin_space, p.inset.block_start);
+ ComputeOutOfFlowBlockDimensions(vrl_space_, *style_, vrl_border_padding,
+ static_position, estimated_block,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(left + margin_space, dimensions.inset.block_end);
+ EXPECT_EQ(right + margin_space, dimensions.inset.block_start);
// left, right, and width are known, not enough space for margins LTR.
SetHorizontalStyle(left, NGAuto, LayoutUnit(200), NGAuto, right);
estimated_inline.reset();
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(left, p.inset.inline_start);
- EXPECT_EQ(-left, p.inset.inline_end);
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(left, dimensions.inset.inline_start);
+ EXPECT_EQ(-left, dimensions.inset.inline_end);
// left, right, and left are known, not enough space for margins RTL.
SetHorizontalStyle(left, NGAuto, LayoutUnit(200), NGAuto, right,
WritingMode::kHorizontalTb);
estimated_inline.reset();
- p = ComputePartialAbsoluteWithChildInlineSize(
- rtl_space_, *style_, rtl_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kRtl);
- EXPECT_EQ(-right, p.inset.inline_start);
- EXPECT_EQ(right, p.inset.inline_end);
+ ComputeOutOfFlowInlineDimensions(rtl_space_, *style_, rtl_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kRtl, &dimensions);
+ EXPECT_EQ(-right, dimensions.inset.inline_start);
+ EXPECT_EQ(right, dimensions.inset.inline_end);
// Rule 1 left and width are auto.
SetHorizontalStyle(NGAuto, margin_left, NGAuto, margin_right, right);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), true);
- estimated_inline = minmax_60;
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(minmax_60.min_size, p.size.inline_size);
+ estimated_inline = min_max_60;
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(min_max_60.min_size, dimensions.size.inline_size);
// Rule 2 left and right are auto LTR.
SetHorizontalStyle(NGAuto, margin_left, width, margin_right, NGAuto);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(margin_left, p.inset.inline_start);
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(margin_left, dimensions.inset.inline_start);
EXPECT_EQ(container_size_.inline_size - margin_left - width,
- p.inset.inline_end);
+ dimensions.inset.inline_end);
// Rule 2 left and right are auto RTL.
SetHorizontalStyle(NGAuto, margin_left, width, margin_right, NGAuto);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
- p = ComputePartialAbsoluteWithChildInlineSize(
- rtl_space_, *style_, rtl_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(margin_left, p.inset.inline_start);
+ ComputeOutOfFlowInlineDimensions(rtl_space_, *style_, rtl_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(margin_left, dimensions.inset.inline_start);
EXPECT_EQ(container_size_.inline_size - margin_left - width,
- p.inset.inline_end);
+ dimensions.inset.inline_end);
// Rule 3 width and right are auto.
SetHorizontalStyle(left, margin_left, NGAuto, margin_right, NGAuto);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), true);
- estimated_inline = minmax_60;
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
+ estimated_inline = min_max_60;
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
EXPECT_EQ(
- container_size_.inline_size - minmax_60.min_size - left - margin_left,
- p.inset.inline_end);
- EXPECT_EQ(minmax_60.min_size, p.size.inline_size);
+ container_size_.inline_size - min_max_60.min_size - left - margin_left,
+ dimensions.inset.inline_end);
+ EXPECT_EQ(min_max_60.min_size, dimensions.size.inline_size);
// Rule 4: left is auto.
SetHorizontalStyle(NGAuto, margin_left, width, margin_right, right);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(left + margin_left, p.inset.inline_start);
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(left + margin_left, dimensions.inset.inline_start);
// Rule 4: left is auto, EBoxSizing::kContentBox
style_->SetBoxSizing(EBoxSizing::kContentBox);
@@ -307,32 +310,32 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
margin_right, right);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(left + margin_left, p.inset.inline_start);
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(left + margin_left, dimensions.inset.inline_start);
style_->SetBoxSizing(EBoxSizing::kBorderBox);
// Rule 5: right is auto.
SetHorizontalStyle(left, margin_left, width, margin_right, NGAuto);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(right + margin_right, p.inset.inline_end);
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(right + margin_right, dimensions.inset.inline_end);
// Rule 6: width is auto.
SetHorizontalStyle(left, margin_left, NGAuto, margin_right, right);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(width, p.size.inline_size);
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(width, dimensions.size.inline_size);
}
TEST_F(NGAbsoluteUtilsTest, Vertical) {
@@ -365,7 +368,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
style_->SetBorderRightWidth(0);
base::Optional<LayoutUnit> auto_height;
- MinMaxSize minmax_60{LayoutUnit(60), LayoutUnit(60)};
+ MinMaxSizes min_max_60{LayoutUnit(60), LayoutUnit(60)};
NGBoxStrut ltr_border_padding =
ComputeBordersForTest(*style_) + ComputePadding(ltr_space_, *style_);
@@ -387,133 +390,145 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
// Tests
//
- NGLogicalOutOfFlowPosition p;
+ NGLogicalOutOfFlowDimensions dimensions;
// All auto, compute margins.
SetVerticalStyle(NGAuto, NGAuto, NGAuto, NGAuto, NGAuto);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), true);
auto_height = LayoutUnit(60);
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(*auto_height, p.size.block_size);
- EXPECT_EQ(LayoutUnit(0), p.inset.block_start);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(*auto_height, dimensions.size.block_size);
+ EXPECT_EQ(LayoutUnit(0), dimensions.inset.block_start);
// All auto, static position bottom
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position_block_end,
- auto_height, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr, &p);
- EXPECT_EQ(container_size_.block_size, p.inset.block_end);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position_block_end, auto_height,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(container_size_.block_size, dimensions.inset.block_end);
// If top, bottom, and height are known, compute margins.
SetVerticalStyle(top, NGAuto, height, NGAuto, bottom);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
auto_height.reset();
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
LayoutUnit margin_space =
(container_size_.block_size - top - height - bottom) / 2;
- EXPECT_EQ(top + margin_space, p.inset.block_start);
- EXPECT_EQ(bottom + margin_space, p.inset.block_end);
+ EXPECT_EQ(top + margin_space, dimensions.inset.block_start);
+ EXPECT_EQ(bottom + margin_space, dimensions.inset.block_end);
// If top, bottom, and height are known, writing mode vertical_lr.
SetVerticalStyle(top, NGAuto, height, NGAuto, bottom,
WritingMode::kVerticalLr);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
- p = ComputePartialAbsoluteWithChildInlineSize(
- vlr_space_, *style_, vlr_border_padding, static_position, minmax_60,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr);
- EXPECT_EQ(top + margin_space, p.inset.inline_start);
- EXPECT_EQ(bottom + margin_space, p.inset.inline_end);
+ ComputeOutOfFlowInlineDimensions(vlr_space_, *style_, vlr_border_padding,
+ static_position, min_max_60, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(top + margin_space, dimensions.inset.inline_start);
+ EXPECT_EQ(bottom + margin_space, dimensions.inset.inline_end);
// If top, bottom, and height are known, writing mode vertical_rl.
SetVerticalStyle(top, NGAuto, height, NGAuto, bottom,
WritingMode::kVerticalRl);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
- p = ComputePartialAbsoluteWithChildInlineSize(
- vrl_space_, *style_, vrl_border_padding, static_position, minmax_60,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr);
- EXPECT_EQ(top + margin_space, p.inset.inline_start);
- EXPECT_EQ(bottom + margin_space, p.inset.inline_end);
+ ComputeOutOfFlowInlineDimensions(vrl_space_, *style_, vrl_border_padding,
+ static_position, min_max_60, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(top + margin_space, dimensions.inset.inline_start);
+ EXPECT_EQ(bottom + margin_space, dimensions.inset.inline_end);
// If top, bottom, and height are known, negative auto margins.
LayoutUnit negative_margin_space =
(container_size_.block_size - top - LayoutUnit(300) - bottom) / 2;
SetVerticalStyle(top, NGAuto, LayoutUnit(300), NGAuto, bottom);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(top + negative_margin_space, p.inset.block_start);
- EXPECT_EQ(bottom + negative_margin_space, p.inset.block_end);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(top + negative_margin_space, dimensions.inset.block_start);
+ EXPECT_EQ(bottom + negative_margin_space, dimensions.inset.block_end);
// Rule 1: top and height are unknown.
SetVerticalStyle(NGAuto, margin_top, NGAuto, margin_bottom, bottom);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), true);
auto_height = LayoutUnit(60);
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(*auto_height, p.size.block_size);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(*auto_height, dimensions.size.block_size);
// Rule 2: top and bottom are unknown.
SetVerticalStyle(NGAuto, margin_top, height, margin_bottom, NGAuto);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
auto_height.reset();
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(margin_top, p.inset.block_start);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(margin_top, dimensions.inset.block_start);
EXPECT_EQ(container_size_.block_size - margin_top - height,
- p.inset.block_end);
+ dimensions.inset.block_end);
// Rule 3: height and bottom are unknown, auto_height <
// horizontal_border_padding.
SetVerticalStyle(top, margin_top, NGAuto, margin_bottom, NGAuto);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), true);
auto_height = LayoutUnit(20);
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(horizontal_border_padding, p.size.block_size);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(horizontal_border_padding, dimensions.size.block_size);
// Rule 3: height and bottom are unknown.
SetVerticalStyle(top, margin_top, NGAuto, margin_bottom, NGAuto);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), true);
auto_height = LayoutUnit(70);
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(*auto_height, p.size.block_size);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(*auto_height, dimensions.size.block_size);
// Rule 4: top is unknown.
SetVerticalStyle(NGAuto, margin_top, height, margin_bottom, bottom);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
auto_height.reset();
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(top + margin_top, p.inset.block_start);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(top + margin_top, dimensions.inset.block_start);
// Rule 5: bottom is unknown.
SetVerticalStyle(top, margin_top, height, margin_bottom, NGAuto);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
auto_height.reset();
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(bottom + margin_bottom, p.inset.block_end);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(bottom + margin_bottom, dimensions.inset.block_end);
// Rule 6: height is unknown.
SetVerticalStyle(top, margin_top, NGAuto, margin_bottom, bottom);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
auto_height.reset();
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(height, p.size.block_size);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(height, dimensions.size.block_size);
}
TEST_F(NGAbsoluteUtilsTest, CenterStaticPosition) {
@@ -529,28 +544,31 @@ TEST_F(NGAbsoluteUtilsTest, CenterStaticPosition) {
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), true);
NGBoxStrut border_padding;
- NGLogicalOutOfFlowPosition p = ComputePartialAbsoluteWithChildInlineSize(
+ NGLogicalOutOfFlowDimensions dimensions;
+
+ ComputeOutOfFlowInlineDimensions(
ltr_space_, *style_, border_padding, static_position,
- MinMaxSize{LayoutUnit(), LayoutUnit(1000)}, base::nullopt,
- WritingMode::kHorizontalTb, TextDirection::kLtr);
- EXPECT_EQ(LayoutUnit(100), p.size.inline_size);
- EXPECT_EQ(LayoutUnit(100), p.inset.inline_start);
- EXPECT_EQ(LayoutUnit(), p.inset.inline_end);
+ MinMaxSizes{LayoutUnit(), LayoutUnit(1000)}, base::nullopt,
+ WritingMode::kHorizontalTb, TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(LayoutUnit(100), dimensions.size.inline_size);
+ EXPECT_EQ(LayoutUnit(100), dimensions.inset.inline_start);
+ EXPECT_EQ(LayoutUnit(), dimensions.inset.inline_end);
- p = ComputePartialAbsoluteWithChildInlineSize(
+ ComputeOutOfFlowInlineDimensions(
ltr_space_, *style_, border_padding, static_position,
- MinMaxSize{LayoutUnit(), LayoutUnit(1000)}, base::nullopt,
- WritingMode::kHorizontalTb, TextDirection::kRtl);
- EXPECT_EQ(LayoutUnit(100), p.size.inline_size);
- EXPECT_EQ(LayoutUnit(100), p.inset.inline_start);
- EXPECT_EQ(LayoutUnit(), p.inset.inline_end);
-
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, border_padding, static_position, LayoutUnit(150),
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(LayoutUnit(150), p.size.block_size);
- EXPECT_EQ(LayoutUnit(125), p.inset.block_start);
- EXPECT_EQ(LayoutUnit(25), p.inset.block_end);
+ MinMaxSizes{LayoutUnit(), LayoutUnit(1000)}, base::nullopt,
+ WritingMode::kHorizontalTb, TextDirection::kRtl, &dimensions);
+ EXPECT_EQ(LayoutUnit(100), dimensions.size.inline_size);
+ EXPECT_EQ(LayoutUnit(100), dimensions.inset.inline_start);
+ EXPECT_EQ(LayoutUnit(), dimensions.inset.inline_end);
+
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, border_padding,
+ static_position, LayoutUnit(150),
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(LayoutUnit(150), dimensions.size.block_size);
+ EXPECT_EQ(LayoutUnit(125), dimensions.inset.block_start);
+ EXPECT_EQ(LayoutUnit(25), dimensions.inset.block_end);
}
TEST_F(NGAbsoluteUtilsTest, MinMax) {
@@ -569,34 +587,34 @@ TEST_F(NGAbsoluteUtilsTest, MinMax) {
{LayoutUnit(), LayoutUnit()},
NGLogicalStaticPosition::kInlineStart,
NGLogicalStaticPosition::kBlockStart};
- MinMaxSize estimated_inline{LayoutUnit(20), LayoutUnit(20)};
- NGLogicalOutOfFlowPosition p;
+ MinMaxSizes estimated_inline{LayoutUnit(20), LayoutUnit(20)};
+ NGLogicalOutOfFlowDimensions dimensions;
// WIDTH TESTS
// width < min gets set to min.
SetHorizontalStyle(NGAuto, NGAuto, LayoutUnit(5), NGAuto, NGAuto);
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(min, p.size.inline_size);
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(min, dimensions.size.inline_size);
// width > max gets set to max.
SetHorizontalStyle(NGAuto, NGAuto, LayoutUnit(200), NGAuto, NGAuto);
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(max, p.size.inline_size);
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(max, dimensions.size.inline_size);
- // Unspecified width becomes minmax, gets clamped to min.
+ // Unspecified width becomes min_max, gets clamped to min.
SetHorizontalStyle(NGAuto, NGAuto, NGAuto, NGAuto, NGAuto);
- p = ComputePartialAbsoluteWithChildInlineSize(
- ltr_space_, *style_, ltr_border_padding, static_position,
- estimated_inline, base::nullopt, WritingMode::kHorizontalTb,
- TextDirection::kLtr);
- EXPECT_EQ(min, p.size.inline_size);
+ ComputeOutOfFlowInlineDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, estimated_inline,
+ base::nullopt, WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(min, dimensions.size.inline_size);
// HEIGHT TESTS
@@ -604,25 +622,28 @@ TEST_F(NGAbsoluteUtilsTest, MinMax) {
// height < min gets set to min.
SetVerticalStyle(NGAuto, NGAuto, LayoutUnit(5), NGAuto, NGAuto);
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(min, p.size.block_size);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(min, dimensions.size.block_size);
// height > max gets set to max.
SetVerticalStyle(NGAuto, NGAuto, LayoutUnit(200), NGAuto, NGAuto);
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(max, p.size.block_size);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(max, dimensions.size.block_size);
// // Unspecified height becomes estimated, gets clamped to min.
SetVerticalStyle(NGAuto, NGAuto, NGAuto, NGAuto, NGAuto);
auto_height = LayoutUnit(20);
- ComputeFullAbsoluteWithChildBlockSize(
- ltr_space_, *style_, ltr_border_padding, static_position, auto_height,
- base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
- EXPECT_EQ(min, p.size.block_size);
+ ComputeOutOfFlowBlockDimensions(ltr_space_, *style_, ltr_border_padding,
+ static_position, auto_height, base::nullopt,
+ WritingMode::kHorizontalTb,
+ TextDirection::kLtr, &dimensions);
+ EXPECT_EQ(min, dimensions.size.block_size);
}
} // namespace
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc
index 7f919d2599f..1ddab49c2b9 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.cc
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
@@ -49,8 +50,8 @@ std::pair<scoped_refptr<const NGPhysicalBoxFragment>, NGConstraintSpace>
NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithmForElement(Element* element) {
auto* block_flow = To<LayoutBlockFlow>(element->GetLayoutObject());
NGBlockNode node(block_flow);
- NGConstraintSpace space = NGConstraintSpace::CreateFromLayoutObject(
- *block_flow, false /* is_layout_root */);
+ NGConstraintSpace space =
+ NGConstraintSpace::CreateFromLayoutObject(*block_flow);
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
@@ -61,6 +62,22 @@ NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithmForElement(Element* element) {
}
scoped_refptr<const NGPhysicalBoxFragment>
+NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ NGBlockNode node,
+ const NGConstraintSpace& space,
+ const NGBreakToken* break_token) {
+ NGFragmentGeometry fragment_geometry =
+ CalculateInitialFragmentGeometry(space, node);
+
+ scoped_refptr<const NGLayoutResult> result =
+ NGFieldsetLayoutAlgorithm(
+ {node, fragment_geometry, space, To<NGBlockBreakToken>(break_token)})
+ .Layout();
+
+ return To<NGPhysicalBoxFragment>(&result->PhysicalFragment());
+}
+
+scoped_refptr<const NGPhysicalBoxFragment>
NGBaseLayoutAlgorithmTest::GetBoxFragmentByElementId(const char* id) {
LayoutObject* layout_object = GetLayoutObjectByElementId(id);
CHECK(layout_object && layout_object->IsLayoutNGMixin());
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h
index 702637ee1bb..9f9fe176151 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h
@@ -41,6 +41,11 @@ class NGBaseLayoutAlgorithmTest
std::pair<scoped_refptr<const NGPhysicalBoxFragment>, NGConstraintSpace>
RunBlockLayoutAlgorithmForElement(Element* element);
+ scoped_refptr<const NGPhysicalBoxFragment> RunFieldsetLayoutAlgorithm(
+ NGBlockNode node,
+ const NGConstraintSpace& space,
+ const NGBreakToken* break_token = nullptr);
+
scoped_refptr<const NGPhysicalBoxFragment> GetBoxFragmentByElementId(
const char*);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc
index 6e9781b9bdf..eea8efbb3da 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.cc
@@ -12,7 +12,7 @@ namespace blink {
namespace {
struct SameSizeAsNGBlockBreakToken : NGBreakToken {
- unsigned numbers[2];
+ unsigned numbers[3];
};
static_assert(sizeof(NGBlockBreakToken) == sizeof(SameSizeAsNGBlockBreakToken),
@@ -21,13 +21,16 @@ static_assert(sizeof(NGBlockBreakToken) == sizeof(SameSizeAsNGBlockBreakToken),
} // namespace
NGBlockBreakToken::NGBlockBreakToken(
+ PassKey key,
NGLayoutInputNode node,
LayoutUnit consumed_block_size,
+ unsigned sequence_number,
const NGBreakTokenVector& child_break_tokens,
NGBreakAppeal break_appeal,
bool has_seen_all_children)
: NGBreakToken(kBlockBreakToken, kUnfinished, node),
consumed_block_size_(consumed_block_size),
+ sequence_number_(sequence_number),
num_children_(child_break_tokens.size()) {
break_appeal_ = break_appeal;
has_seen_all_children_ = has_seen_all_children;
@@ -37,7 +40,7 @@ NGBlockBreakToken::NGBlockBreakToken(
}
}
-NGBlockBreakToken::NGBlockBreakToken(NGLayoutInputNode node)
+NGBlockBreakToken::NGBlockBreakToken(PassKey key, NGLayoutInputNode node)
: NGBreakToken(kBlockBreakToken, kUnfinished, node), num_children_(0) {}
const NGInlineBreakToken* NGBlockBreakToken::InlineBreakTokenFor(
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
index fc5ab4ba485..ee2bcc92fba 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_break_token.h
@@ -27,6 +27,7 @@ class CORE_EXPORT NGBlockBreakToken final : public NGBreakToken {
static scoped_refptr<NGBlockBreakToken> Create(
NGLayoutInputNode node,
LayoutUnit consumed_block_size,
+ unsigned sequence_number,
const NGBreakTokenVector& child_break_tokens,
NGBreakAppeal break_appeal,
bool has_seen_all_children) {
@@ -37,7 +38,8 @@ class CORE_EXPORT NGBlockBreakToken final : public NGBreakToken {
sizeof(NGBlockBreakToken) +
child_break_tokens.size() * sizeof(NGBreakToken*),
::WTF::GetStringWithTypeName<NGBlockBreakToken>());
- new (data) NGBlockBreakToken(node, consumed_block_size, child_break_tokens,
+ new (data) NGBlockBreakToken(PassKey(), node, consumed_block_size,
+ sequence_number, child_break_tokens,
break_appeal, has_seen_all_children);
return base::AdoptRef(static_cast<NGBlockBreakToken*>(data));
}
@@ -48,7 +50,7 @@ class CORE_EXPORT NGBlockBreakToken final : public NGBreakToken {
static scoped_refptr<NGBlockBreakToken> CreateBreakBefore(
NGLayoutInputNode node,
bool is_forced_break) {
- auto* token = new NGBlockBreakToken(node);
+ auto* token = new NGBlockBreakToken(PassKey(), node);
token->is_break_before_ = true;
token->is_forced_break_ = is_forced_break;
return base::AdoptRef(token);
@@ -68,6 +70,17 @@ class CORE_EXPORT NGBlockBreakToken final : public NGBreakToken {
// the fragmentainer is shorter than 50px, for instance).
LayoutUnit ConsumedBlockSize() const { return consumed_block_size_; }
+ // A unique identifier for a fragment that generates a break token. This is
+ // unique within the generating layout input node. The break token of the
+ // first fragment gets 0, then second 1, and so on. Note that we don't "count"
+ // break tokens that aren't associated with a fragment (this happens when we
+ // want a fragmentainer break before laying out the node). What the sequence
+ // number is for such a break token is undefined.
+ unsigned SequenceNumber() const {
+ DCHECK(!IsBreakBefore());
+ return sequence_number_;
+ }
+
// Return true if this is a break token that was produced without any
// "preceding" fragment. This happens when we determine that the first
// fragment for a node needs to be created in a later fragmentainer than the
@@ -102,18 +115,23 @@ class CORE_EXPORT NGBlockBreakToken final : public NGBreakToken {
String ToString() const override;
#endif
- private:
+ using PassKey = util::PassKey<NGBlockBreakToken>;
+
// Must only be called from Create(), because it assumes that enough space
// has been allocated in the flexible array to store the children.
- NGBlockBreakToken(NGLayoutInputNode node,
+ NGBlockBreakToken(PassKey,
+ NGLayoutInputNode node,
LayoutUnit consumed_block_size,
+ unsigned sequence_number,
const NGBreakTokenVector& child_break_tokens,
NGBreakAppeal break_appeal,
bool has_seen_all_children);
- explicit NGBlockBreakToken(NGLayoutInputNode node);
+ explicit NGBlockBreakToken(PassKey, NGLayoutInputNode node);
+ private:
LayoutUnit consumed_block_size_;
+ unsigned sequence_number_ = 0;
wtf_size_t num_children_;
// This must be the last member, because it is a flexible array.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_child_iterator_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_child_iterator_test.cc
index 917eb7864f5..01b46282762 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_child_iterator_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_child_iterator_test.cc
@@ -58,19 +58,19 @@ TEST_F(NGBlockChildIteratorTest, BreakTokens) {
NGBreakTokenVector empty_tokens_list;
scoped_refptr<NGBreakToken> child_token1 = NGBlockBreakToken::Create(
- node1, LayoutUnit(), empty_tokens_list, kBreakAppealPerfect,
+ node1, LayoutUnit(), 0, empty_tokens_list, kBreakAppealPerfect,
/* has_seen_all_children */ false);
scoped_refptr<NGBreakToken> child_token2 = NGBlockBreakToken::Create(
- node2, LayoutUnit(), empty_tokens_list, kBreakAppealPerfect,
+ node2, LayoutUnit(), 0, empty_tokens_list, kBreakAppealPerfect,
/* has_seen_all_children */ false);
scoped_refptr<NGBreakToken> child_token3 = NGBlockBreakToken::Create(
- node3, LayoutUnit(), empty_tokens_list, kBreakAppealPerfect,
+ node3, LayoutUnit(), 0, empty_tokens_list, kBreakAppealPerfect,
/* has_seen_all_children */ false);
NGBreakTokenVector child_break_tokens;
child_break_tokens.push_back(child_token1);
scoped_refptr<NGBlockBreakToken> parent_token = NGBlockBreakToken::Create(
- container, LayoutUnit(), child_break_tokens, kBreakAppealPerfect,
+ container, LayoutUnit(), 0, child_break_tokens, kBreakAppealPerfect,
/* has_seen_all_children */ false);
NGBlockChildIterator iterator(node1, parent_token.get());
@@ -86,7 +86,7 @@ TEST_F(NGBlockChildIteratorTest, BreakTokens) {
child_break_tokens.push_back(child_token1);
child_break_tokens.push_back(child_token2);
parent_token = NGBlockBreakToken::Create(
- container, LayoutUnit(), child_break_tokens, kBreakAppealPerfect,
+ container, LayoutUnit(), 0, child_break_tokens, kBreakAppealPerfect,
/* has_seen_all_children */ false);
iterator = NGBlockChildIterator(node1, parent_token.get());
@@ -103,7 +103,7 @@ TEST_F(NGBlockChildIteratorTest, BreakTokens) {
child_break_tokens.push_back(child_token2);
child_break_tokens.push_back(child_token3);
parent_token = NGBlockBreakToken::Create(
- container, LayoutUnit(), child_break_tokens, kBreakAppealPerfect,
+ container, LayoutUnit(), 0, child_break_tokens, kBreakAppealPerfect,
/* has_seen_all_children */ false);
iterator = NGBlockChildIterator(node1, parent_token.get());
@@ -119,7 +119,7 @@ TEST_F(NGBlockChildIteratorTest, BreakTokens) {
child_break_tokens.push_back(child_token1);
child_break_tokens.push_back(child_token3);
parent_token = NGBlockBreakToken::Create(
- container, LayoutUnit(), child_break_tokens, kBreakAppealPerfect,
+ container, LayoutUnit(), 0, child_break_tokens, kBreakAppealPerfect,
/* has_seen_all_children */ false);
iterator = NGBlockChildIterator(node1, parent_token.get());
@@ -145,13 +145,13 @@ TEST_F(NGBlockChildIteratorTest, SeenAllChildren) {
NGBreakTokenVector empty_tokens_list;
scoped_refptr<NGBreakToken> child_token1 = NGBlockBreakToken::Create(
- node1, LayoutUnit(), empty_tokens_list, kBreakAppealPerfect,
+ node1, LayoutUnit(), 0, empty_tokens_list, kBreakAppealPerfect,
/* has_seen_all_children */ false);
NGBreakTokenVector child_break_tokens;
child_break_tokens.push_back(child_token1);
scoped_refptr<NGBlockBreakToken> parent_token = NGBlockBreakToken::Create(
- container, LayoutUnit(), child_break_tokens, kBreakAppealPerfect,
+ container, LayoutUnit(), 0, child_break_tokens, kBreakAppealPerfect,
/* has_seen_all_children */ true);
// We have a break token for #child1, but have seen all children. This happens
@@ -166,7 +166,7 @@ TEST_F(NGBlockChildIteratorTest, SeenAllChildren) {
child_break_tokens.clear();
parent_token = NGBlockBreakToken::Create(
- container, LayoutUnit(), child_break_tokens, kBreakAppealPerfect,
+ container, LayoutUnit(), 0, child_break_tokens, kBreakAppealPerfect,
/* has_seen_all_children */ true);
// We have no break tokens, but have seen all children. This happens e.g. when
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
index ec88e7d665b..9d0e5660942 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc
@@ -16,6 +16,7 @@
#include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_child_iterator.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
@@ -30,7 +31,6 @@
#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
-#include "third_party/blink/renderer/core/layout/text_autosizer.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
@@ -53,7 +53,8 @@ inline scoped_refptr<const NGLayoutResult> LayoutBlockChild(
// child.
DCHECK(early_break_in_child);
}
- return node->Layout(space, break_token, early_break_in_child);
+ return node->Layout(space, To<NGBlockBreakToken>(break_token),
+ early_break_in_child);
}
inline scoped_refptr<const NGLayoutResult> LayoutInflow(
@@ -180,6 +181,8 @@ NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(
params.fragment_geometry.scrollbar),
is_resuming_(IsResumingLayout(params.break_token)),
exclusion_space_(params.space.ExclusionSpace()),
+ lines_until_clamp_(params.space.LinesUntilClamp()),
+ force_truncate_at_line_clamp_(params.space.ForceTruncateAtLineClamp()),
early_break_(params.early_break) {
AdjustForFragmentation(BreakToken(), &border_scrollbar_padding_);
container_builder_.SetIsNewFormattingContext(
@@ -195,10 +198,10 @@ void NGBlockLayoutAlgorithm::SetBoxType(NGPhysicalFragment::NGBoxType type) {
container_builder_.SetBoxType(type);
}
-base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
- const MinMaxSizeInput& input) const {
- base::Optional<MinMaxSize> sizes = CalculateMinMaxSizesIgnoringChildren(
- node_, border_scrollbar_padding_, input.size_type);
+base::Optional<MinMaxSizes> NGBlockLayoutAlgorithm::ComputeMinMaxSizes(
+ const MinMaxSizesInput& input) const {
+ base::Optional<MinMaxSizes> sizes =
+ CalculateMinMaxSizesIgnoringChildren(node_, border_scrollbar_padding_);
if (sizes)
return sizes;
@@ -242,13 +245,13 @@ base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
float_right_inline_size = LayoutUnit();
}
- MinMaxSizeInput child_input(child_percentage_resolution_block_size);
+ MinMaxSizesInput child_input(child_percentage_resolution_block_size);
if (child.IsInline() || child.IsAnonymousBlock()) {
child_input.float_left_inline_size = float_left_inline_size;
child_input.float_right_inline_size = float_right_inline_size;
}
- MinMaxSize child_sizes;
+ MinMaxSizes child_sizes;
if (child.IsInline()) {
// From |NGBlockLayoutAlgorithm| perspective, we can handle |NGInlineNode|
// almost the same as |NGBlockNode|, because an |NGInlineNode| includes
@@ -257,7 +260,7 @@ base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
// |NextSibling| returns the next block sibling, or nullptr, skipping all
// following inline siblings and descendants.
child_sizes =
- child.ComputeMinMaxSize(Style().GetWritingMode(), child_input);
+ child.ComputeMinMaxSizes(Style().GetWritingMode(), child_input);
} else {
child_sizes =
ComputeMinAndMaxContentContribution(Style(), child, child_input);
@@ -331,8 +334,7 @@ base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
DCHECK_GE(sizes->min_size, LayoutUnit());
DCHECK_LE(sizes->min_size, sizes->max_size) << Node().ToString();
- if (input.size_type == NGMinMaxSizeType::kBorderBoxSize)
- *sizes += border_scrollbar_padding_.InlineSum();
+ *sizes += border_scrollbar_padding_.InlineSum();
return sizes;
}
@@ -364,7 +366,7 @@ scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
// Inline children require an inline child layout context to be
// passed between siblings. We want to stack-allocate that one, but
// only on demand, as it's quite big.
- if (Node().ChildrenInline())
+ if (Node().IsInlineFormattingContextRoot())
result = LayoutWithInlineChildLayoutContext();
else
result = Layout(nullptr);
@@ -374,6 +376,11 @@ scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
DCHECK(!early_break_);
DCHECK(result->GetEarlyBreak());
return RelayoutAndBreakEarlier(*result->GetEarlyBreak());
+ } else if (UNLIKELY(result->Status() ==
+ NGLayoutResult::
+ kNeedsRelayoutWithNoForcedTruncateAtLineClamp)) {
+ DCHECK(force_truncate_at_line_clamp_);
+ return RelayoutNoForcedTruncateForLineClamp();
}
return result;
}
@@ -417,6 +424,19 @@ NGBlockLayoutAlgorithm::RelayoutAndBreakEarlier(
return algorithm_with_break.Layout();
}
+NOINLINE scoped_refptr<const NGLayoutResult>
+NGBlockLayoutAlgorithm::RelayoutNoForcedTruncateForLineClamp() {
+ NGLayoutAlgorithmParams params(Node(),
+ container_builder_.InitialFragmentGeometry(),
+ ConstraintSpace(), BreakToken(), nullptr);
+ NGBlockLayoutAlgorithm algorithm_with_forced_truncate(params);
+ algorithm_with_forced_truncate.force_truncate_at_line_clamp_ = false;
+ NGBoxFragmentBuilder& new_builder =
+ algorithm_with_forced_truncate.container_builder_;
+ new_builder.SetBoxType(container_builder_.BoxType());
+ return algorithm_with_forced_truncate.Layout();
+}
+
inline scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::Layout(
NGInlineChildLayoutContext* inline_child_layout_context) {
const LogicalSize border_box_size = container_builder_.InitialBorderBoxSize();
@@ -436,6 +456,10 @@ inline scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::Layout(
ConstraintSpace(), Style(), container_builder_.Scrollbar());
}
+ DCHECK_EQ(!!inline_child_layout_context,
+ Node().IsInlineFormattingContextRoot());
+ container_builder_.SetIsInlineFormattingContext(inline_child_layout_context);
+
if (ConstraintSpace().HasBlockFragmentation()) {
container_builder_.SetHasBlockFragmentation();
// The whereabouts of our container's so far best breakpoint is none of our
@@ -463,6 +487,10 @@ inline scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::Layout(
container_builder_.SetAdjoiningObjectTypes(adjoining_object_types);
}
+ if (Style().IsDeprecatedWebkitBoxWithVerticalLineClamp() &&
+ RuntimeEnabledFeatures::BlockFlowHandlesWebkitLineClampEnabled())
+ lines_until_clamp_ = Style().LineClamp();
+
LayoutUnit content_edge = border_scrollbar_padding_.block_start;
NGPreviousInflowPosition previous_inflow_position = {
@@ -480,8 +508,7 @@ inline scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::Layout(
//
// In all those cases we can and must resolve the BFC block offset now.
if (border_scrollbar_padding_.block_start || is_resuming_ ||
- ConstraintSpace().IsNewFormattingContext() ||
- Style().MarginBeforeCollapse() != EMarginCollapse::kCollapse) {
+ ConstraintSpace().IsNewFormattingContext()) {
bool discard_subsequent_margins =
previous_inflow_position.margin_strut.discard_margins &&
!border_scrollbar_padding_.block_start;
@@ -537,12 +564,6 @@ inline scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::Layout(
if (node_.IsQuirkyContainer())
previous_inflow_position.margin_strut.is_quirky_container_start = true;
- // Before we descend into children (but after we have determined our inline
- // size), give the autosizer an opportunity to adjust the font size on the
- // children.
- TextAutosizer::NGLayoutScope text_autosizer_layout_scope(
- Node(), border_box_size.inline_size);
-
// Try to reuse line box fragments from cached fragments if possible.
// When possible, this adds fragments to |container_builder_| and update
// |previous_inflow_position| and |BreakToken()|.
@@ -650,6 +671,18 @@ inline scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::Layout(
}
}
+ if (UNLIKELY(ConstraintSpace().IsNewFormattingContext() &&
+ force_truncate_at_line_clamp_ &&
+ intrinsic_block_size_when_clamped_ && lines_until_clamp_ == 0)) {
+ // Truncation of the last line was forced, but there are no lines after the
+ // truncated line. Rerun layout without forcing truncation. This is only
+ // done if line-clamp was specified on the element as the element containing
+ // the node may have subsequent lines. If there aren't, the containing
+ // element will relayout.
+ return container_builder_.Abort(
+ NGLayoutResult::kNeedsRelayoutWithNoForcedTruncateAtLineClamp);
+ }
+
if (child_iterator.IsAtEnd()) {
// We've gone through all the children. This doesn't necessarily mean that
// we're done fragmenting, as there may be parallel flows [1] (visible
@@ -685,15 +718,22 @@ scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::FinishLayout(
intrinsic_block_size_, exclusion_space_.ClearanceOffset(EClear::kBoth));
}
- // The end margin strut of an in-flow fragment contributes to the size of the
- // current fragment if:
- // - There is block-end border/scrollbar/padding.
- // - There was a self-collapsing child affected by clearance.
- // - We are a new formatting context.
- // Additionally this fragment produces no end margin strut.
- if (border_scrollbar_padding_.block_end ||
- previous_inflow_position->self_collapsing_child_had_clearance ||
- ConstraintSpace().IsNewFormattingContext()) {
+ // If line clamping occurred, the intrinsic block-size comes from the
+ // intrinsic block-size at the time of the clamp.
+ if (intrinsic_block_size_when_clamped_) {
+ DCHECK(container_builder_.BfcBlockOffset());
+ intrinsic_block_size_ = *intrinsic_block_size_when_clamped_;
+ end_margin_strut = NGMarginStrut();
+ } else if (border_scrollbar_padding_.block_end ||
+ previous_inflow_position->self_collapsing_child_had_clearance ||
+ ConstraintSpace().IsNewFormattingContext()) {
+ // The end margin strut of an in-flow fragment contributes to the size of
+ // the current fragment if:
+ // - There is block-end border/scrollbar/padding.
+ // - There was a self-collapsing child affected by clearance.
+ // - We are a new formatting context.
+ // Additionally this fragment produces no end margin strut.
+ //
// If we are a quirky container, we ignore any quirky margins and
// just consider normal margins to extend our size. Other UAs
// perform this calculation differently, e.g. by just ignoring the
@@ -741,7 +781,7 @@ scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::FinishLayout(
}
// Save the unconstrained intrinsic size on the builder before clamping it.
- container_builder_.SetUnconstrainedIntrinsicBlockSize(intrinsic_block_size_);
+ container_builder_.SetOverflowBlockSize(intrinsic_block_size_);
intrinsic_block_size_ = ClampIntrinsicBlockSize(
ConstraintSpace(), Node(), border_scrollbar_padding_,
@@ -827,11 +867,14 @@ scoped_refptr<const NGLayoutResult> NGBlockLayoutAlgorithm::FinishLayout(
container_builder_.CheckNoBlockFragmentation();
#endif
- PropagateBaselinesFromChildren();
+ // Adjust the position of the final baseline if needed.
+ FinalizeBaseline();
// An exclusion space is confined to nodes within the same formatting context.
- if (!ConstraintSpace().IsNewFormattingContext())
+ if (!ConstraintSpace().IsNewFormattingContext()) {
container_builder_.SetExclusionSpace(std::move(exclusion_space_));
+ container_builder_.SetLinesUntilClamp(lines_until_clamp_);
+ }
if (ConstraintSpace().UseFirstLineStyle())
container_builder_.SetStyleVariant(NGStyleVariant::kFirstLine);
@@ -1016,6 +1059,10 @@ void NGBlockLayoutAlgorithm::HandleFloat(
PositionFloat(&unpositioned_float, &exclusion_space_);
const NGLayoutResult& layout_result = *positioned_float.layout_result;
+
+ // TODO(mstensho): Handle abortions caused by block fragmentation.
+ DCHECK_EQ(layout_result.Status(), NGLayoutResult::kSuccess);
+
const auto& physical_fragment = layout_result.PhysicalFragment();
if (const NGBreakToken* token = physical_fragment.BreakToken()) {
DCHECK(ConstraintSpace().HasBlockFragmentation());
@@ -1230,13 +1277,6 @@ NGLayoutResult::EStatus NGBlockLayoutAlgorithm::HandleNewFormattingContext(
/* abort_if_cleared */ false, &child_bfc_offset);
}
- NGFragment fragment(ConstraintSpace().GetWritingMode(),
- layout_result->PhysicalFragment());
-
- LogicalOffset logical_offset = LogicalFromBfcOffsets(
- child_bfc_offset, ContainerBfcOffset(), fragment.InlineSize(),
- container_builder_.Size().inline_size, ConstraintSpace().Direction());
-
if (ConstraintSpace().HasBlockFragmentation()) {
bool has_container_separation =
has_processed_first_child_ || child_margin_got_separated ||
@@ -1244,20 +1284,32 @@ NGLayoutResult::EStatus NGBlockLayoutAlgorithm::HandleNewFormattingContext(
layout_result->IsPushedByFloats();
NGBreakStatus break_status = BreakBeforeChildIfNeeded(
child, *layout_result, previous_inflow_position,
- logical_offset.block_offset, has_container_separation);
+ child_bfc_offset.block_offset, has_container_separation);
if (break_status == NGBreakStatus::kBrokeBefore)
return NGLayoutResult::kSuccess;
if (break_status == NGBreakStatus::kNeedsEarlierBreak)
return NGLayoutResult::kNeedsEarlierBreak;
+
+ // If the child aborted layout, we cannot continue.
+ DCHECK_EQ(layout_result->Status(), NGLayoutResult::kSuccess);
+
EBreakBetween break_after = JoinFragmentainerBreakValues(
layout_result->FinalBreakAfter(), child.Style().BreakAfter());
container_builder_.SetPreviousBreakAfter(break_after);
}
+ const auto& physical_fragment = layout_result->PhysicalFragment();
+ NGFragment fragment(ConstraintSpace().GetWritingMode(), physical_fragment);
+
+ LogicalOffset logical_offset = LogicalFromBfcOffsets(
+ child_bfc_offset, ContainerBfcOffset(), fragment.InlineSize(),
+ container_builder_.Size().inline_size, ConstraintSpace().Direction());
+
if (!PositionOrPropagateListMarker(*layout_result, &logical_offset,
previous_inflow_position))
return NGLayoutResult::kBfcBlockOffsetResolved;
+ PropagateBaselineFromChild(physical_fragment, logical_offset.block_offset);
container_builder_.AddResult(*layout_result, logical_offset);
// The margins we store will be used by e.g. getComputedStyle().
@@ -1306,7 +1358,7 @@ NGBlockLayoutAlgorithm::LayoutNewFormattingContext(
// fit where it was laid out, and is pushed downwards, we'll lay out over
// again, since a new BFC block offset could result in a new fragment size,
// e.g. when inline size is auto, or if we're block-fragmented.
- for (const auto opportunity : opportunities) {
+ for (const auto& opportunity : opportunities) {
if (abort_if_cleared &&
origin_offset.block_offset < opportunity.rect.BlockStartOffset()) {
// Abort if we got pushed downwards. We need to adjust
@@ -1378,6 +1430,12 @@ NGBlockLayoutAlgorithm::LayoutNewFormattingContext(
// should be returned.
DCHECK(layout_result->ExclusionSpace().IsEmpty());
+ if (layout_result->Status() != NGLayoutResult::kSuccess) {
+ DCHECK_EQ(layout_result->Status(),
+ NGLayoutResult::kOutOfFragmentainerSpace);
+ return layout_result;
+ }
+
NGFragment fragment(writing_mode, layout_result->PhysicalFragment());
// Check if the fragment will fit in this layout opportunity, if not proceed
@@ -1730,7 +1788,8 @@ NGLayoutResult::EStatus NGBlockLayoutAlgorithm::FinishInflow(
LogicalOffset logical_offset = CalculateLogicalOffset(
fragment, layout_result->BfcLineOffset(), child_bfc_block_offset);
- if (ConstraintSpace().HasBlockFragmentation()) {
+ if (ConstraintSpace().HasBlockFragmentation() &&
+ container_builder_.BfcBlockOffset() && child_bfc_block_offset) {
// Floats only cause container separation for the outermost block child that
// gets pushed down (the container and the child may have adjoining
// block-start margins).
@@ -1739,7 +1798,7 @@ NGLayoutResult::EStatus NGBlockLayoutAlgorithm::FinishInflow(
!container_builder_.IsPushedByFloats());
NGBreakStatus break_status = BreakBeforeChildIfNeeded(
child, *layout_result, previous_inflow_position,
- logical_offset.block_offset, has_container_separation);
+ *child_bfc_block_offset, has_container_separation);
if (break_status == NGBreakStatus::kBrokeBefore)
return NGLayoutResult::kSuccess;
if (break_status == NGBreakStatus::kNeedsEarlierBreak)
@@ -1753,6 +1812,7 @@ NGLayoutResult::EStatus NGBlockLayoutAlgorithm::FinishInflow(
previous_inflow_position))
return NGLayoutResult::kBfcBlockOffsetResolved;
+ PropagateBaselineFromChild(physical_fragment, logical_offset.block_offset);
container_builder_.AddResult(*layout_result, logical_offset);
if (auto* block_child = DynamicTo<NGBlockNode>(child)) {
@@ -1795,6 +1855,24 @@ NGLayoutResult::EStatus NGBlockLayoutAlgorithm::FinishInflow(
}
}
+ // Update |lines_until_clamp_| from the LayoutResult.
+ if (lines_until_clamp_) {
+ if (const auto* line_box =
+ DynamicTo<NGPhysicalLineBoxFragment>(physical_fragment)) {
+ if (!line_box->IsEmptyLineBox())
+ lines_until_clamp_ = *lines_until_clamp_ - 1;
+ } else {
+ lines_until_clamp_ = layout_result->LinesUntilClamp();
+ }
+ if (lines_until_clamp_ <= 0 &&
+ !intrinsic_block_size_when_clamped_.has_value()) {
+ // If line-clamping occurred save the intrinsic block-size, as this
+ // becomes the final intrinsic block-size.
+ intrinsic_block_size_when_clamped_ =
+ previous_inflow_position->logical_block_offset +
+ border_scrollbar_padding_.block_end;
+ }
+ }
return NGLayoutResult::kSuccess;
}
@@ -1832,32 +1910,9 @@ NGInflowChildData NGBlockLayoutAlgorithm::ComputeChildData(
LayoutUnit logical_block_offset =
previous_inflow_position.logical_block_offset;
- EMarginCollapse margin_before_collapse = child.Style().MarginBeforeCollapse();
- if (margin_before_collapse != EMarginCollapse::kCollapse) {
- // Stop margin collapsing on the block-start side of the child.
- StopMarginCollapsing(child.Style().MarginBeforeCollapse(),
- margins.block_start, &logical_block_offset,
- &margin_strut);
-
- if (margin_before_collapse == EMarginCollapse::kSeparate) {
- UseCounter::Count(Node().GetDocument(),
- WebFeature::kWebkitMarginBeforeCollapseSeparate);
- if (margin_strut != previous_inflow_position.margin_strut ||
- logical_block_offset !=
- previous_inflow_position.logical_block_offset) {
- UseCounter::Count(
- Node().GetDocument(),
- WebFeature::kWebkitMarginBeforeCollapseSeparateMaybeDoesSomething);
- }
- } else if (margin_before_collapse == EMarginCollapse::kDiscard) {
- UseCounter::Count(Node().GetDocument(),
- WebFeature::kWebkitMarginBeforeCollapseDiscard);
- }
- } else {
- margin_strut.Append(margins.block_start,
- child.Style().HasMarginBeforeQuirk());
- SetSubtreeModifiedMarginStrutIfNeeded(&child.Style().MarginBefore());
- }
+ margin_strut.Append(margins.block_start,
+ child.Style().HasMarginBeforeQuirk());
+ SetSubtreeModifiedMarginStrutIfNeeded(&child.Style().MarginBefore());
NGBfcOffset child_bfc_offset = {
ConstraintSpace().BfcOffset().line_offset +
@@ -1945,36 +2000,14 @@ NGPreviousInflowPosition NGBlockLayoutAlgorithm::ComputeInflowPosition(
NGMarginStrut margin_strut = layout_result.EndMarginStrut();
- EMarginCollapse margin_after_collapse = child.Style().MarginAfterCollapse();
- if (margin_after_collapse != EMarginCollapse::kCollapse) {
- LayoutUnit logical_block_offset_copy = logical_block_offset;
- // Stop margin collapsing on the block-end side of the child.
- StopMarginCollapsing(margin_after_collapse, child_data.margins.block_end,
- &logical_block_offset, &margin_strut);
-
- if (margin_after_collapse == EMarginCollapse::kSeparate) {
- UseCounter::Count(Node().GetDocument(),
- WebFeature::kWebkitMarginAfterCollapseSeparate);
- if (margin_strut != layout_result.EndMarginStrut() ||
- logical_block_offset != logical_block_offset_copy) {
- UseCounter::Count(
- Node().GetDocument(),
- WebFeature::kWebkitMarginAfterCollapseSeparateMaybeDoesSomething);
- }
- } else if (margin_after_collapse == EMarginCollapse::kDiscard) {
- UseCounter::Count(Node().GetDocument(),
- WebFeature::kWebkitMarginAfterCollapseDiscard);
- }
- } else {
- // Self collapsing child's end margin can "inherit" quirkiness from its
- // start margin. E.g.
- // <ol style="margin-bottom: 20px"></ol>
- bool is_quirky =
- (is_self_collapsing && child.Style().HasMarginBeforeQuirk()) ||
- child.Style().HasMarginAfterQuirk();
- margin_strut.Append(child_data.margins.block_end, is_quirky);
- SetSubtreeModifiedMarginStrutIfNeeded(&child.Style().MarginAfter());
- }
+ // Self collapsing child's end margin can "inherit" quirkiness from its start
+ // margin. E.g.
+ // <ol style="margin-bottom: 20px"></ol>
+ bool is_quirky =
+ (is_self_collapsing && child.Style().HasMarginBeforeQuirk()) ||
+ child.Style().HasMarginAfterQuirk();
+ margin_strut.Append(child_data.margins.block_end, is_quirky);
+ SetSubtreeModifiedMarginStrutIfNeeded(&child.Style().MarginAfter());
// This flag is subtle, but in order to determine our size correctly we need
// to check if our last child is self-collapsing, and it was affected by
@@ -2044,7 +2077,7 @@ void NGBlockLayoutAlgorithm::SetFragmentainerOutOfSpace(
}
bool NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
- if (Node().ChildrenInline() && !early_break_) {
+ if (Node().IsInlineFormattingContextRoot() && !early_break_) {
if (container_builder_.DidBreak() || first_overflowing_line_) {
if (first_overflowing_line_ &&
first_overflowing_line_ < container_builder_.LineCount()) {
@@ -2112,8 +2145,8 @@ bool NGBlockLayoutAlgorithm::FinalizeForFragmentation() {
}
}
- FinishFragmentation(ConstraintSpace(), block_size, intrinsic_block_size_,
- consumed_block_size, space_left, &container_builder_);
+ FinishFragmentation(ConstraintSpace(), BreakToken(), block_size,
+ intrinsic_block_size_, space_left, &container_builder_);
return true;
}
@@ -2122,14 +2155,13 @@ NGBreakStatus NGBlockLayoutAlgorithm::BreakBeforeChildIfNeeded(
NGLayoutInputNode child,
const NGLayoutResult& layout_result,
NGPreviousInflowPosition* previous_inflow_position,
- LayoutUnit block_offset,
+ LayoutUnit bfc_block_offset,
bool has_container_separation) {
DCHECK(ConstraintSpace().HasBlockFragmentation());
// If the BFC offset is unknown, there's nowhere to break, since there's no
// non-empty child content yet (as that would have resolved the BFC offset).
- if (!container_builder_.BfcBlockOffset())
- return NGBreakStatus::kContinue;
+ DCHECK(container_builder_.BfcBlockOffset());
// If we already know where to insert the break, we already know that it's not
// going to be here, since that's something we check before entering layout of
@@ -2138,8 +2170,7 @@ NGBreakStatus NGBlockLayoutAlgorithm::BreakBeforeChildIfNeeded(
return NGBreakStatus::kContinue;
LayoutUnit fragmentainer_block_offset =
- ConstraintSpace().FragmentainerOffsetAtBfc() +
- *container_builder_.BfcBlockOffset() + block_offset;
+ ConstraintSpace().FragmentainerOffsetAtBfc() + bfc_block_offset;
if (has_container_separation) {
EBreakBetween break_between =
@@ -2315,7 +2346,7 @@ NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins(
NGConstraintSpace space = builder.ToConstraintSpace();
NGBoxStrut child_border_padding =
- ComputeBorders(space, child) + ComputePadding(space, child.Style());
+ ComputeBorders(space, child_style) + ComputePadding(space, child_style);
LayoutUnit child_inline_size =
ComputeInlineSizeForFragment(space, child, child_border_padding);
@@ -2327,29 +2358,6 @@ NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins(
return margins;
}
-// Stop margin collapsing on one side of a block when
-// -webkit-margin-{after,before}-collapse is something other than 'collapse'
-// (the initial value)
-void NGBlockLayoutAlgorithm::StopMarginCollapsing(
- EMarginCollapse collapse_value,
- LayoutUnit this_margin,
- LayoutUnit* logical_block_offset,
- NGMarginStrut* margin_strut) {
- DCHECK_NE(collapse_value, EMarginCollapse::kCollapse);
- if (collapse_value == EMarginCollapse::kSeparate) {
- // Separate margins between previously adjoining margins and this margin,
- // AND between this margin and adjoining margins to come.
- *logical_block_offset += margin_strut->Sum() + this_margin;
- *margin_strut = NGMarginStrut();
- return;
- }
- DCHECK_EQ(collapse_value, EMarginCollapse::kDiscard);
- // Discard previously adjoining margins, this margin AND all adjoining margins
- // to come, so that the sum becomes 0.
- margin_strut->discard_margins = true;
- SetSubtreeModifiedMarginStrutIfNeeded();
-}
-
NGConstraintSpace NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
const NGLayoutInputNode child,
const NGInflowChildData& child_data,
@@ -2369,6 +2377,9 @@ NGConstraintSpace NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
if (!IsParallelWritingMode(ConstraintSpace().GetWritingMode(),
child_writing_mode))
builder.SetIsShrinkToFit(child_style.LogicalWidth().IsAuto());
+ if (child_style.LogicalWidth().IsAuto() &&
+ child.GetLayoutBox()->AutoWidthShouldFitContent())
+ builder.SetIsShrinkToFit(true);
builder.SetAvailableSize(child_available_size);
builder.SetPercentageResolutionSize(child_percentage_size_);
@@ -2387,9 +2398,6 @@ NGConstraintSpace NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
builder.SetTableCellChildLayoutMode(mode);
}
- if (NGBaseline::ShouldPropagateBaselines(child))
- builder.AddBaselineRequests(ConstraintSpace().BaselineRequests());
-
bool has_bfc_block_offset = container_builder_.BfcBlockOffset().has_value();
// Propagate the |NGConstraintSpace::ForcedBfcBlockOffset| down to our
@@ -2447,11 +2455,10 @@ NGConstraintSpace NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
clearance_offset = std::max(clearance_offset, child_clearance_offset);
builder.SetTextDirection(child_style.Direction());
- // PositionListMarker() requires a first line baseline.
- if (container_builder_.UnpositionedListMarker()) {
- builder.AddBaselineRequest(
- {NGBaselineAlgorithmType::kFirstLine, style.GetFontBaseline()});
- }
+ // |PositionListMarker()| requires a baseline.
+ builder.SetNeedsBaseline(ConstraintSpace().NeedsBaseline() ||
+ container_builder_.UnpositionedListMarker());
+ builder.SetBaselineAlgorithmType(ConstraintSpace().BaselineAlgorithmType());
} else {
builder.SetTextDirection(style.Direction());
}
@@ -2465,6 +2472,8 @@ NGConstraintSpace NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
builder.SetAdjoiningObjectTypes(
container_builder_.AdjoiningObjectTypes());
}
+ builder.SetLinesUntilClamp(lines_until_clamp_);
+ builder.SetForceTruncateAtLineClamp(force_truncate_at_line_clamp_);
} else if (child_data.is_resuming_after_break) {
// If the child is being resumed after a break, margins inside the child may
// be adjoining with the fragmentainer boundary, regardless of whether the
@@ -2479,109 +2488,78 @@ NGConstraintSpace NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
// fragmentation line.
if (is_new_fc)
fragmentainer_offset_delta = *child_bfc_block_offset;
- SetupFragmentation(ConstraintSpace(), fragmentainer_offset_delta, &builder,
- is_new_fc);
+ SetupFragmentation(ConstraintSpace(), child, fragmentainer_offset_delta,
+ &builder, is_new_fc);
builder.SetEarlyBreakAppeal(container_builder_.BreakAppeal());
}
return builder.ToConstraintSpace();
}
-LayoutUnit NGBlockLayoutAlgorithm::ComputeLineBoxBaselineOffset(
- const NGBaselineRequest& request,
- const NGPhysicalLineBoxFragment& line_box,
- LayoutUnit line_box_block_offset) const {
- NGLineHeightMetrics metrics =
- line_box.BaselineMetrics(request.BaselineType());
- DCHECK(!metrics.IsEmpty());
-
- // NGLineHeightMetrics is line-relative, which matches to the flow-relative
- // unless this box is in flipped-lines writing-mode.
- if (!Style().IsFlippedLinesWritingMode())
- return metrics.ascent + line_box_block_offset;
-
- if (Node().IsInlineLevel()) {
- // If this box is inline-level, since we're in NGBlockLayoutAlgorithm, this
- // is an inline-block.
- DCHECK(Node().IsAtomicInlineLevel());
- // This box will be flipped when the containing line is flipped. Compute the
- // baseline offset from the block-end (right in vertical-lr) content edge.
- line_box_block_offset = container_builder_.Size().block_size -
- (line_box_block_offset + line_box.Size().width);
- return metrics.ascent + line_box_block_offset;
- }
-
- // Otherwise, the baseline is offset by the descent from the block-start
- // content edge.
- return metrics.descent + line_box_block_offset;
-}
+void NGBlockLayoutAlgorithm::PropagateBaselineFromChild(
+ const NGPhysicalContainerFragment& child,
+ LayoutUnit block_offset) {
+ // Check if we've already found an appropriate baseline.
+ if (container_builder_.Baseline() &&
+ ConstraintSpace().BaselineAlgorithmType() ==
+ NGBaselineAlgorithmType::kFirstLine)
+ return;
-// Add a baseline from a child box fragment.
-// @return false if the specified child is not a box or is OOF.
-bool NGBlockLayoutAlgorithm::AddBaseline(const NGBaselineRequest& request,
- const NGPhysicalFragment& child,
- LayoutUnit child_offset) {
if (child.IsLineBox()) {
const auto& line_box = To<NGPhysicalLineBoxFragment>(child);
- // Skip over a line-box which is empty. These don't have any baselines which
- // should be added.
+ // Skip over a line-box which is empty. These don't have any baselines
+ // which should be added.
if (line_box.IsEmptyLineBox())
- return false;
+ return;
- LayoutUnit offset =
- ComputeLineBoxBaselineOffset(request, line_box, child_offset);
- container_builder_.AddBaseline(request, offset);
- return true;
+ NGLineHeightMetrics metrics = line_box.BaselineMetrics();
+ DCHECK(!metrics.IsEmpty());
+ LayoutUnit baseline =
+ block_offset + (Style().IsFlippedLinesWritingMode() ? metrics.descent
+ : metrics.ascent);
+
+ if (!container_builder_.Baseline())
+ container_builder_.SetBaseline(baseline);
+
+ // Set the last baseline only if required.
+ if (ConstraintSpace().BaselineAlgorithmType() !=
+ NGBaselineAlgorithmType::kFirstLine)
+ container_builder_.SetLastBaseline(baseline);
+
+ return;
}
- if (child.IsFloatingOrOutOfFlowPositioned())
- return false;
+ NGBoxFragment fragment(ConstraintSpace().GetWritingMode(),
+ ConstraintSpace().Direction(),
+ To<NGPhysicalBoxFragment>(child));
- if (const auto* box = DynamicTo<NGPhysicalBoxFragment>(child)) {
- if (base::Optional<LayoutUnit> baseline = box->Baseline(request)) {
- container_builder_.AddBaseline(request, *baseline + child_offset);
- return true;
- }
+ if (!container_builder_.Baseline()) {
+ if (auto baseline = fragment.FirstBaseline())
+ container_builder_.SetBaseline(block_offset + *baseline);
}
- return false;
+ // Set the last baseline only if required.
+ if (ConstraintSpace().BaselineAlgorithmType() !=
+ NGBaselineAlgorithmType::kFirstLine) {
+ if (auto last_baseline = fragment.Baseline())
+ container_builder_.SetLastBaseline(block_offset + *last_baseline);
+ }
}
-// Propagate computed baselines from children.
-// Skip children that do not produce baselines (e.g., empty blocks.)
-void NGBlockLayoutAlgorithm::PropagateBaselinesFromChildren() {
- const NGBaselineRequestList requests = ConstraintSpace().BaselineRequests();
- if (requests.IsEmpty())
+void NGBlockLayoutAlgorithm::FinalizeBaseline() {
+ if (ConstraintSpace().BaselineAlgorithmType() !=
+ NGBaselineAlgorithmType::kInlineBlock)
return;
- for (const auto& request : requests) {
- switch (request.AlgorithmType()) {
- case NGBaselineAlgorithmType::kAtomicInline: {
- if (Node().UseLogicalBottomMarginEdgeForInlineBlockBaseline()) {
- LayoutUnit block_end = container_builder_.BlockSize();
- NGBoxStrut margins =
- ComputeMarginsForSelf(ConstraintSpace(), Style());
- container_builder_.AddBaseline(request,
- block_end + margins.block_end);
- break;
- }
+ if (!Node().UseLogicalBottomMarginEdgeForInlineBlockBaseline())
+ return;
- const auto& children = container_builder_.Children();
- for (auto it = children.rbegin(); it != children.rend(); ++it) {
- if (AddBaseline(request, *it->fragment, it->offset.block_offset))
- break;
- }
- break;
- }
- case NGBaselineAlgorithmType::kFirstLine:
- for (const auto& child : container_builder_.Children()) {
- if (AddBaseline(request, *child.fragment, child.offset.block_offset))
- break;
- }
- break;
- }
- }
+ // When overflow is present (within an atomic-inline baseline context) we
+ // should always use the block-end margin edge as the baseline.
+ NGBoxStrut margins = ComputeMarginsForSelf(ConstraintSpace(), Style());
+ container_builder_.SetLastBaseline(container_builder_.BlockSize() +
+ margins.block_end);
}
bool NGBlockLayoutAlgorithm::ResolveBfcBlockOffset(
@@ -2687,12 +2665,11 @@ bool NGBlockLayoutAlgorithm::PositionOrPropagateListMarker(
container_builder_.SetUnpositionedListMarker(NGUnpositionedListMarker());
}
- NGLineHeightMetrics content_metrics;
const NGConstraintSpace& space = ConstraintSpace();
const NGPhysicalFragment& content = layout_result.PhysicalFragment();
FontBaseline baseline_type = Style().GetFontBaseline();
- if (list_marker.CanAddToBox(space, baseline_type, content,
- &content_metrics)) {
+ if (auto content_baseline =
+ list_marker.ContentAlignmentBaseline(space, baseline_type, content)) {
// TODO: We are reusing the ConstraintSpace for LI here. It works well for
// now because authors cannot style list-markers currently. If we want to
// support `::marker` pseudo, we need to create ConstraintSpace for marker
@@ -2713,8 +2690,8 @@ bool NGBlockLayoutAlgorithm::PositionOrPropagateListMarker(
}
list_marker.AddToBox(space, baseline_type, content,
- border_scrollbar_padding_, content_metrics,
- *marker_layout_result, content_offset,
+ border_scrollbar_padding_, *marker_layout_result,
+ *content_baseline, content_offset,
&container_builder_);
return true;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
index 8274b1dc201..644bb031ead 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h
@@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_BLOCK_LAYOUT_ALGORITHM_H_
#include "base/memory/scoped_refptr.h"
+#include "base/optional.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h"
@@ -17,6 +18,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
+#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
namespace blink {
@@ -24,7 +26,6 @@ enum class NGBreakStatus;
class NGConstraintSpace;
class NGEarlyBreak;
class NGFragment;
-class NGPhysicalLineBoxFragment;
// This struct is used for communicating to a child the position of the previous
// inflow child. This will be used to calculate the position of the next child.
@@ -58,8 +59,8 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
void SetBoxType(NGPhysicalFragment::NGBoxType type);
- base::Optional<MinMaxSize> ComputeMinMaxSize(
- const MinMaxSizeInput&) const override;
+ base::Optional<MinMaxSizes> ComputeMinMaxSizes(
+ const MinMaxSizesInput&) const override;
scoped_refptr<const NGLayoutResult> Layout() override;
private:
@@ -75,10 +76,14 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
NOINLINE scoped_refptr<const NGLayoutResult> RelayoutAndBreakEarlier(
const NGEarlyBreak&);
+ NOINLINE scoped_refptr<const NGLayoutResult>
+ RelayoutNoForcedTruncateForLineClamp();
+
inline scoped_refptr<const NGLayoutResult> Layout(
NGInlineChildLayoutContext* inline_child_layout_context);
- scoped_refptr<const NGLayoutResult> FinishLayout(NGPreviousInflowPosition*);
+ scoped_refptr<const NGLayoutResult> FinishLayout(
+ NGPreviousInflowPosition* previous_inflow_position);
// Return the BFC block offset of this block.
LayoutUnit BfcBlockOffset() const {
@@ -102,11 +107,6 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
bool is_new_fc,
bool* margins_fully_resolved);
- void StopMarginCollapsing(EMarginCollapse collapse_value,
- LayoutUnit this_margin,
- LayoutUnit* logical_block_offset,
- NGMarginStrut* margin_strut);
-
// Creates a new constraint space for the current child.
NGConstraintSpace CreateConstraintSpaceForChild(
const NGLayoutInputNode child,
@@ -238,25 +238,19 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
NGBreakStatus BreakBeforeChildIfNeeded(NGLayoutInputNode child,
const NGLayoutResult&,
NGPreviousInflowPosition*,
- LayoutUnit block_offset,
+ LayoutUnit bfc_block_offset,
bool has_container_separation);
// Look for a better breakpoint (than we already have) between lines (i.e. a
// class B breakpoint), and store it.
void UpdateEarlyBreakBetweenLines();
- void PropagateBaselinesFromChildren();
- bool AddBaseline(const NGBaselineRequest&,
- const NGPhysicalFragment&,
- LayoutUnit child_offset);
+ // Propagates the baseline from the given |child| if needed.
+ void PropagateBaselineFromChild(const NGPhysicalContainerFragment& child,
+ LayoutUnit block_offset);
- // Compute the baseline offset of a line box from the content box.
- // Line boxes are in line-relative coordinates. This function returns the
- // offset in flow-relative coordinates.
- LayoutUnit ComputeLineBoxBaselineOffset(
- const NGBaselineRequest&,
- const NGPhysicalLineBoxFragment&,
- LayoutUnit line_box_block_offset) const;
+ // Performs any final baseline adjustments needed.
+ void FinalizeBaseline();
// If still unresolved, resolve the fragment's BFC block offset.
//
@@ -396,6 +390,18 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
NGExclusionSpace exclusion_space_;
+ // If set, this is the number of lines until a clamp. A value of 1 indicates
+ // the current line should be clamped. This may go negative.
+ base::Optional<int> lines_until_clamp_;
+
+ // If true, truncation is forced at the clamped line regardless of whether
+ // there is more text.
+ bool force_truncate_at_line_clamp_ = true;
+
+ // If set, one of the lines was clamped and this is the intrinsic size at the
+ // time of the clamp.
+ base::Optional<LayoutUnit> intrinsic_block_size_when_clamped_;
+
// When set, this will specify where to break before or inside.
const NGEarlyBreak* early_break_ = nullptr;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
index 1cc8a99f1ed..f07b9dcfcf3 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc
@@ -33,7 +33,7 @@ class NGBlockLayoutAlgorithmTest : public NGBaseLayoutAlgorithmTest {
NGBaseLayoutAlgorithmTest::SetUp();
}
- MinMaxSize RunComputeMinAndMax(NGBlockNode node) {
+ MinMaxSizes RunComputeMinMaxSizes(NGBlockNode node) {
// The constraint space is not used for min/max computation, but we need
// it to create the algorithm.
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
@@ -43,9 +43,9 @@ class NGBlockLayoutAlgorithmTest : public NGBaseLayoutAlgorithmTest {
CalculateInitialMinMaxFragmentGeometry(space, node);
NGBlockLayoutAlgorithm algorithm({node, fragment_geometry, space});
- MinMaxSizeInput input(
+ MinMaxSizesInput input(
/* percentage_resolution_block_size */ (LayoutUnit()));
- auto min_max = algorithm.ComputeMinMaxSize(input);
+ auto min_max = algorithm.ComputeMinMaxSizes(input);
EXPECT_TRUE(min_max.has_value());
return *min_max;
}
@@ -97,10 +97,11 @@ TEST_F(NGBlockLayoutAlgorithmTest, FixedSize) {
}
TEST_F(NGBlockLayoutAlgorithmTest, Caching) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
+ // The inner element exists so that "simplified" layout logic isn't invoked.
SetBodyInnerHTML(R"HTML(
- <div id="box" style="width:30px; height:40%;"></div>
+ <div id="box" style="width:30px; height:40%;">
+ <div style="height: 100%;"></div>
+ </div>
)HTML");
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
@@ -132,7 +133,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, Caching) {
EXPECT_NE(result.get(), nullptr);
// Test a different constraint space that will actually result in a different
- // size.
+ // sized fragment.
space = ConstructBlockLayoutTestConstraintSpace(
WritingMode::kHorizontalTb, TextDirection::kLtr,
LogicalSize(LayoutUnit(200), LayoutUnit(200)));
@@ -146,8 +147,6 @@ TEST_F(NGBlockLayoutAlgorithmTest, Caching) {
}
TEST_F(NGBlockLayoutAlgorithmTest, MinInlineSizeCaching) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
SetBodyInnerHTML(R"HTML(
<div id="box" style="min-width:30%; width: 10px; height:40px;"></div>
)HTML");
@@ -190,8 +189,6 @@ TEST_F(NGBlockLayoutAlgorithmTest, MinInlineSizeCaching) {
}
TEST_F(NGBlockLayoutAlgorithmTest, PercentageBlockSizeQuirkDescendantsCaching) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Quirks mode triggers the interesting parent-child %-resolution behaviour.
GetDocument().SetCompatibilityMode(Document::kQuirksMode);
@@ -237,10 +234,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, PercentageBlockSizeQuirkDescendantsCaching) {
builder.SetAvailableSize(size);
builder.SetPercentageResolutionSize(size);
builder.SetTextDirection(TextDirection::kLtr);
- builder.AddBaselineRequest({NGBaselineAlgorithmType::kAtomicInline,
- FontBaseline::kAlphabeticBaseline});
- builder.AddBaselineRequest({NGBaselineAlgorithmType::kFirstLine,
- FontBaseline::kAlphabeticBaseline});
+ builder.SetNeedsBaseline(true);
return builder.ToConstraintSpace();
};
@@ -298,99 +292,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, PercentageBlockSizeQuirkDescendantsCaching) {
EXPECT_EQ(run_test("box9"), nullptr);
}
-TEST_F(NGBlockLayoutAlgorithmTest, ShrinkToFitCaching) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
- SetBodyInnerHTML(R"HTML(
- <div id="container" style="display: flow-root; width: 300px; height: 100px;">
- <div id="box1" style="float: left;">
- <div style="display: inline-block; width: 150px;"></div>
- <div style="display: inline-block; width: 50px;"></div>
- </div>
- <div id="box2" style="float: left;">
- <div style="display: inline-block; width: 350px;"></div>
- <div style="display: inline-block; width: 250px;"></div>
- </div>
- <div id="box3" style="float: left; min-width: 80%;">
- <div style="display: inline-block; width: 150px;"></div>
- <div style="display: inline-block; width: 250px;"></div>
- </div>
- <div id="box4" style="float: left; margin-left: 75px;">
- <div style="display: inline-block; width: 150px;"></div>
- <div style="display: inline-block; width: 50px;"></div>
- </div>
- </div>
- )HTML");
-
- NGConstraintSpace space100 = ConstructBlockLayoutTestConstraintSpace(
- WritingMode::kHorizontalTb, TextDirection::kLtr,
- LogicalSize(LayoutUnit(100), LayoutUnit(100)),
- /* shrink_to_fit */ true, /* is_new_formatting_context */ true);
- NGConstraintSpace space200 = ConstructBlockLayoutTestConstraintSpace(
- WritingMode::kHorizontalTb, TextDirection::kLtr,
- LogicalSize(LayoutUnit(200), LayoutUnit(100)),
- /* shrink_to_fit */ true, /* is_new_formatting_context */ true);
- NGConstraintSpace space250 = ConstructBlockLayoutTestConstraintSpace(
- WritingMode::kHorizontalTb, TextDirection::kLtr,
- LogicalSize(LayoutUnit(250), LayoutUnit(100)),
- /* shrink_to_fit */ true, /* is_new_formatting_context */ true);
- NGConstraintSpace space300 = ConstructBlockLayoutTestConstraintSpace(
- WritingMode::kHorizontalTb, TextDirection::kLtr,
- LogicalSize(LayoutUnit(300), LayoutUnit(100)),
- /* shrink_to_fit */ true, /* is_new_formatting_context */ true);
- NGConstraintSpace space400 = ConstructBlockLayoutTestConstraintSpace(
- WritingMode::kHorizontalTb, TextDirection::kLtr,
- LogicalSize(LayoutUnit(400), LayoutUnit(100)),
- /* shrink_to_fit */ true, /* is_new_formatting_context */ true);
- scoped_refptr<const NGLayoutResult> result;
-
- auto* box1 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("box1"));
- auto* box2 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("box2"));
- auto* box3 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("box3"));
- auto* box4 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("box4"));
-
- // Ensure we cached the result for box1 in the first layout pass.
- result = RunCachedLayoutResult(space300, NGBlockNode(box1));
- EXPECT_NE(result.get(), nullptr);
-
- // box1 was sized to its max-content size in the first layout pass, passing
- // an available size larger than the fragment should hit the cache.
- result = RunCachedLayoutResult(space400, NGBlockNode(box1));
- EXPECT_NE(result.get(), nullptr);
-
- // Passing an available size smaller than the fragment should miss the cache
- // as the fragment may shrink.
- result = RunCachedLayoutResult(space100, NGBlockNode(box1));
- EXPECT_EQ(result.get(), nullptr);
-
- // Ensure we cached the result for box2 in the first layout pass.
- result = RunCachedLayoutResult(space300, NGBlockNode(box2));
- EXPECT_NE(result.get(), nullptr);
-
- // box2 was sized to its min-content size in the first layout pass, passing
- // an available size smaller than the fragment should hit the cache.
- result = RunCachedLayoutResult(space200, NGBlockNode(box2));
- EXPECT_NE(result.get(), nullptr);
-
- // Passing an available size larger than the fragment should miss the cache
- // as the fragment may shrink.
- result = RunCachedLayoutResult(space400, NGBlockNode(box2));
- EXPECT_EQ(result.get(), nullptr);
-
- // box3 was sized to its min-content size in the first layout pass, however
- // it should miss the cache as it has a %-min-size.
- result = RunCachedLayoutResult(space200, NGBlockNode(box3));
- EXPECT_EQ(result.get(), nullptr);
-
- // box4 was sized to its max-content size in the first layout pass (the same
- // as box1) however it should miss the cache due to its margin.
- result = RunCachedLayoutResult(space250, NGBlockNode(box4));
- EXPECT_EQ(result.get(), nullptr);
-}
-
TEST_F(NGBlockLayoutAlgorithmTest, LineOffsetCaching) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
SetBodyInnerHTML(R"HTML(
<div id="container" style="display: flow-root; width: 300px; height: 100px;">
<div id="box1" style="width: 100px; margin: 0 auto 0 auto;"></div>
@@ -404,10 +306,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, LineOffsetCaching) {
builder.SetAvailableSize(size);
builder.SetPercentageResolutionSize(size);
builder.SetTextDirection(TextDirection::kLtr);
- builder.AddBaselineRequest({NGBaselineAlgorithmType::kAtomicInline,
- FontBaseline::kAlphabeticBaseline});
- builder.AddBaselineRequest({NGBaselineAlgorithmType::kFirstLine,
- FontBaseline::kAlphabeticBaseline});
+ builder.SetNeedsBaseline(true);
builder.SetBfcOffset(bfc_offset);
return builder.ToConstraintSpace();
};
@@ -1645,7 +1544,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, ComputeMinMaxContent) {
NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
- MinMaxSize sizes = RunComputeMinAndMax(container);
+ MinMaxSizes sizes = RunComputeMinMaxSizes(container);
EXPECT_EQ(kSecondChildWidth, sizes.min_size);
EXPECT_EQ(kSecondChildWidth, sizes.max_size);
}
@@ -1666,7 +1565,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, ComputeMinMaxContentFloats) {
NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
- MinMaxSize sizes = RunComputeMinAndMax(container);
+ MinMaxSizes sizes = RunComputeMinMaxSizes(container);
EXPECT_EQ(LayoutUnit(40), sizes.min_size);
EXPECT_EQ(LayoutUnit(90), sizes.max_size);
}
@@ -1687,7 +1586,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, ComputeMinMaxContentFloatsClearance) {
NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
- MinMaxSize sizes = RunComputeMinAndMax(container);
+ MinMaxSizes sizes = RunComputeMinMaxSizes(container);
EXPECT_EQ(LayoutUnit(40), sizes.min_size);
EXPECT_EQ(LayoutUnit(50), sizes.max_size);
}
@@ -1708,7 +1607,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, ComputeMinMaxContentNewFormattingContext) {
NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
- MinMaxSize sizes = RunComputeMinAndMax(container);
+ MinMaxSizes sizes = RunComputeMinMaxSizes(container);
EXPECT_EQ(LayoutUnit(100), sizes.min_size);
EXPECT_EQ(LayoutUnit(100), sizes.max_size);
}
@@ -1730,7 +1629,7 @@ TEST_F(NGBlockLayoutAlgorithmTest,
NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
- MinMaxSize sizes = RunComputeMinAndMax(container);
+ MinMaxSizes sizes = RunComputeMinMaxSizes(container);
EXPECT_EQ(LayoutUnit(30), sizes.min_size);
EXPECT_EQ(LayoutUnit(70), sizes.max_size);
}
@@ -1748,7 +1647,7 @@ TEST_F(NGBlockLayoutAlgorithmTest,
NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
- MinMaxSize sizes = RunComputeMinAndMax(container);
+ MinMaxSizes sizes = RunComputeMinMaxSizes(container);
EXPECT_EQ(LayoutUnit(), sizes.min_size);
EXPECT_EQ(LayoutUnit(), sizes.max_size);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
index 301d9e9215b..48871b0c4f8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc
@@ -7,8 +7,11 @@
#include <memory>
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/html_marquee_element.h"
+#include "third_party/blink/renderer/core/input_type_names.h"
#include "third_party/blink/renderer/core/layout/box_layout_extra_input.h"
+#include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_fieldset.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
@@ -17,7 +20,8 @@
#include "third_party/blink/renderer/core/layout/layout_multi_column_spanner_placeholder.h"
#include "third_party/blink/renderer/core/layout/layout_table.h"
#include "third_party/blink/renderer/core/layout/layout_table_cell.h"
-#include "third_party/blink/renderer/core/layout/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/layout_video.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "third_party/blink/renderer/core/layout/ng/custom/layout_ng_custom.h"
#include "third_party/blink/renderer/core/layout/ng/custom/ng_custom_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_fragment_geometry.h"
@@ -25,6 +29,10 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
+#include "third_party/blink/renderer/core/layout/ng/mathml/ng_math_fraction_layout_algorithm.h"
+#include "third_party/blink/renderer/core/layout/ng/mathml/ng_math_layout_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/mathml/ng_math_row_layout_algorithm.h"
+#include "third_party/blink/renderer/core/layout/ng/mathml/ng_math_space_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
@@ -43,6 +51,10 @@
#include "third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
#include "third_party/blink/renderer/core/layout/shapes/shape_outside_info.h"
+#include "third_party/blink/renderer/core/layout/text_autosizer.h"
+#include "third_party/blink/renderer/core/mathml/mathml_element.h"
+#include "third_party/blink/renderer/core/mathml/mathml_fraction_element.h"
+#include "third_party/blink/renderer/core/mathml/mathml_space_element.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
@@ -74,6 +86,24 @@ NOINLINE void CreateAlgorithmAndRun(const NGLayoutAlgorithmParams& params,
}
template <typename Callback>
+NOINLINE void DetermineMathMLAlgorithmAndRun(
+ const LayoutBox& box,
+ const NGLayoutAlgorithmParams& params,
+ const Callback& callback) {
+ DCHECK(box.IsMathML());
+ // Currently math layout algorithms can only apply to MathML elements.
+ auto* element = box.GetNode();
+ DCHECK(element);
+ if (IsA<MathMLSpaceElement>(element))
+ CreateAlgorithmAndRun<NGMathSpaceLayoutAlgorithm>(params, callback);
+ else if (IsA<MathMLFractionElement>(element) &&
+ IsValidMathMLFraction(params.node))
+ CreateAlgorithmAndRun<NGMathFractionLayoutAlgorithm>(params, callback);
+ else
+ CreateAlgorithmAndRun<NGMathRowLayoutAlgorithm>(params, callback);
+}
+
+template <typename Callback>
NOINLINE void DetermineAlgorithmAndRun(const NGLayoutAlgorithmParams& params,
const Callback& callback) {
const ComputedStyle& style = params.node.Style();
@@ -82,6 +112,8 @@ NOINLINE void DetermineAlgorithmAndRun(const NGLayoutAlgorithmParams& params,
CreateAlgorithmAndRun<NGFlexLayoutAlgorithm>(params, callback);
} else if (box.IsLayoutNGCustom()) {
CreateAlgorithmAndRun<NGCustomLayoutAlgorithm>(params, callback);
+ } else if (box.IsMathML()) {
+ DetermineMathMLAlgorithmAndRun(box, params, callback);
} else if (box.IsLayoutNGFieldset()) {
CreateAlgorithmAndRun<NGFieldsetLayoutAlgorithm>(params, callback);
// If there's a legacy layout box, we can only do block fragmentation if
@@ -108,15 +140,15 @@ inline scoped_refptr<const NGLayoutResult> LayoutWithAlgorithm(
return result;
}
-inline base::Optional<MinMaxSize> ComputeMinMaxSizeWithAlgorithm(
+inline base::Optional<MinMaxSizes> ComputeMinMaxSizesWithAlgorithm(
const NGLayoutAlgorithmParams& params,
- const MinMaxSizeInput& input) {
- base::Optional<MinMaxSize> minmax;
+ const MinMaxSizesInput& input) {
+ base::Optional<MinMaxSizes> min_max_sizes;
DetermineAlgorithmAndRun(
- params, [&minmax, &input](NGLayoutAlgorithmOperations* algorithm) {
- minmax = algorithm->ComputeMinMaxSize(input);
+ params, [&min_max_sizes, &input](NGLayoutAlgorithmOperations* algorithm) {
+ min_max_sizes = algorithm->ComputeMinMaxSizes(input);
});
- return minmax;
+ return min_max_sizes;
}
void UpdateLegacyMultiColumnFlowThread(
@@ -131,7 +163,7 @@ void UpdateLegacyMultiColumnFlowThread(
// Stitch the columns together.
NGBoxStrut border_scrollbar_padding =
- ComputeBorders(constraint_space, node) +
+ ComputeBorders(constraint_space, node.Style()) +
ComputeScrollbars(constraint_space, node) +
ComputePadding(constraint_space, node.Style());
NGFragment logical_multicol_fragment(writing_mode, fragment);
@@ -171,7 +203,8 @@ void UpdateLegacyMultiColumnFlowThread(
if (!has_processed_first_column_in_flow_thread) {
// The offset of the flow thread should be the same as that of the first
// first column.
- flow_thread->SetLocation(child.Offset().ToLayoutPoint());
+ flow_thread->SetLocationAndUpdateOverflowControlsIfNeeded(
+ child.Offset().ToLayoutPoint());
flow_thread->SetLogicalWidth(logical_column_fragment.InlineSize());
has_processed_first_column_in_flow_thread = true;
}
@@ -267,11 +300,36 @@ void SetupBoxLayoutExtraInput(const NGConstraintSpace& space,
input->override_block_size = space.AvailableSize().block_size;
}
+bool CanUseCachedIntrinsicInlineSizes(const MinMaxSizesInput& input,
+ const LayoutBox& box) {
+ // Obviously can't use the cache if our intrinsic logical widths are dirty.
+ if (box.IntrinsicLogicalWidthsDirty())
+ return false;
+
+ // We don't store the float inline sizes for comparison, always skip the
+ // cache in this case.
+ if (input.float_left_inline_size || input.float_right_inline_size)
+ return false;
+
+ // Check if we have any percentage inline padding.
+ const auto& style = box.StyleRef();
+ if (style.MayHavePadding() && (style.PaddingStart().IsPercentOrCalc() ||
+ style.PaddingEnd().IsPercentOrCalc()))
+ return false;
+
+ // Check if the %-block-size matches.
+ if (input.percentage_resolution_block_size !=
+ box.IntrinsicLogicalWidthsPercentageResolutionBlockSize())
+ return false;
+
+ return true;
+}
+
} // namespace
scoped_refptr<const NGLayoutResult> NGBlockNode::Layout(
const NGConstraintSpace& constraint_space,
- const NGBreakToken* break_token,
+ const NGBlockBreakToken* break_token,
const NGEarlyBreak* early_break) {
// Use the old layout code and synthesize a fragment.
if (!CanUseNewLayout())
@@ -296,8 +354,8 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::Layout(
scoped_refptr<const NGLayoutResult> layout_result =
box_->CachedLayoutResult(constraint_space, break_token, early_break,
&fragment_geometry, &cache_status);
- if (layout_result) {
- DCHECK_EQ(cache_status, NGLayoutCacheStatus::kHit);
+ if (cache_status == NGLayoutCacheStatus::kHit) {
+ DCHECK(layout_result);
// We may have to update the margins on box_; we reuse the layout result
// even if a percentage margin may have changed.
@@ -325,11 +383,13 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::Layout(
CalculateInitialFragmentGeometry(constraint_space, *this);
}
+ TextAutosizer::NGLayoutScope text_autosizer_layout_scope(
+ box_, fragment_geometry->border_box_size.inline_size);
+
PrepareForLayout();
NGLayoutAlgorithmParams params(*this, *fragment_geometry, constraint_space,
- To<NGBlockBreakToken>(break_token),
- early_break);
+ break_token, early_break);
// Try to perform "simplified" layout.
// TODO(crbug.com/992953): Add a simplified layout pass for custom layout.
@@ -339,26 +399,33 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::Layout(
!(block_flow->ChildrenInline() &&
RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) &&
!block_flow->IsLayoutNGCustom()) {
+ DCHECK(layout_result);
+#if DCHECK_IS_ON()
+ scoped_refptr<const NGLayoutResult> previous_result = layout_result;
+#endif
+
// A child may have changed size while performing "simplified" layout (it
// may have gained or removed scrollbars, changing its size). In these
// cases "simplified" layout will return a null layout-result, indicating
// we need to perform a full layout.
- layout_result = RunSimplifiedLayout(params);
+ layout_result = RunSimplifiedLayout(params, *layout_result);
#if DCHECK_IS_ON()
if (layout_result) {
layout_result->CheckSameForSimplifiedLayout(
- *box_->GetCachedLayoutResult(), /* check_same_block_size */ false);
+ *previous_result, /* check_same_block_size */ false);
}
#endif
+ } else {
+ layout_result = nullptr;
}
// Fragment geometry scrollbars are potentially size constrained, and cannot
// be used for comparison with their after layout size.
NGBoxStrut before_layout_scrollbars =
ComputeScrollbars(constraint_space, *this);
- bool before_layout_preferred_logical_widths_dirty =
- box_->PreferredLogicalWidthsDirty();
+ bool before_layout_intrinsic_logical_widths_dirty =
+ box_->IntrinsicLogicalWidthsDirty();
if (!layout_result)
layout_result = LayoutWithAlgorithm(params);
@@ -373,10 +440,15 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::Layout(
// This mirrors legacy code in PaintLayerScrollableArea::UpdateAfterLayout.
if ((before_layout_scrollbars !=
ComputeScrollbars(constraint_space, *this)) ||
- (!before_layout_preferred_logical_widths_dirty &&
- box_->PreferredLogicalWidthsDirty())) {
+ (!before_layout_intrinsic_logical_widths_dirty &&
+ box_->IntrinsicLogicalWidthsDirty())) {
PaintLayerScrollableArea::FreezeScrollbarsScope freeze_scrollbars;
+ // We need to clear any previous results when scrollbars change. For
+ // example - we may have stored a "measure" layout result which will be
+ // incorrect if we try and reuse it.
+ box_->ClearLayoutResults();
+
#if DCHECK_IS_ON()
// Ensure turning on/off scrollbars only once at most, when we call
// |LayoutWithAlgorithm| recursively.
@@ -506,18 +578,32 @@ void NGBlockNode::PrepareForLayout() {
void NGBlockNode::FinishLayout(
LayoutBlockFlow* block_flow,
const NGConstraintSpace& constraint_space,
- const NGBreakToken* break_token,
+ const NGBlockBreakToken* break_token,
scoped_refptr<const NGLayoutResult> layout_result) {
// If we abort layout and don't clear the cached layout-result, we can end
// up in a state where the layout-object tree doesn't match fragment tree
// referenced by this layout-result.
if (layout_result->Status() != NGLayoutResult::kSuccess) {
- box_->ClearCachedLayoutResult();
+ box_->ClearLayoutResults();
return;
}
- if (!constraint_space.HasBlockFragmentation())
- box_->SetCachedLayoutResult(*layout_result, break_token);
+ // Add all layout results (and fragments) generated from a node to a list in
+ // the layout object. Some extra care is required to correctly overwrite
+ // intermediate layout results: The sequence number of an incoming break token
+ // corresponds with the fragment index in the layout object (off by 1,
+ // though). When writing back a layout result, we remove any fragments in the
+ // layout box at higher indices than that of the one we're writing back.
+ const auto& physical_fragment =
+ To<NGPhysicalBoxFragment>(layout_result->PhysicalFragment());
+ wtf_size_t fragment_index = 0;
+ if (break_token && !break_token->IsBreakBefore())
+ fragment_index = break_token->SequenceNumber() + 1;
+
+ if (layout_result->IsSingleUse())
+ box_->AddLayoutResult(layout_result, fragment_index);
+ else
+ box_->SetCachedLayoutResult(layout_result);
if (block_flow) {
auto* child = GetLayoutObjectForFirstChildNode(block_flow);
@@ -543,40 +629,28 @@ void NGBlockNode::FinishLayout(
}
if (has_inline_children) {
- const auto& physical_fragment =
- To<NGPhysicalBoxFragment>(layout_result->PhysicalFragment());
if (!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
CopyFragmentDataToLayoutBoxForInlineChildren(
physical_fragment, physical_fragment.Size().width,
Style().IsFlippedBlocksWritingMode());
- block_flow->SetPaintFragment(To<NGBlockBreakToken>(break_token),
- &physical_fragment);
+ block_flow->SetPaintFragment(break_token, &physical_fragment);
} else {
CopyFragmentDataToLayoutBoxForInlineChildren(physical_fragment);
-
- // Floats are in the fragment tree, not in the item list, and the
- // painter relies on |LayoutBox.Location()|.
- if (physical_fragment.HasFloatingDescendantsForPaint()) {
- CopyFragmentDataToLayoutBoxForInlineChildren(
- physical_fragment, physical_fragment.Size().width,
- Style().IsFlippedBlocksWritingMode());
- }
}
} else {
// We still need to clear paint fragments in case it had inline children,
// and thus had NGPaintFragment.
block_flow->ClearNGInlineNodeData();
- block_flow->SetPaintFragment(To<NGBlockBreakToken>(break_token), nullptr);
+ block_flow->SetPaintFragment(break_token, nullptr);
}
}
- CopyFragmentDataToLayoutBox(constraint_space, *layout_result,
- To<NGBlockBreakToken>(break_token));
+ CopyFragmentDataToLayoutBox(constraint_space, *layout_result, break_token);
}
-MinMaxSize NGBlockNode::ComputeMinMaxSize(
+MinMaxSizes NGBlockNode::ComputeMinMaxSizes(
WritingMode container_writing_mode,
- const MinMaxSizeInput& input,
+ const MinMaxSizesInput& input,
const NGConstraintSpace* constraint_space) {
// TODO(layoutng) Can UpdateMarkerTextIfNeeded call be moved
// somewhere else? List items need up-to-date markers before layout.
@@ -586,13 +660,17 @@ MinMaxSize NGBlockNode::ComputeMinMaxSize(
bool is_orthogonal_flow_root =
!IsParallelWritingMode(container_writing_mode, Style().GetWritingMode());
- MinMaxSize sizes;
+ if (CanUseCachedIntrinsicInlineSizes(input, *box_))
+ return box_->IntrinsicLogicalWidths();
+
+ box_->SetIntrinsicLogicalWidthsDirty();
+
+ MinMaxSizes sizes;
// If we're orthogonal, we have to run layout to compute the sizes. However,
// if we're outside of layout, we can't do that. This can happen on Mac.
if ((!CanUseNewLayout() && !is_orthogonal_flow_root) ||
- (is_orthogonal_flow_root && !box_->GetFrameView()->IsInPerformLayout())) {
- return ComputeMinMaxSizeFromLegacy(input);
- }
+ (is_orthogonal_flow_root && !box_->GetFrameView()->IsInPerformLayout()))
+ return ComputeMinMaxSizesFromLegacy(input);
NGConstraintSpace zero_constraint_space =
CreateConstraintSpaceBuilderForMinMax(*this).ToConstraintSpace();
@@ -614,18 +692,12 @@ MinMaxSize NGBlockNode::ComputeMinMaxSize(
TextDirection::kLtr, // irrelevant here
To<NGPhysicalBoxFragment>(layout_result->PhysicalFragment()));
sizes.min_size = sizes.max_size = fragment.Size().inline_size;
- if (input.size_type == NGMinMaxSizeType::kContentBoxSize) {
- sizes -= fragment.Borders().InlineSum() + fragment.Padding().InlineSum() +
- box_->ScrollbarLogicalWidth();
- DCHECK_GE(sizes.min_size, LayoutUnit());
- DCHECK_GE(sizes.max_size, LayoutUnit());
- }
return sizes;
}
NGFragmentGeometry fragment_geometry =
CalculateInitialMinMaxFragmentGeometry(*constraint_space, *this);
- base::Optional<MinMaxSize> maybe_sizes = ComputeMinMaxSizeWithAlgorithm(
+ base::Optional<MinMaxSizes> maybe_sizes = ComputeMinMaxSizesWithAlgorithm(
NGLayoutAlgorithmParams(*this, fragment_geometry, *constraint_space),
input);
@@ -633,13 +705,21 @@ MinMaxSize NGBlockNode::ComputeMinMaxSize(
auto* html_marquee_element = DynamicTo<HTMLMarqueeElement>(box_->GetNode());
if (UNLIKELY(html_marquee_element && html_marquee_element->IsHorizontal()))
maybe_sizes->min_size = LayoutUnit();
+ else if (UNLIKELY(IsA<HTMLSelectElement>(box_->GetNode()) ||
+ (IsA<HTMLInputElement>(box_->GetNode()) &&
+ To<HTMLInputElement>(box_->GetNode())->type() ==
+ input_type_names::kFile)) &&
+ Style().LogicalWidth().IsPercentOrCalc())
+ maybe_sizes->min_size = LayoutUnit();
+ box_->SetIntrinsicLogicalWidthsFromNG(
+ *maybe_sizes, input.percentage_resolution_block_size);
return *maybe_sizes;
}
if (!box_->GetFrameView()->IsInPerformLayout()) {
// We can't synthesize these using Layout() if we're not in PerformLayout.
// This situation can happen on mac. Fall back to legacy instead.
- return ComputeMinMaxSizeFromLegacy(input);
+ return ComputeMinMaxSizesFromLegacy(input);
}
// Have to synthesize this value.
@@ -662,18 +742,11 @@ MinMaxSize NGBlockNode::ComputeMinMaxSize(
TextDirection::kLtr, // irrelevant here
To<NGPhysicalBoxFragment>(layout_result->PhysicalFragment()));
sizes.max_size = max_fragment.Size().inline_size;
-
- if (input.size_type == NGMinMaxSizeType::kContentBoxSize) {
- sizes -= max_fragment.Borders().InlineSum() +
- max_fragment.Padding().InlineSum() + box_->ScrollbarLogicalWidth();
- DCHECK_GE(sizes.min_size, LayoutUnit());
- DCHECK_GE(sizes.max_size, LayoutUnit());
- }
return sizes;
}
-MinMaxSize NGBlockNode::ComputeMinMaxSizeFromLegacy(
- const MinMaxSizeInput& input) const {
+MinMaxSizes NGBlockNode::ComputeMinMaxSizesFromLegacy(
+ const MinMaxSizesInput& input) const {
bool needs_size_reset = false;
if (!box_->HasOverrideContainingBlockContentLogicalHeight()) {
box_->SetOverrideContainingBlockContentLogicalHeight(
@@ -681,16 +754,13 @@ MinMaxSize NGBlockNode::ComputeMinMaxSizeFromLegacy(
needs_size_reset = true;
}
- MinMaxSize sizes;
- // ComputeIntrinsicLogicalWidths returns content-box + scrollbar.
- box_->ComputeIntrinsicLogicalWidths(sizes.min_size, sizes.max_size);
- if (input.size_type == NGMinMaxSizeType::kContentBoxSize) {
- sizes -= LayoutUnit(box_->ScrollbarLogicalWidth());
- DCHECK_GE(sizes.min_size, LayoutUnit());
- DCHECK_GE(sizes.max_size, LayoutUnit());
- } else {
- sizes += box_->BorderAndPaddingLogicalWidth();
- }
+ // Tables don't calculate their min/max content contribution the same way as
+ // other layout nodes. This is because width/min-width/etc have a different
+ // meaning for tables.
+ //
+ // Due to this the min/max content contribution is their min/max content size.
+ MinMaxSizes sizes = box_->IsTable() ? box_->PreferredLogicalWidths()
+ : box_->IntrinsicLogicalWidths();
if (needs_size_reset)
box_->ClearOverrideContainingBlockContentSize();
@@ -857,10 +927,9 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
LayoutBlock* block = DynamicTo<LayoutBlock>(box_);
bool needs_full_invalidation = false;
if (LIKELY(block && is_last_fragment)) {
- LayoutUnit intrinsic_block_size =
- layout_result.UnconstrainedIntrinsicBlockSize();
+ LayoutUnit overflow_block_size = layout_result.OverflowBlockSize();
if (UNLIKELY(previous_break_token))
- intrinsic_block_size += previous_break_token->ConsumedBlockSize();
+ overflow_block_size += previous_break_token->ConsumedBlockSize();
#if DCHECK_IS_ON()
block->CheckPositionedObjectsNeedLayout();
@@ -881,10 +950,9 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
// |ComputeOverflow()| below calls |AddVisualOverflowFromChildren()|, which
// computes visual overflow from |RootInlineBox| if |ChildrenInline()|
- // TODO(rego): This causes that ChildNeedsLayoutOverflowRecalc flags are not
- // cleared after layout (see https://crbug.com/941180).
- block->SetNeedsOverflowRecalc();
- block->ComputeLayoutOverflow(intrinsic_block_size - borders.block_end -
+ block->SetNeedsOverflowRecalc(
+ LayoutObject::OverflowRecalcType::kOnlyVisualOverflowRecalc);
+ block->ComputeLayoutOverflow(overflow_block_size - borders.block_end -
scrollbars.block_end);
}
@@ -915,7 +983,7 @@ void NGBlockNode::PlaceChildrenInLayoutBox(
for (const auto& child_fragment : physical_fragment.Children()) {
// Skip any line-boxes we have as children, this is handled within
// NGInlineNode at the moment.
- if (!child_fragment->IsBox() && !child_fragment->IsRenderedLegend())
+ if (!child_fragment->IsBox())
continue;
const auto& box_fragment = *To<NGPhysicalBoxFragment>(child_fragment.get());
@@ -940,7 +1008,7 @@ void NGBlockNode::PlaceChildrenInLayoutBox(
DCHECK(IsA<HTMLFieldSetElement>(content_wrapper->Parent()->GetNode()));
LayoutPoint location = rendered_legend->Location();
location -= content_wrapper->Location();
- rendered_legend->SetLocation(location);
+ rendered_legend->SetLocationAndUpdateOverflowControlsIfNeeded(location);
}
}
@@ -996,7 +1064,8 @@ void NGBlockNode::CopyChildFragmentPosition(
offset.left += consumed;
}
- layout_box->SetLocation(offset.ToLayoutPoint());
+ layout_box->SetLocationAndUpdateOverflowControlsIfNeeded(
+ offset.ToLayoutPoint());
}
// For inline children, NG painters handles fragments directly, but there are
@@ -1007,6 +1076,7 @@ void NGBlockNode::CopyFragmentDataToLayoutBoxForInlineChildren(
LayoutUnit initial_container_width,
bool initial_container_is_flipped,
PhysicalOffset offset) {
+ DCHECK(!RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
for (const auto& child : container.Children()) {
if (child->IsContainer()) {
PhysicalOffset child_offset = offset + child.Offset();
@@ -1022,7 +1092,8 @@ void NGBlockNode::CopyFragmentDataToLayoutBoxForInlineChildren(
child->Size().width -
maybe_flipped_offset.left;
}
- layout_box.SetLocation(maybe_flipped_offset.ToLayoutPoint());
+ layout_box.SetLocationAndUpdateOverflowControlsIfNeeded(
+ maybe_flipped_offset.ToLayoutPoint());
}
// Legacy compatibility. This flag is used in paint layer for
@@ -1038,7 +1109,7 @@ void NGBlockNode::CopyFragmentDataToLayoutBoxForInlineChildren(
// LayoutBlockFlow. If |child| establishes a new block formatting context,
// it also creates another inline formatting context. Do not copy to its
// descendants in this case.
- if (!child->IsBlockFormattingContextRoot()) {
+ if (!child->IsFormattingContextRoot()) {
CopyFragmentDataToLayoutBoxForInlineChildren(
To<NGPhysicalContainerFragment>(*child), initial_container_width,
initial_container_is_flipped, child_offset);
@@ -1055,20 +1126,22 @@ void NGBlockNode::CopyFragmentDataToLayoutBoxForInlineChildren(
return;
bool initial_container_is_flipped = Style().IsFlippedBlocksWritingMode();
for (NGInlineCursor cursor(*items); cursor; cursor.MoveToNext()) {
- if (const NGPhysicalBoxFragment* child = cursor.CurrentBoxFragment()) {
+ if (const NGPhysicalBoxFragment* child = cursor.Current().BoxFragment()) {
// Replaced elements and inline blocks need Location() set relative to
// their block container.
LayoutObject* layout_object = child->GetMutableLayoutObject();
if (!layout_object)
continue;
if (LayoutBox* layout_box = ToLayoutBoxOrNull(layout_object)) {
- PhysicalOffset maybe_flipped_offset = cursor.CurrentOffset();
+ PhysicalOffset maybe_flipped_offset =
+ cursor.Current().OffsetInContainerBlock();
if (initial_container_is_flipped) {
maybe_flipped_offset.left = container.Size().width -
child->Size().width -
maybe_flipped_offset.left;
}
- layout_box->SetLocation(maybe_flipped_offset.ToLayoutPoint());
+ layout_box->SetLocationAndUpdateOverflowControlsIfNeeded(
+ maybe_flipped_offset.ToLayoutPoint());
continue;
}
@@ -1085,9 +1158,9 @@ void NGBlockNode::CopyFragmentDataToLayoutBoxForInlineChildren(
}
}
-bool NGBlockNode::ChildrenInline() const {
+bool NGBlockNode::IsInlineFormattingContextRoot() const {
if (const auto* block = DynamicTo<LayoutBlockFlow>(box_))
- return AreNGBlockFlowChildrenInline(block);
+ return AreNGBlockFlowChildrenInline(block) && FirstChild().IsInline();
return false;
}
@@ -1101,10 +1174,28 @@ bool NGBlockNode::IsAtomicInlineLevel() const {
return GetLayoutBox()->IsAtomicInlineLevel() && GetLayoutBox()->IsInline();
}
-bool NGBlockNode::MayHaveAspectRatio() const {
+bool NGBlockNode::HasAspectRatio() const {
LayoutBox* layout_object = GetLayoutBox();
- return layout_object->IsImage() || layout_object->IsVideo() ||
- layout_object->IsCanvas();
+ if (!layout_object->IsImage() && !IsA<LayoutVideo>(layout_object) &&
+ !layout_object->IsCanvas())
+ return false;
+
+ // Retrieving this and throwing it away is wasteful. We could make this method
+ // return Optional<LogicalSize> that returns the aspect_ratio if there is one.
+ return !GetAspectRatio().IsEmpty();
+}
+
+LogicalSize NGBlockNode::GetAspectRatio() const {
+ base::Optional<LayoutUnit> computed_inline_size;
+ base::Optional<LayoutUnit> computed_block_size;
+ GetOverrideIntrinsicSize(&computed_inline_size, &computed_block_size);
+ if (computed_inline_size && computed_block_size)
+ return LogicalSize(*computed_inline_size, *computed_block_size);
+
+ IntrinsicSizingInfo legacy_sizing_info;
+ ToLayoutReplaced(box_)->ComputeIntrinsicSizingInfo(legacy_sizing_info);
+ return LogicalSize(LayoutUnit(legacy_sizing_info.aspect_ratio.Width()),
+ LayoutUnit(legacy_sizing_info.aspect_ratio.Height()));
}
bool NGBlockNode::UseLogicalBottomMarginEdgeForInlineBlockBaseline() const {
@@ -1121,21 +1212,17 @@ bool NGBlockNode::IsCustomLayoutLoaded() const {
scoped_refptr<const NGLayoutResult> NGBlockNode::LayoutAtomicInline(
const NGConstraintSpace& parent_constraint_space,
const ComputedStyle& parent_style,
- FontBaseline baseline_type,
- bool use_first_line_style) {
+ bool use_first_line_style,
+ NGBaselineAlgorithmType baseline_algorithm_type) {
NGConstraintSpaceBuilder builder(
parent_constraint_space, Style().GetWritingMode(), /* is_new_fc */ true);
SetOrthogonalFallbackInlineSizeIfNeeded(parent_style, *this, &builder);
+ builder.SetIsPaintedAtomically(true);
builder.SetUseFirstLineStyle(use_first_line_style);
- // Request to compute baseline during the layout, except when we know the box
- // would synthesize box-baseline.
- LayoutBox* layout_box = GetLayoutBox();
- if (NGBaseline::ShouldPropagateBaselines(layout_box)) {
- builder.AddBaselineRequest(
- {NGBaselineAlgorithmType::kAtomicInline, baseline_type});
- }
+ builder.SetNeedsBaseline(true);
+ builder.SetBaselineAlgorithmType(baseline_algorithm_type);
builder.SetIsShrinkToFit(Style().LogicalWidth().IsAuto());
builder.SetAvailableSize(parent_constraint_space.AvailableSize());
@@ -1148,7 +1235,7 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::LayoutAtomicInline(
scoped_refptr<const NGLayoutResult> result = Layout(constraint_space);
// TODO(kojii): Investigate why ClearNeedsLayout() isn't called automatically
// when it's being laid out.
- layout_box->ClearNeedsLayout();
+ GetLayoutBox()->ClearNeedsLayout();
return result;
}
@@ -1208,7 +1295,13 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::RunLegacyLayout(
constraint_space.IsNewFormattingContext());
builder.SetInitialFragmentGeometry(fragment_geometry);
builder.SetIsLegacyLayoutRoot();
- builder.SetIntrinsicBlockSize(box_->IntrinsicContentLogicalHeight());
+ if (box_->ShouldComputeSizeAsReplaced()) {
+ builder.SetIntrinsicBlockSize(box_->LogicalHeight());
+ } else {
+ builder.SetIntrinsicBlockSize(box_->IntrinsicContentLogicalHeight() +
+ box_->BorderAndPaddingLogicalHeight() +
+ box_->ScrollbarLogicalHeight());
+ }
// If we're block-fragmented, we can only handle monolithic content, since
// the two block fragmentation machineries (NG and legacy) cannot cooperate.
@@ -1227,7 +1320,7 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::RunLegacyLayout(
CopyBaselinesFromLegacyLayout(constraint_space, &builder);
layout_result = builder.ToBoxFragment();
- box_->SetCachedLayoutResult(*layout_result, /* break_token */ nullptr);
+ box_->SetCachedLayoutResult(layout_result);
// If |SetCachedLayoutResult| did not update cached |LayoutResult|,
// |NeedsLayout()| flag should not be cleared.
@@ -1254,7 +1347,7 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::RunLegacyLayout(
*layout_result, constraint_space, layout_result->EndMarginStrut(),
layout_result->BfcLineOffset(), layout_result->BfcBlockOffset(),
LayoutUnit() /* block_offset_delta */));
- box_->SetCachedLayoutResult(*layout_result, /* break_token */ nullptr);
+ box_->SetCachedLayoutResult(layout_result);
}
}
@@ -1265,42 +1358,40 @@ scoped_refptr<const NGLayoutResult> NGBlockNode::RunLegacyLayout(
}
scoped_refptr<const NGLayoutResult> NGBlockNode::RunSimplifiedLayout(
- const NGLayoutAlgorithmParams& params) const {
- return NGSimplifiedLayoutAlgorithm(params, *box_->GetCachedLayoutResult())
- .Layout();
+ const NGLayoutAlgorithmParams& params,
+ const NGLayoutResult& result) const {
+ return NGSimplifiedLayoutAlgorithm(params, result).Layout();
}
void NGBlockNode::CopyBaselinesFromLegacyLayout(
const NGConstraintSpace& constraint_space,
NGBoxFragmentBuilder* builder) {
- const NGBaselineRequestList requests = constraint_space.BaselineRequests();
- if (requests.IsEmpty())
+ // As the calls to query baselines from legacy layout are potentially
+ // expensive we only ask for them if needed.
+ // TODO(layout-dev): Once we have flexbox, and editing switched over to
+ // LayoutNG we should be able to safely remove this flag without a
+ // performance penalty.
+ if (!constraint_space.NeedsBaseline())
return;
- if (UNLIKELY(constraint_space.GetWritingMode() != Style().GetWritingMode()))
- return;
-
- for (const auto& request : requests) {
- switch (request.AlgorithmType()) {
- case NGBaselineAlgorithmType::kAtomicInline: {
- LayoutUnit position =
- AtomicInlineBaselineFromLegacyLayout(request, constraint_space);
- if (position != -1)
- builder->AddBaseline(request, position);
- break;
- }
- case NGBaselineAlgorithmType::kFirstLine: {
- LayoutUnit position = box_->FirstLineBoxBaseline();
- if (position != -1)
- builder->AddBaseline(request, position);
- break;
- }
+ switch (constraint_space.BaselineAlgorithmType()) {
+ case NGBaselineAlgorithmType::kFirstLine: {
+ LayoutUnit position = box_->FirstLineBoxBaseline();
+ if (position != -1)
+ builder->SetBaseline(position);
+ break;
+ }
+ case NGBaselineAlgorithmType::kInlineBlock: {
+ LayoutUnit position =
+ AtomicInlineBaselineFromLegacyLayout(constraint_space);
+ if (position != -1)
+ builder->SetBaseline(position);
+ break;
}
}
}
LayoutUnit NGBlockNode::AtomicInlineBaselineFromLegacyLayout(
- const NGBaselineRequest& request,
const NGConstraintSpace& constraint_space) {
LineDirectionMode line_direction = box_->IsHorizontalWritingMode()
? LineDirectionMode::kHorizontalLine
@@ -1310,7 +1401,7 @@ LayoutUnit NGBlockNode::AtomicInlineBaselineFromLegacyLayout(
// classes override it assuming inline layout calls |BaselinePosition()|.
if (box_->IsInline()) {
LayoutUnit position = LayoutUnit(box_->BaselinePosition(
- request.BaselineType(), constraint_space.UseFirstLineStyle(),
+ box_->Style()->GetFontBaseline(), constraint_space.UseFirstLineStyle(),
line_direction, kPositionOnContainingLine));
// BaselinePosition() uses margin edge for atomic inlines. Subtract
@@ -1318,6 +1409,9 @@ LayoutUnit NGBlockNode::AtomicInlineBaselineFromLegacyLayout(
if (box_->IsAtomicInlineLevel())
position -= box_->MarginOver();
+ if (IsFlippedLinesWritingMode(constraint_space.GetWritingMode()))
+ return box_->Size().Width() - position;
+
return position;
}
@@ -1363,4 +1457,8 @@ void NGBlockNode::StoreMargins(const NGConstraintSpace& constraint_space,
box_->SetMargin(physical_margins);
}
+void NGBlockNode::StoreMargins(const NGPhysicalBoxStrut& physical_margins) {
+ box_->SetMargin(physical_margins);
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.h
index 91b6986774a..7ccb575505f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.h
@@ -14,16 +14,14 @@
namespace blink {
class LayoutBox;
-class NGBaselineRequest;
class NGBlockBreakToken;
class NGBoxFragmentBuilder;
-class NGBreakToken;
class NGConstraintSpace;
class NGEarlyBreak;
class NGLayoutResult;
class NGPhysicalBoxFragment;
class NGPhysicalContainerFragment;
-struct MinMaxSize;
+struct MinMaxSizes;
struct NGBoxStrut;
struct NGLayoutAlgorithmParams;
@@ -37,7 +35,7 @@ class CORE_EXPORT NGBlockNode final : public NGLayoutInputNode {
scoped_refptr<const NGLayoutResult> Layout(
const NGConstraintSpace& constraint_space,
- const NGBreakToken* break_token = nullptr,
+ const NGBlockBreakToken* break_token = nullptr,
const NGEarlyBreak* = nullptr);
// This method is just for use within the |NGSimplifiedLayoutAlgorithm|.
@@ -66,7 +64,7 @@ class CORE_EXPORT NGBlockNode final : public NGLayoutInputNode {
// Computes the value of min-content and max-content for this node's border
// box.
- // If the underlying layout algorithm's ComputeMinMaxSize returns
+ // If the underlying layout algorithm's ComputeMinMaxSizes returns
// no value, this function will synthesize these sizes using Layout with
// special constraint spaces -- infinite available size for max content, zero
// available size for min content, and percentage resolution size zero for
@@ -82,21 +80,29 @@ class CORE_EXPORT NGBlockNode final : public NGLayoutInputNode {
// The constraint space is also used to perform layout when this block's
// writing mode is orthogonal to its parent's, in which case the constraint
// space is not optional.
- MinMaxSize ComputeMinMaxSize(WritingMode container_writing_mode,
- const MinMaxSizeInput&,
- const NGConstraintSpace* = nullptr);
+ MinMaxSizes ComputeMinMaxSizes(WritingMode container_writing_mode,
+ const MinMaxSizesInput&,
+ const NGConstraintSpace* = nullptr);
- MinMaxSize ComputeMinMaxSizeFromLegacy(const MinMaxSizeInput&) const;
+ MinMaxSizes ComputeMinMaxSizesFromLegacy(const MinMaxSizesInput&) const;
NGLayoutInputNode FirstChild() const;
NGBlockNode GetRenderedLegend() const;
NGBlockNode GetFieldsetContent() const;
- bool ChildrenInline() const;
+ // Return true if this block node establishes an inline formatting context.
+ // This will only be the case if there is actual inline content. Empty nodes
+ // or nodes consisting purely of block-level, floats, and/or out-of-flow
+ // positioned children will return false.
+ bool IsInlineFormattingContextRoot() const;
+
bool IsInlineLevel() const;
bool IsAtomicInlineLevel() const;
- bool MayHaveAspectRatio() const;
+ bool HasAspectRatio() const;
+
+ // Returns the aspect ratio of a replaced element.
+ LogicalSize GetAspectRatio() const;
// Returns true if this node should fill the viewport.
// This occurs when we are in quirks-mode and we are *not* OOF-positioned,
@@ -127,8 +133,9 @@ class CORE_EXPORT NGBlockNode final : public NGLayoutInputNode {
scoped_refptr<const NGLayoutResult> LayoutAtomicInline(
const NGConstraintSpace& parent_constraint_space,
const ComputedStyle& parent_style,
- FontBaseline,
- bool use_first_line_style);
+ bool use_first_line_style,
+ NGBaselineAlgorithmType baseline_algorithm_type =
+ NGBaselineAlgorithmType::kInlineBlock);
// Called if this is an out-of-flow block which needs to be
// positioned with legacy layout.
@@ -136,6 +143,7 @@ class CORE_EXPORT NGBlockNode final : public NGLayoutInputNode {
// Write back resolved margins to legacy.
void StoreMargins(const NGConstraintSpace&, const NGBoxStrut& margins);
+ void StoreMargins(const NGPhysicalBoxStrut& margins);
static bool CanUseNewLayout(const LayoutBox&);
bool CanUseNewLayout() const;
@@ -150,13 +158,14 @@ class CORE_EXPORT NGBlockNode final : public NGLayoutInputNode {
scoped_refptr<const NGLayoutResult> RunLegacyLayout(const NGConstraintSpace&);
scoped_refptr<const NGLayoutResult> RunSimplifiedLayout(
- const NGLayoutAlgorithmParams&) const;
+ const NGLayoutAlgorithmParams&,
+ const NGLayoutResult&) const;
// If this node is a LayoutNGMixin, the caller must pass the layout object for
// this node cast to a LayoutBlockFlow as the first argument.
void FinishLayout(LayoutBlockFlow*,
const NGConstraintSpace&,
- const NGBreakToken*,
+ const NGBlockBreakToken*,
scoped_refptr<const NGLayoutResult>);
// After we run the layout algorithm, this function copies back the geometry
@@ -183,8 +192,7 @@ class CORE_EXPORT NGBlockNode final : public NGLayoutInputNode {
void CopyBaselinesFromLegacyLayout(const NGConstraintSpace&,
NGBoxFragmentBuilder*);
- LayoutUnit AtomicInlineBaselineFromLegacyLayout(const NGBaselineRequest&,
- const NGConstraintSpace&);
+ LayoutUnit AtomicInlineBaselineFromLegacyLayout(const NGConstraintSpace&);
void UpdateShapeOutsideInfoIfNeeded(
const NGLayoutResult&,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node_test.cc
index 8190b808e58..f42f0ef6ff5 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_block_node_test.cc
@@ -4,7 +4,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
-#include "third_party/blink/renderer/core/layout/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
namespace blink {
@@ -174,9 +174,9 @@ TEST_F(NGBlockNodeForTest, MinAndMaxContent) {
const int kWidth = 30;
NGBlockNode box(ToLayoutBox(GetLayoutObjectByElementId("box")));
- MinMaxSize sizes = box.ComputeMinMaxSize(
+ MinMaxSizes sizes = box.ComputeMinMaxSizes(
WritingMode::kHorizontalTb,
- MinMaxSizeInput(/* percentage_resolution_block_size */ LayoutUnit()));
+ MinMaxSizesInput(/* percentage_resolution_block_size */ LayoutUnit()));
EXPECT_EQ(LayoutUnit(kWidth), sizes.min_size);
EXPECT_EQ(LayoutUnit(kWidth), sizes.max_size);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.cc
index 20aef602f4e..f0b62aff415 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.cc
@@ -12,75 +12,46 @@
namespace blink {
-NGLineHeightMetrics NGBoxFragment::BaselineMetricsWithoutSynthesize(
- const NGBaselineRequest& request) const {
+NGLineHeightMetrics NGBoxFragment::BaselineMetrics(
+ const NGLineBoxStrut& margins,
+ FontBaseline baseline_type) const {
+ DCHECK(physical_fragment_.IsAtomicInline() ||
+ physical_fragment_.IsListMarker());
+ const ComputedStyle& style = physical_fragment_.Style();
+
// For "leaf" theme objects, let the theme decide what the baseline position
// is. The theme baseline wins over the propagated baselines.
- const auto& physical_fragment = To<NGPhysicalBoxFragment>(physical_fragment_);
- DCHECK(physical_fragment_.GetLayoutObject());
- const LayoutBox& layout_box =
- ToLayoutBox(*physical_fragment_.GetLayoutObject());
- const ComputedStyle& style = physical_fragment.Style();
if (style.HasEffectiveAppearance() &&
!LayoutTheme::GetTheme().IsControlContainer(
style.EffectiveAppearance())) {
return NGLineHeightMetrics(
- BlockSize() + layout_box.MarginOver() +
+ BlockSize() + margins.line_over +
LayoutTheme::GetTheme().BaselinePositionAdjustment(style),
- layout_box.MarginUnder());
+ margins.line_under);
}
- // Check if we have a propagated baseline.
- if (base::Optional<LayoutUnit> baseline =
- physical_fragment.Baseline(request)) {
- LayoutUnit ascent = *baseline;
- LayoutUnit descent = BlockSize() - ascent;
+ base::Optional<LayoutUnit> baseline = Baseline();
+ if (baseline) {
+ NGLineHeightMetrics metrics =
+ IsFlippedLinesWritingMode(GetWritingMode())
+ ? NGLineHeightMetrics(BlockSize() - *baseline, *baseline)
+ : NGLineHeightMetrics(*baseline, BlockSize() - *baseline);
- // For replaced elements, inline-block elements, and inline-table
- // elements, the height is the height of their margin box.
+ // For replaced elements, inline-block elements, and inline-table elements,
+ // the height is the height of their margin-box.
// https://drafts.csswg.org/css2/visudet.html#line-height
- if (layout_box.IsAtomicInlineLevel()) {
- ascent += layout_box.MarginOver();
- descent += layout_box.MarginUnder();
- }
+ metrics.ascent += margins.line_over;
+ metrics.descent += margins.line_under;
- return NGLineHeightMetrics(ascent, descent);
- }
-
- return NGLineHeightMetrics();
-}
-
-NGLineHeightMetrics NGBoxFragment::BaselineMetrics(
- const NGBaselineRequest& request,
- const NGConstraintSpace& constraint_space) const {
- // Try to compute the baseline if the writing-modes are the same.
- if (constraint_space.GetWritingMode() == GetWritingMode()) {
- NGLineHeightMetrics metrics = BaselineMetricsWithoutSynthesize(request);
- if (!metrics.IsEmpty())
- return metrics;
+ return metrics;
}
// The baseline type was not found. This is either this box should synthesize
// box-baseline without propagating from children, or caller forgot to add
// baseline requests to constraint space when it called Layout().
- LayoutUnit block_size = BlockSize();
-
- // If atomic inline, use the margin box. See above.
- const auto& physical_fragment = To<NGPhysicalBoxFragment>(physical_fragment_);
- DCHECK(physical_fragment_.GetLayoutObject());
- const LayoutBox& layout_box =
- ToLayoutBox(*physical_fragment_.GetLayoutObject());
- if (layout_box.IsAtomicInlineLevel()) {
- bool is_parallel_writing_mode =
- IsParallelWritingMode(constraint_space.GetWritingMode(),
- physical_fragment.Style().GetWritingMode());
- if (is_parallel_writing_mode)
- block_size += layout_box.MarginLogicalHeight();
- else
- block_size += layout_box.MarginLogicalWidth();
- }
+ LayoutUnit block_size = BlockSize() + margins.BlockSum();
- if (request.BaselineType() == kAlphabeticBaseline)
+ if (baseline_type == kAlphabeticBaseline)
return NGLineHeightMetrics(block_size, LayoutUnit());
return NGLineHeightMetrics(block_size - block_size / 2, block_size / 2);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
index dbfd474e7c8..f31585b148d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h
@@ -14,7 +14,6 @@
namespace blink {
-class NGBaselineRequest;
struct NGLineHeightMetrics;
class CORE_EXPORT NGBoxFragment final : public NGFragment {
@@ -24,18 +23,34 @@ class CORE_EXPORT NGBoxFragment final : public NGFragment {
const NGPhysicalBoxFragment& physical_fragment)
: NGFragment(writing_mode, physical_fragment), direction_(direction) {}
+ base::Optional<LayoutUnit> FirstBaseline() const {
+ if (GetWritingMode() != physical_fragment_.Style().GetWritingMode())
+ return base::nullopt;
+
+ return To<NGPhysicalBoxFragment>(physical_fragment_).Baseline();
+ }
+
+ // Returns the baseline for this fragment wrt. the parent writing mode. Will
+ // return a null baseline if:
+ // - The fragment has no baseline.
+ // - The writing modes differ.
+ base::Optional<LayoutUnit> Baseline() const {
+ if (GetWritingMode() != physical_fragment_.Style().GetWritingMode())
+ return base::nullopt;
+
+ if (auto last_baseline =
+ To<NGPhysicalBoxFragment>(physical_fragment_).LastBaseline())
+ return last_baseline;
+
+ return To<NGPhysicalBoxFragment>(physical_fragment_).Baseline();
+ }
+
// Compute baseline metrics (ascent/descent) for this box.
//
- // Baseline requests must be added to constraint space when this fragment was
- // laid out.
- //
- // The "WithoutSynthesize" version returns an empty metrics if this box does
- // not have any baselines, while the other version synthesize the baseline
- // from the box.
- NGLineHeightMetrics BaselineMetricsWithoutSynthesize(
- const NGBaselineRequest&) const;
- NGLineHeightMetrics BaselineMetrics(const NGBaselineRequest&,
- const NGConstraintSpace&) const;
+ // This will synthesize baseline metrics if no baseline is available. See
+ // |Baseline()| for when this may occur.
+ NGLineHeightMetrics BaselineMetrics(const NGLineBoxStrut& margins,
+ FontBaseline) const;
NGBoxStrut Borders() const {
const NGPhysicalBoxFragment& physical_box_fragment =
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
index 990d5a59d6d..96c7f46d336 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.cc
@@ -77,6 +77,70 @@ void GatherInlineContainerFragmentsFromLinebox(
}
}
+void GatherInlineContainerFragmentsFromItems(
+ const Vector<std::unique_ptr<NGFragmentItem>>& items,
+ const PhysicalOffset& box_offset,
+ NGBoxFragmentBuilder::InlineContainingBlockMap* inline_containing_block_map,
+ HashMap<const LayoutObject*, LineBoxPair>* containing_linebox_map) {
+ const NGPhysicalLineBoxFragment* linebox = nullptr;
+ for (const auto& item : items) {
+ // Track the current linebox.
+ if (const NGPhysicalLineBoxFragment* current_linebox =
+ item->LineBoxFragment()) {
+ linebox = current_linebox;
+ continue;
+ }
+
+ // We only care about inlines which have generated a box fragment.
+ const NGPhysicalBoxFragment* box = item->BoxFragment();
+ if (!box)
+ continue;
+
+ // The key for the inline is the continuation root if it exists.
+ const LayoutObject* key = box->GetLayoutObject();
+ if (key->IsLayoutInline() && key->GetNode())
+ key = key->ContinuationRoot();
+
+ // See if we need the containing block information for this inline.
+ auto it = inline_containing_block_map->find(key);
+ if (it == inline_containing_block_map->end())
+ continue;
+
+ base::Optional<NGBoxFragmentBuilder::InlineContainingBlockGeometry>&
+ containing_block_geometry = it->value;
+ LineBoxPair& containing_lineboxes =
+ containing_linebox_map->insert(key, LineBoxPair{nullptr, nullptr})
+ .stored_value->value;
+ DCHECK(containing_block_geometry.has_value() ||
+ !containing_lineboxes.first);
+
+ PhysicalRect fragment_rect = item->RectInContainerBlock();
+ fragment_rect.offset += box_offset;
+ if (containing_lineboxes.first == linebox) {
+ // Unite the start rect with the fragment's rect.
+ containing_block_geometry->start_fragment_union_rect.Unite(fragment_rect);
+ } else if (!containing_lineboxes.first) {
+ DCHECK(!containing_lineboxes.second);
+ // This is the first linebox we've encountered, initialize the containing
+ // block geometry.
+ containing_lineboxes.first = linebox;
+ containing_lineboxes.second = linebox;
+ containing_block_geometry =
+ NGBoxFragmentBuilder::InlineContainingBlockGeometry{fragment_rect,
+ fragment_rect};
+ }
+
+ if (containing_lineboxes.second == linebox) {
+ // Unite the end rect with the fragment's rect.
+ containing_block_geometry->end_fragment_union_rect.Unite(fragment_rect);
+ } else if (!linebox->IsEmptyLineBox()) {
+ // We've found a new "end" linebox, update the containing block geometry.
+ containing_lineboxes.second = linebox;
+ containing_block_geometry->end_fragment_union_rect = fragment_rect;
+ }
+ }
+}
+
} // namespace
void NGBoxFragmentBuilder::AddBreakBeforeChild(
@@ -121,8 +185,6 @@ void NGBoxFragmentBuilder::AddResult(const NGLayoutResult& child_layout_result,
items_builder_->AddLine(*line, offset);
// TODO(kojii): We probably don't need to AddChild this line, but there
// maybe OOF objects. Investigate how to handle them.
- } else {
- DCHECK(fragment.IsFloating());
}
}
AddChild(fragment, offset, inline_container);
@@ -156,6 +218,8 @@ NGPhysicalFragment::NGBoxType NGBoxFragmentBuilder::BoxType() const {
return NGPhysicalFragment::NGBoxType::kFloating;
if (layout_object_->IsOutOfFlowPositioned())
return NGPhysicalFragment::NGBoxType::kOutOfFlowPositioned;
+ if (layout_object_->IsRenderedLegend())
+ return NGPhysicalFragment::NGBoxType::kRenderedLegend;
if (layout_object_->IsInline()) {
// Check |IsAtomicInlineLevel()| after |IsInline()| because |LayoutReplaced|
// sets |IsAtomicInlineLevel()| even when it's block-level. crbug.com/567964
@@ -171,15 +235,6 @@ NGPhysicalFragment::NGBoxType NGBoxFragmentBuilder::BoxType() const {
return NGPhysicalFragment::NGBoxType::kNormalBox;
}
-void NGBoxFragmentBuilder::AddBaseline(NGBaselineRequest request,
- LayoutUnit offset) {
-#if DCHECK_IS_ON()
- for (const auto& baseline : baselines_)
- DCHECK(baseline.request != request);
-#endif
- baselines_.emplace_back(request, offset);
-}
-
EBreakBetween NGBoxFragmentBuilder::JoinedBreakBetweenValue(
EBreakBetween break_before) const {
return JoinFragmentainerBreakValues(previous_break_after_, break_before);
@@ -226,8 +281,8 @@ scoped_refptr<const NGLayoutResult> NGBoxFragmentBuilder::ToBoxFragment(
}
if (did_break_) {
break_token_ = NGBlockBreakToken::Create(
- node_, consumed_block_size_, child_break_tokens_, break_appeal_,
- has_seen_all_children_);
+ node_, consumed_block_size_, sequence_number_, child_break_tokens_,
+ break_appeal_, has_seen_all_children_);
}
}
@@ -240,18 +295,54 @@ scoped_refptr<const NGLayoutResult> NGBoxFragmentBuilder::ToBoxFragment(
NGPhysicalBoxFragment::Create(this, block_or_line_writing_mode);
fragment->CheckType();
- return base::AdoptRef(new NGLayoutResult(std::move(fragment), this));
+ return base::AdoptRef(
+ new NGLayoutResult(NGLayoutResult::NGBoxFragmentBuilderPassKey(),
+ std::move(fragment), this));
}
scoped_refptr<const NGLayoutResult> NGBoxFragmentBuilder::Abort(
NGLayoutResult::EStatus status) {
- return base::AdoptRef(new NGLayoutResult(status, this));
+ return base::AdoptRef(new NGLayoutResult(
+ NGLayoutResult::NGBoxFragmentBuilderPassKey(), status, this));
+}
+
+LogicalOffset NGBoxFragmentBuilder::GetChildOffset(
+ const LayoutObject* object) const {
+ DCHECK(object);
+
+ if (const NGFragmentItemsBuilder* items_builder = items_builder_) {
+ if (auto offset = items_builder->LogicalOffsetFor(*object))
+ return *offset;
+ NOTREACHED();
+ return LogicalOffset();
+ }
+
+ for (const auto& child : children_) {
+ if (child.fragment->GetLayoutObject() == object)
+ return child.offset;
+
+ // TODO(layout-dev): ikilpatrick thinks we may need to traverse
+ // further than the initial line-box children for a nested inline
+ // container. We could not come up with a testcase, it would be
+ // something with split inlines, and nested oof/fixed descendants maybe.
+ if (child.fragment->IsLineBox()) {
+ const auto& line_box_fragment =
+ To<NGPhysicalLineBoxFragment>(*child.fragment);
+ for (const auto& line_box_child : line_box_fragment.Children()) {
+ if (line_box_child->GetLayoutObject() == object) {
+ return child.offset + line_box_child.Offset().ConvertToLogical(
+ GetWritingMode(), Direction(),
+ line_box_fragment.Size(),
+ line_box_child->Size());
+ }
+ }
+ }
+ }
+ NOTREACHED();
+ return LogicalOffset();
}
-// Computes the geometry required for any inline containing blocks.
-// |inline_containing_block_map| is a map whose keys specify which inline
-// containing block geometry is required.
-void NGBoxFragmentBuilder::ComputeInlineContainerFragments(
+void NGBoxFragmentBuilder::ComputeInlineContainerGeometryFromFragmentTree(
InlineContainingBlockMap* inline_containing_block_map) {
if (inline_containing_block_map->IsEmpty())
return;
@@ -307,6 +398,59 @@ void NGBoxFragmentBuilder::ComputeInlineContainerFragments(
}
}
+void NGBoxFragmentBuilder::ComputeInlineContainerGeometry(
+ InlineContainingBlockMap* inline_containing_block_map) {
+ if (inline_containing_block_map->IsEmpty())
+ return;
+
+ // This function requires that we have the final size of the fragment set
+ // upon the builder.
+ DCHECK_GE(InlineSize(), LayoutUnit());
+ DCHECK_GE(BlockSize(), LayoutUnit());
+
+#if DCHECK_IS_ON()
+ // Make sure all entries are a continuation root.
+ for (const auto& entry : *inline_containing_block_map)
+ DCHECK_EQ(entry.key, entry.key->ContinuationRoot());
+#endif
+
+ HashMap<const LayoutObject*, LineBoxPair> containing_linebox_map;
+
+ if (items_builder_) {
+ // To access the items correctly we need to convert them to the physical
+ // coordinate space.
+ GatherInlineContainerFragmentsFromItems(
+ items_builder_->Items(GetWritingMode(), Direction(),
+ ToPhysicalSize(Size(), GetWritingMode())),
+ PhysicalOffset(), inline_containing_block_map, &containing_linebox_map);
+ return;
+ }
+
+ // If we have children which are anonymous block, we might contain split
+ // inlines, this can occur in the following example:
+ // <div>
+ // Some text <span style="position: relative;">text
+ // <div>block</div>
+ // text </span> text.
+ // </div>
+ for (const auto& child : children_) {
+ if (!child.fragment->IsAnonymousBlock())
+ continue;
+
+ const auto& child_fragment = To<NGPhysicalBoxFragment>(*child.fragment);
+ const auto* items = child_fragment.Items();
+ if (!items)
+ continue;
+
+ const PhysicalOffset child_offset = child.offset.ConvertToPhysical(
+ GetWritingMode(), Direction(), ToPhysicalSize(Size(), GetWritingMode()),
+ child_fragment.Size());
+ GatherInlineContainerFragmentsFromItems(items->Items(), child_offset,
+ inline_containing_block_map,
+ &containing_linebox_map);
+ }
+}
+
#if DCHECK_IS_ON()
void NGBoxFragmentBuilder::CheckNoBlockFragmentation() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
index 0544b7aa751..288530aeceb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h
@@ -9,7 +9,6 @@
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_fragment_geometry.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h"
@@ -38,6 +37,7 @@ class CORE_EXPORT NGBoxFragmentBuilder final
writing_mode,
direction),
box_type_(NGPhysicalFragment::NGBoxType::kNormalBox),
+ is_inline_formatting_context_(node.IsInline()),
did_break_(false) {}
// Build a fragment for LayoutObject without NGLayoutInputNode. LayoutInline
@@ -52,6 +52,7 @@ class CORE_EXPORT NGBoxFragmentBuilder final
writing_mode,
direction),
box_type_(NGPhysicalFragment::NGBoxType::kNormalBox),
+ is_inline_formatting_context_(true),
did_break_(false) {
layout_object_ = layout_object;
}
@@ -68,9 +69,8 @@ class CORE_EXPORT NGBoxFragmentBuilder final
return *initial_fragment_geometry_;
}
- void SetUnconstrainedIntrinsicBlockSize(
- LayoutUnit unconstrained_intrinsic_block_size) {
- unconstrained_intrinsic_block_size_ = unconstrained_intrinsic_block_size;
+ void SetOverflowBlockSize(LayoutUnit overflow_block_size) {
+ overflow_block_size_ = overflow_block_size;
}
void SetIntrinsicBlockSize(LayoutUnit intrinsic_block_size) {
intrinsic_block_size_ = intrinsic_block_size;
@@ -121,6 +121,10 @@ class CORE_EXPORT NGBoxFragmentBuilder final
// building now.
void SetConsumedBlockSize(LayoutUnit size) { consumed_block_size_ = size; }
+ void SetSequenceNumber(unsigned sequence_number) {
+ sequence_number_ = sequence_number;
+ }
+
// Specify that we broke.
//
// This will result in a fragment which has an unfinished break token.
@@ -197,6 +201,10 @@ class CORE_EXPORT NGBoxFragmentBuilder final
void SetColumnSpanner(NGBlockNode spanner) { column_spanner_ = spanner; }
bool FoundColumnSpanner() const { return !!column_spanner_; }
+ void SetLinesUntilClamp(const base::Optional<int>& value) {
+ lines_until_clamp_ = value;
+ }
+
void SetEarlyBreak(scoped_refptr<const NGEarlyBreak> breakpoint,
NGBreakAppeal appeal) {
early_break_ = breakpoint;
@@ -240,6 +248,12 @@ class CORE_EXPORT NGBoxFragmentBuilder final
void SetIsFieldsetContainer() { is_fieldset_container_ = true; }
void SetIsLegacyLayoutRoot() { is_legacy_layout_root_ = true; }
+ void SetIsInlineFormattingContext(bool is_inline_formatting_context) {
+ is_inline_formatting_context_ = is_inline_formatting_context;
+ }
+
+ void SetIsMathMLFraction() { is_math_fraction_ = true; }
+
bool DidBreak() const { return did_break_; }
void SetBorderEdges(NGBorderEdges border_edges) {
@@ -254,15 +268,16 @@ class CORE_EXPORT NGBoxFragmentBuilder final
custom_layout_data_ = std::move(custom_layout_data);
}
- // Layout algorithms should call this function for each baseline request in
- // the constraint space.
- //
- // If a request should use a synthesized baseline from the box rectangle,
- // algorithms can omit the call.
- //
- // This function should be called at most once for a given algorithm/baseline
- // type pair.
- void AddBaseline(NGBaselineRequest, LayoutUnit);
+ // Sets the alignment baseline for this fragment.
+ void SetBaseline(LayoutUnit baseline) { baseline_ = baseline; }
+ base::Optional<LayoutUnit> Baseline() const { return baseline_; }
+
+ // Sets the last baseline for this fragment.
+ void SetLastBaseline(LayoutUnit baseline) {
+ DCHECK_EQ(space_->BaselineAlgorithmType(),
+ NGBaselineAlgorithmType::kInlineBlock);
+ last_baseline_ = baseline;
+ }
// The |NGFragmentItemsBuilder| for the inline formatting context of this box.
NGFragmentItemsBuilder* ItemsBuilder() { return items_builder_; }
@@ -270,8 +285,12 @@ class CORE_EXPORT NGBoxFragmentBuilder final
items_builder_ = builder;
}
- // Inline containing block geometry is defined by two rectangles defined
- // by fragments generated by LayoutInline.
+ // Returns offset for given child. DCHECK if child not found.
+ // Warning: Do not call unless necessary.
+ LogicalOffset GetChildOffset(const LayoutObject* child) const;
+
+ // Inline containing block geometry is defined by two rectangles, generated
+ // by fragments of the LayoutInline.
struct InlineContainingBlockGeometry {
DISALLOW_NEW();
// Union of fragments generated on the first line.
@@ -283,7 +302,13 @@ class CORE_EXPORT NGBoxFragmentBuilder final
using InlineContainingBlockMap =
HashMap<const LayoutObject*,
base::Optional<InlineContainingBlockGeometry>>;
- void ComputeInlineContainerFragments(
+
+ // Computes the geometry required for any inline containing blocks.
+ // |inline_containing_block_map| is a map whose keys specify which inline
+ // containing block geometry is required.
+ void ComputeInlineContainerGeometryFromFragmentTree(
+ InlineContainingBlockMap* inline_containing_block_map);
+ void ComputeInlineContainerGeometry(
InlineContainingBlockMap* inline_containing_block_map);
#if DCHECK_IS_ON()
@@ -304,7 +329,7 @@ class CORE_EXPORT NGBoxFragmentBuilder final
scoped_refptr<const NGLayoutResult> ToBoxFragment(WritingMode);
const NGFragmentGeometry* initial_fragment_geometry_ = nullptr;
- LayoutUnit unconstrained_intrinsic_block_size_ = kIndefiniteSize;
+ LayoutUnit overflow_block_size_ = kIndefiniteSize;
LayoutUnit intrinsic_block_size_;
NGFragmentItemsBuilder* items_builder_ = nullptr;
@@ -314,12 +339,15 @@ class CORE_EXPORT NGBoxFragmentBuilder final
NGPhysicalFragment::NGBoxType box_type_;
bool is_fieldset_container_ = false;
bool is_initial_block_size_indefinite_ = false;
+ bool is_inline_formatting_context_;
bool did_break_;
bool has_forced_break_ = false;
bool is_new_fc_ = false;
bool subtree_modified_margin_strut_ = false;
bool has_seen_all_children_ = false;
+ bool is_math_fraction_ = false;
LayoutUnit consumed_block_size_;
+ unsigned sequence_number_ = 0;
LayoutUnit minimal_space_shortage_ = LayoutUnit::Max();
LayoutUnit tallest_unbreakable_block_size_ = LayoutUnit::Min();
@@ -331,11 +359,12 @@ class CORE_EXPORT NGBoxFragmentBuilder final
// The break-after value of the previous in-flow sibling.
EBreakBetween previous_break_after_ = EBreakBetween::kAuto;
- NGBaselineList baselines_;
-
+ base::Optional<LayoutUnit> baseline_;
+ base::Optional<LayoutUnit> last_baseline_;
NGBorderEdges border_edges_;
scoped_refptr<SerializedScriptValue> custom_layout_data_;
+ base::Optional<int> lines_until_clamp_;
friend class NGPhysicalBoxFragment;
friend class NGLayoutResult;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
index e61e4d42998..f1034c33a1c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc
@@ -8,7 +8,6 @@
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_fragment_geometry.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
@@ -138,10 +137,16 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::Layout() {
intrinsic_block_size_ = border_scrollbar_padding_.block_start;
- if (!LayoutChildren()) {
+ NGBreakStatus break_status = LayoutChildren();
+ if (break_status == NGBreakStatus::kNeedsEarlierBreak) {
// We need to discard this layout and do it again. We found an earlier break
// point that's more appealing than the one we ran out of space at.
return RelayoutAndBreakEarlier();
+ } else if (break_status == NGBreakStatus::kBrokeBefore) {
+ // If we want to break before, make sure that we're actually at the start.
+ DCHECK(!BreakToken());
+
+ return container_builder_.Abort(NGLayoutResult::kOutOfFragmentainerSpace);
}
// Figure out how much space we've already been able to process in previous
@@ -166,10 +171,9 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::Layout() {
if (is_constrained_by_outer_fragmentation_context_) {
// In addition to establishing one, we're nested inside another
// fragmentation context.
- FinishFragmentation(ConstraintSpace(), block_size, intrinsic_block_size_,
- previously_consumed_block_size,
- FragmentainerSpaceAtBfcStart(ConstraintSpace()),
- &container_builder_);
+ FinishFragmentation(
+ ConstraintSpace(), BreakToken(), block_size, intrinsic_block_size_,
+ FragmentainerSpaceAtBfcStart(ConstraintSpace()), &container_builder_);
} else {
container_builder_.SetBlockSize(block_size);
container_builder_.SetIntrinsicBlockSize(intrinsic_block_size_);
@@ -184,19 +188,17 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::Layout() {
return container_builder_.ToBoxFragment();
}
-base::Optional<MinMaxSize> NGColumnLayoutAlgorithm::ComputeMinMaxSize(
- const MinMaxSizeInput& input) const {
+base::Optional<MinMaxSizes> NGColumnLayoutAlgorithm::ComputeMinMaxSizes(
+ const MinMaxSizesInput& input) const {
// First calculate the min/max sizes of columns.
NGConstraintSpace space = CreateConstraintSpaceForMinMax();
NGFragmentGeometry fragment_geometry =
CalculateInitialMinMaxFragmentGeometry(space, Node());
NGBlockLayoutAlgorithm algorithm({Node(), fragment_geometry, space});
- MinMaxSizeInput child_input(input);
- child_input.size_type = NGMinMaxSizeType::kContentBoxSize;
- base::Optional<MinMaxSize> min_max_sizes =
- algorithm.ComputeMinMaxSize(child_input);
+ base::Optional<MinMaxSizes> min_max_sizes =
+ algorithm.ComputeMinMaxSizes(input);
DCHECK(min_max_sizes.has_value());
- MinMaxSize sizes = *min_max_sizes;
+ MinMaxSizes sizes = *min_max_sizes;
// If column-width is non-auto, pick the larger of that and intrinsic column
// width.
@@ -217,14 +219,11 @@ base::Optional<MinMaxSize> NGColumnLayoutAlgorithm::ComputeMinMaxSize(
// TODO(mstensho): Need to include spanners.
- if (input.size_type == NGMinMaxSizeType::kBorderBoxSize) {
- sizes += border_scrollbar_padding_.InlineSum();
- }
-
+ sizes += border_scrollbar_padding_.InlineSum();
return sizes;
}
-bool NGColumnLayoutAlgorithm::LayoutChildren() {
+NGBreakStatus NGColumnLayoutAlgorithm::LayoutChildren() {
NGMarginStrut margin_strut;
// First extract incoming child break tokens.
@@ -281,7 +280,7 @@ bool NGColumnLayoutAlgorithm::LayoutChildren() {
PushSpannerBreakTokens(std::move(spanner_break_token),
std::move(next_column_token),
&container_builder_);
- return true;
+ return NGBreakStatus::kContinue;
}
} else {
// Breaking before the first element in the fragmentainer isn't allowed,
@@ -291,7 +290,7 @@ bool NGColumnLayoutAlgorithm::LayoutChildren() {
}
if (BreakToken() && BreakToken()->HasSeenAllChildren() && !next_column_token)
- return true;
+ return NGBreakStatus::kContinue;
// Entering the child main loop. Here we'll alternate between laying out
// column content and column spanners, until we're either done, or until
@@ -301,6 +300,26 @@ bool NGColumnLayoutAlgorithm::LayoutChildren() {
do {
scoped_refptr<const NGLayoutResult> result =
LayoutRow(next_column_token.get(), &margin_strut);
+
+ if (!result) {
+ // Not enough outer fragmentainer space to produce any columns at all.
+ container_builder_.SetDidBreak();
+ if (intrinsic_block_size_) {
+ // We have preceding initial border/padding, or a column spanner
+ // (possibly preceded by other spanners or even column content). So we
+ // need to break inside the multicol container. Stop walking the
+ // children, but "continue" layout, so that we produce a fragment. Note
+ // that we normally don't want to break right after initial
+ // border/padding, but will do so as a last resort. It's up to our
+ // containing block to decide what's best.
+ FinishAfterBreakBeforeRow(std::move(next_column_token));
+ return NGBreakStatus::kContinue;
+ }
+ // Otherwise we have nothing here, and need to break before the multicol
+ // container. No fragment will be produced.
+ return NGBreakStatus::kBrokeBefore;
+ }
+
next_column_token =
To<NGBlockBreakToken>(result->PhysicalFragment().BreakToken());
@@ -320,7 +339,7 @@ bool NGColumnLayoutAlgorithm::LayoutChildren() {
container_builder_.AddBreakBeforeChild(
spanner_node, kBreakAppealPerfect, /* is_forced_break */ false);
FinishAfterBreakBeforeSpanner(std::move(next_column_token));
- return true;
+ return NGBreakStatus::kContinue;
}
}
@@ -328,18 +347,18 @@ bool NGColumnLayoutAlgorithm::LayoutChildren() {
NGBreakStatus break_status = LayoutSpanner(
spanner_node, nullptr, &margin_strut, &spanner_break_token);
if (break_status == NGBreakStatus::kNeedsEarlierBreak) {
- return false;
+ return break_status;
} else if (break_status == NGBreakStatus::kBrokeBefore) {
DCHECK(ConstraintSpace().HasBlockFragmentation());
FinishAfterBreakBeforeSpanner(std::move(next_column_token));
- return true;
+ return NGBreakStatus::kContinue;
} else if (spanner_break_token) {
DCHECK_EQ(break_status, NGBreakStatus::kContinue);
// We broke inside the spanner. This may happen if we're nested inside
// another fragmentation context.
PushSpannerBreakTokens(std::move(spanner_break_token),
std::move(next_column_token), &container_builder_);
- return true;
+ return NGBreakStatus::kContinue;
}
} while (next_column_token);
@@ -362,7 +381,7 @@ bool NGColumnLayoutAlgorithm::LayoutChildren() {
intrinsic_block_size_ += margin_strut.Sum();
}
- return true;
+ return NGBreakStatus::kContinue;
}
scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
@@ -401,13 +420,23 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
LayoutUnit column_block_offset = intrinsic_block_size_ + margin_strut->Sum();
bool needs_more_fragments_in_outer = false;
+ bool zero_outer_space_left = false;
if (is_constrained_by_outer_fragmentation_context_) {
LayoutUnit available_outer_space =
FragmentainerSpaceAtBfcStart(ConstraintSpace()) - column_block_offset;
- // TODO(mstensho): This should never be negative, or even zero. Turn into a
- // DCHECK when the underlying problem is fixed.
- available_outer_space = available_outer_space.ClampNegativeToZero();
+ if (available_outer_space <= LayoutUnit()) {
+ if (available_outer_space < LayoutUnit()) {
+ // We're past the end of the outer fragmentainer (typically due to a
+ // margin). Nothing will fit here, not even zero-size content.
+ return nullptr;
+ }
+
+ // We are out of space, but we're exactly at the end of the outer
+ // fragmentainer. If none of our contents take up space, we're going to
+ // fit, otherwise not. Lay out and find out.
+ zero_outer_space_left = true;
+ }
// Check if we can fit everything (that's remaining), block-wise, within the
// current outer fragmentainer. If we can't, we need to adjust the block
@@ -498,6 +527,11 @@ scoped_refptr<const NGLayoutResult> NGColumnLayoutAlgorithm::LayoutRow(
if (ConstraintSpace().HasBlockFragmentation() && column_break_token &&
actual_column_count >= used_column_count_ &&
needs_more_fragments_in_outer) {
+ // We cannot keep any of this if we have zero space left. Then we need
+ // to resume in the next outer fragmentainer.
+ if (zero_outer_space_left)
+ return nullptr;
+
container_builder_.SetDidBreak();
container_builder_.SetBreakAppeal(kBreakAppealPerfect);
break;
@@ -626,7 +660,8 @@ NGBreakStatus NGColumnLayoutAlgorithm::LayoutSpanner(
margin_strut->Append(margins.block_start, /* is_quirky */ false);
LayoutUnit block_offset = intrinsic_block_size_ + margin_strut->Sum();
- auto spanner_space = CreateConstraintSpaceForSpanner(block_offset);
+ auto spanner_space =
+ CreateConstraintSpaceForSpanner(spanner_node, block_offset);
const NGEarlyBreak* early_break_in_child = nullptr;
if (early_break_ && early_break_->Type() == NGEarlyBreak::kBlock &&
@@ -764,6 +799,10 @@ LayoutUnit NGColumnLayoutAlgorithm::CalculateBalancedColumnBlockSize(
NGBlockLayoutAlgorithm balancing_algorithm(
{Node(), fragment_geometry, space, break_token.get()});
scoped_refptr<const NGLayoutResult> result = balancing_algorithm.Layout();
+
+ // This algorithm should never abort.
+ DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
+
const NGPhysicalBoxFragment& fragment =
To<NGPhysicalBoxFragment>(result->PhysicalFragment());
LayoutUnit column_block_size = CalculateColumnContentBlockSize(
@@ -841,7 +880,7 @@ LayoutUnit NGColumnLayoutAlgorithm::ConstrainColumnBlockSize(
const ComputedStyle& style = Style();
LayoutUnit max = ResolveMaxBlockLength(
- ConstraintSpace(), style, border_padding_, style.LogicalMaxHeight(), size,
+ ConstraintSpace(), style, border_padding_, style.LogicalMaxHeight(),
LengthResolvePhase::kLayout);
LayoutUnit extent = ResolveMainBlockLength(
ConstraintSpace(), style, border_padding_, style.LogicalHeight(), size,
@@ -856,6 +895,20 @@ LayoutUnit NGColumnLayoutAlgorithm::ConstrainColumnBlockSize(
return size - extra;
}
+void NGColumnLayoutAlgorithm::FinishAfterBreakBeforeRow(
+ scoped_refptr<const NGBlockBreakToken> next_column_token) {
+ // We broke before a row for columns. We're done here. Take up the remaining
+ // space in the outer fragmentation context.
+ intrinsic_block_size_ = FragmentainerSpaceAtBfcStart(ConstraintSpace());
+
+ // If we were about to resume column layout after a spanner, add a break token
+ // for this, so that we resume there in the next outer fragmentainer. If
+ // there's no such break token, it means that we're at the start of the
+ // multicol container.
+ if (next_column_token)
+ container_builder_.AddBreakToken(std::move(next_column_token));
+}
+
void NGColumnLayoutAlgorithm::FinishAfterBreakBeforeSpanner(
scoped_refptr<const NGBlockBreakToken> next_column_token) {
// We broke before the spanner. We're done here. Take up the remaining space
@@ -898,9 +951,6 @@ NGConstraintSpace NGColumnLayoutAlgorithm::CreateConstraintSpaceForColumns(
space_builder.SetAvailableSize(column_size);
space_builder.SetPercentageResolutionSize(column_size);
- if (NGBaseline::ShouldPropagateBaselines(Node()))
- space_builder.AddBaselineRequests(ConstraintSpace().BaselineRequests());
-
// To ensure progression, we need something larger than 0 here. The spec
// actually says that fragmentainers have to accept at least 1px of content.
// See https://www.w3.org/TR/css-break-3/#breaking-rules
@@ -939,6 +989,7 @@ NGConstraintSpace NGColumnLayoutAlgorithm::CreateConstraintSpaceForBalancing(
}
NGConstraintSpace NGColumnLayoutAlgorithm::CreateConstraintSpaceForSpanner(
+ const NGBlockNode& spanner,
LayoutUnit block_offset) const {
NGConstraintSpaceBuilder space_builder(
ConstraintSpace(), Style().GetWritingMode(), /* is_new_fc */ true);
@@ -946,7 +997,7 @@ NGConstraintSpace NGColumnLayoutAlgorithm::CreateConstraintSpaceForSpanner(
space_builder.SetPercentageResolutionSize(content_box_size_);
if (ConstraintSpace().HasBlockFragmentation()) {
- SetupFragmentation(ConstraintSpace(), block_offset, &space_builder,
+ SetupFragmentation(ConstraintSpace(), spanner, block_offset, &space_builder,
/* is_new_fc */ true);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
index b9108019680..c516f1bafaa 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h
@@ -26,17 +26,21 @@ class CORE_EXPORT NGColumnLayoutAlgorithm
scoped_refptr<const NGLayoutResult> Layout() override;
- base::Optional<MinMaxSize> ComputeMinMaxSize(
- const MinMaxSizeInput&) const override;
+ base::Optional<MinMaxSizes> ComputeMinMaxSizes(
+ const MinMaxSizesInput&) const override;
private:
- // Lay out as many children as we can. If false is returned, it means that we
- // ran out of space at an unappealing location, and need to relayout and break
- // earlier (because we have a better breakpoint there).
- bool LayoutChildren();
+ // Lay out as many children as we can. If |kNeedsEarlierBreak| is returned, it
+ // means that we ran out of space at an unappealing location, and need to
+ // relayout and break earlier (because we have a better breakpoint there). If
+ // |kBrokeBefore| is returned, it means that we need to break before the
+ // multicol container, and retry in the next fragmentainer.
+ NGBreakStatus LayoutChildren();
// Lay out one row of columns. The layout result returned is for the last
- // column that was laid out. The rows themselves don't create fragments.
+ // column that was laid out. The rows themselves don't create fragments. If
+ // we're in a nested fragmentation context and completely out of outer
+ // fragmentainer space, nullptr will be returned.
scoped_refptr<const NGLayoutResult> LayoutRow(
const NGBlockBreakToken* next_column_token,
NGMarginStrut*);
@@ -66,6 +70,10 @@ class CORE_EXPORT NGColumnLayoutAlgorithm
return intrinsic_block_size_ - border_scrollbar_padding_.block_start;
}
+ // Finalize layout after breaking before column contents.
+ void FinishAfterBreakBeforeRow(
+ scoped_refptr<const NGBlockBreakToken> next_column_token);
+
// Finalize layout after breaking before a spanner.
void FinishAfterBreakBeforeSpanner(
scoped_refptr<const NGBlockBreakToken> next_column_token);
@@ -83,6 +91,7 @@ class CORE_EXPORT NGColumnLayoutAlgorithm
NGConstraintSpace CreateConstraintSpaceForBalancing(
const LogicalSize& column_size) const;
NGConstraintSpace CreateConstraintSpaceForSpanner(
+ const NGBlockNode& spanner,
LayoutUnit block_offset) const;
NGConstraintSpace CreateConstraintSpaceForMinMax() const;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
index 276c9823f0b..b2d3a0825ec 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc
@@ -787,7 +787,6 @@ TEST_F(NGColumnLayoutAlgorithmTest, FloatWithLastResortBreak) {
offset:110,0 size:100x100
offset:0,0 size:88x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -1434,14 +1433,10 @@ TEST_F(NGColumnLayoutAlgorithmTest, LinesInMulticolExtraSpace) {
offset:0,0 size:320x50
offset:0,0 size:100x50
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x50
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -1476,14 +1471,10 @@ TEST_F(NGColumnLayoutAlgorithmTest, LinesInMulticolExactFit) {
offset:0,0 size:320x40
offset:0,0 size:100x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -1521,15 +1512,11 @@ TEST_F(NGColumnLayoutAlgorithmTest, LinesInMulticolChildExtraSpace) {
offset:0,0 size:100x50
offset:0,0 size:77x50
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x50
offset:0,0 size:77x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -1567,15 +1554,11 @@ TEST_F(NGColumnLayoutAlgorithmTest, LinesInMulticolChildExactFit) {
offset:0,0 size:100x40
offset:0,0 size:77x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x40
offset:0,0 size:77x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -1615,13 +1598,10 @@ TEST_F(NGColumnLayoutAlgorithmTest, LinesInMulticolChildNoSpaceForFirst) {
offset:110,0 size:100x50
offset:0,0 size:77x50
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:220,0 size:100x50
offset:0,0 size:77x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -1662,13 +1642,10 @@ TEST_F(NGColumnLayoutAlgorithmTest,
offset:110,0 size:100x50
offset:0,0 size:77x50
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:220,0 size:100x50
offset:0,0 size:77x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -1713,7 +1690,6 @@ TEST_F(NGColumnLayoutAlgorithmTest, LineAtColumnBoundaryInFirstBlock) {
offset:110,0 size:100x50
offset:0,0 size:66x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -1752,20 +1728,15 @@ TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_LinesAndFloatsMulticol) {
offset:0,0 size:320x70
offset:0,0 size:100x70
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:10x50
offset:10,20 size:0x20
- offset:0,9 size:0x1
offset:10,40 size:11x30
offset:21,40 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x70
offset:0,0 size:10x70
offset:10,0 size:11x70
offset:21,0 size:0x20
- offset:0,9 size:0x1
offset:21,20 size:0x20
- offset:0,9 size:0x1
offset:220,0 size:100x70
offset:0,0 size:11x20
)DUMP";
@@ -1805,18 +1776,13 @@ TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatBelowLastLineInColumn) {
offset:0,0 size:320x70
offset:0,0 size:100x70
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:0,60 size:11x10
offset:110,0 size:100x70
offset:0,0 size:11x70
offset:11,0 size:0x20
- offset:0,9 size:0x1
offset:11,20 size:0x20
- offset:0,9 size:0x1
offset:220,0 size:100x70
offset:0,0 size:11x40
)DUMP";
@@ -1858,11 +1824,8 @@ TEST_F(NGColumnLayoutAlgorithmTest, Orphans) {
offset:110,0 size:100x90
offset:0,0 size:77x60
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -1899,18 +1862,12 @@ TEST_F(NGColumnLayoutAlgorithmTest, OrphansUnsatisfiable) {
offset:0,0 size:320x90
offset:0,0 size:100x90
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:0,60 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x90
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -1948,20 +1905,13 @@ TEST_F(NGColumnLayoutAlgorithmTest, Widows) {
offset:0,0 size:320x110
offset:0,0 size:100x110
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:0,60 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x110
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -2006,37 +1956,23 @@ TEST_F(NGColumnLayoutAlgorithmTest, WidowsUnsatisfiable) {
offset:0,0 size:320x90
offset:0,0 size:100x90
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x90
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:0,60 size:0x20
- offset:0,9 size:0x1
offset:220,0 size:100x90
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:0,60 size:0x20
- offset:0,9 size:0x1
offset:330,0 size:100x90
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:0,60 size:0x20
- offset:0,9 size:0x1
offset:440,0 size:100x90
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -2071,14 +2007,10 @@ TEST_F(NGColumnLayoutAlgorithmTest, OrphansAndUnsatisfiableWidows) {
offset:0,0 size:320x70
offset:0,0 size:100x70
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x70
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -2113,14 +2045,10 @@ TEST_F(NGColumnLayoutAlgorithmTest, UnsatisfiableOrphansAndWidows) {
offset:0,0 size:320x70
offset:0,0 size:100x70
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x70
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -2160,17 +2088,12 @@ TEST_F(NGColumnLayoutAlgorithmTest, WidowsAndAbspos) {
offset:0,0 size:100x70
offset:0,0 size:100x70
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x70
offset:0,0 size:100x60
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:33x33
)DUMP";
EXPECT_EQ(expectation, dump);
@@ -2214,15 +2137,11 @@ TEST_F(NGColumnLayoutAlgorithmTest, BreakBetweenLinesNotBefore) {
offset:0,0 size:44x60
offset:0,60 size:55x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x100
offset:0,0 size:55x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -2262,11 +2181,9 @@ TEST_F(NGColumnLayoutAlgorithmTest, BreakBetweenLinesNotBefore2) {
offset:0,0 size:44x80
offset:0,80 size:55x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x100
offset:0,0 size:55x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -2306,11 +2223,9 @@ TEST_F(NGColumnLayoutAlgorithmTest, BreakBetweenLinesNotBefore3) {
offset:0,0 size:44x80
offset:0,80 size:55x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x100
offset:0,0 size:55x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -2351,10 +2266,8 @@ TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatInBlockMovedByOrphans) {
offset:110,0 size:100x70
offset:0,0 size:77x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:10x10
offset:10,20 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -2392,17 +2305,12 @@ TEST_F(NGColumnLayoutAlgorithmTest, DISABLED_FloatMovedWithWidows) {
offset:0,0 size:320x90
offset:0,0 size:100x90
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x90
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:10x10
offset:10,40 size:0x20
- offset:0,9 size:0x1
offset:0,60 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -2809,32 +2717,32 @@ TEST_F(NGColumnLayoutAlgorithmTest, MinMax) {
NGFragmentGeometry fragment_geometry =
CalculateInitialFragmentGeometry(space, node);
NGColumnLayoutAlgorithm algorithm({node, fragment_geometry, space});
- base::Optional<MinMaxSize> size;
- MinMaxSizeInput zero_input(
+ base::Optional<MinMaxSizes> sizes;
+ MinMaxSizesInput zero_input(
/* percentage_resolution_block_size */ (LayoutUnit()));
// Both column-count and column-width set.
style->SetColumnCount(3);
style->SetColumnWidth(80);
- size = algorithm.ComputeMinMaxSize(zero_input);
- ASSERT_TRUE(size.has_value());
- EXPECT_EQ(LayoutUnit(260), size->min_size);
- EXPECT_EQ(LayoutUnit(320), size->max_size);
+ sizes = algorithm.ComputeMinMaxSizes(zero_input);
+ ASSERT_TRUE(sizes.has_value());
+ EXPECT_EQ(LayoutUnit(260), sizes->min_size);
+ EXPECT_EQ(LayoutUnit(320), sizes->max_size);
// Only column-count set.
style->SetHasAutoColumnWidth();
- size = algorithm.ComputeMinMaxSize(zero_input);
- ASSERT_TRUE(size.has_value());
- EXPECT_EQ(LayoutUnit(170), size->min_size);
- EXPECT_EQ(LayoutUnit(320), size->max_size);
+ sizes = algorithm.ComputeMinMaxSizes(zero_input);
+ ASSERT_TRUE(sizes.has_value());
+ EXPECT_EQ(LayoutUnit(170), sizes->min_size);
+ EXPECT_EQ(LayoutUnit(320), sizes->max_size);
// Only column-width set.
style->SetColumnWidth(80);
style->SetHasAutoColumnCount();
- size = algorithm.ComputeMinMaxSize(zero_input);
- ASSERT_TRUE(size.has_value());
- EXPECT_EQ(LayoutUnit(80), size->min_size);
- EXPECT_EQ(LayoutUnit(100), size->max_size);
+ sizes = algorithm.ComputeMinMaxSizes(zero_input);
+ ASSERT_TRUE(sizes.has_value());
+ EXPECT_EQ(LayoutUnit(80), sizes->min_size);
+ EXPECT_EQ(LayoutUnit(100), sizes->max_size);
}
TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancing) {
@@ -3196,7 +3104,6 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingSingleLine) {
offset:0,0 size:320x20
offset:0,0 size:100x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -3228,7 +3135,6 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingSingleLineInNested) {
offset:0,0 size:100x20
offset:0,0 size:45x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -3262,7 +3168,6 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingSingleLineInNestedSpanner) {
offset:0,0 size:100x20
offset:0,0 size:100x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -3327,17 +3232,12 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLines) {
offset:0,0 size:320x40
offset:0,0 size:100x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:220,0 size:100x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -3375,21 +3275,15 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLinesOrphans) {
offset:0,0 size:100x60
offset:0,0 size:100x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x60
offset:0,0 size:100x60
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:220,0 size:100x60
offset:0,0 size:100x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -3427,21 +3321,15 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLinesForcedBreak) {
offset:0,0 size:100x60
offset:0,0 size:100x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x60
offset:0,0 size:100x60
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:220,0 size:100x60
offset:0,0 size:100x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -3479,34 +3367,22 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLinesForcedBreak2) {
offset:0,0 size:100x100
offset:0,0 size:100x100
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:0,60 size:0x20
- offset:0,9 size:0x1
offset:0,80 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x100
offset:0,0 size:100x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:220,0 size:100x100
offset:0,0 size:99x0
offset:0,0 size:100x100
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:0,60 size:0x20
- offset:0,9 size:0x1
offset:0,80 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -3548,36 +3424,24 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLinesForcedBreak3) {
offset:0,0 size:66x100
offset:0,0 size:66x100
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:0,60 size:0x20
- offset:0,9 size:0x1
offset:0,80 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x100
offset:0,0 size:66x100
offset:0,0 size:66x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:220,0 size:100x100
offset:0,0 size:66x100
offset:0,0 size:99x0
offset:0,0 size:66x100
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:0,60 size:0x20
- offset:0,9 size:0x1
offset:0,80 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -3615,21 +3479,15 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLinesAvoidBreakInside) {
offset:0,0 size:100x60
offset:0,0 size:100x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x60
offset:0,0 size:100x60
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:220,0 size:100x60
offset:0,0 size:100x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -3667,19 +3525,14 @@ TEST_F(NGColumnLayoutAlgorithmTest, ColumnBalancingLinesAvoidBreakInside2) {
offset:0,0 size:100x60
offset:0,0 size:100x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x60
offset:0,0 size:100x60
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
offset:220,0 size:100x60
offset:0,0 size:100x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -3978,7 +3831,6 @@ TEST_F(NGColumnLayoutAlgorithmTest, ClassCBreakPointBeforeLine) {
offset:110,0 size:100x100
offset:0,0 size:55x20
offset:0,0 size:33x20
- offset:0,0 size:33x11
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -4313,6 +4165,168 @@ TEST_F(NGColumnLayoutAlgorithmTest, NestedUnbalancedInnerAutoHeight) {
EXPECT_EQ(expectation, dump);
}
+TEST_F(NGColumnLayoutAlgorithmTest, NestedAtOuterBoundary) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ .outer { columns:3; height:100px; width:320px; }
+ .inner { columns:2; height:50px; }
+ .outer, .inner { column-gap:10px; column-fill:auto; }
+ </style>
+ <div id="container">
+ <div class="outer">
+ <div style="width:11px; height:100px;"></div>
+ <div class="inner">
+ <div style="width:22px; height:70px;"></div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+
+ String dump = DumpFragmentTree(GetElementById("container"));
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x100
+ offset:0,0 size:320x100
+ offset:0,0 size:100x100
+ offset:0,0 size:11x100
+ offset:110,0 size:100x100
+ offset:0,0 size:100x50
+ offset:0,0 size:45x50
+ offset:0,0 size:22x50
+ offset:55,0 size:45x50
+ offset:0,0 size:22x20
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGColumnLayoutAlgorithmTest, NestedZeroHeightAtOuterBoundary) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ .outer { columns:3; height:100px; width:320px; }
+ .inner { columns:2; }
+ .outer, .inner { column-gap:10px; column-fill:auto; }
+ </style>
+ <div id="container">
+ <div class="outer">
+ <div style="width:11px; height:100px;"></div>
+ <div class="inner">
+ <div style="width:22px;"></div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+
+ String dump = DumpFragmentTree(GetElementById("container"));
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x100
+ offset:0,0 size:320x100
+ offset:0,0 size:100x100
+ offset:0,0 size:11x100
+ offset:0,100 size:100x0
+ offset:0,0 size:45x1
+ offset:0,0 size:22x0
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGColumnLayoutAlgorithmTest, NestedWithMarginAtOuterBoundary) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ .outer { columns:3; height:100px; width:320px; }
+ .inner { columns:2; height:50px; margin-top:20px; }
+ .outer, .inner { column-gap:10px; column-fill:auto; }
+ </style>
+ <div id="container">
+ <div class="outer">
+ <div style="width:11px; height:90px;"></div>
+ <div class="inner">
+ <div style="width:22px; height:70px;"></div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+
+ String dump = DumpFragmentTree(GetElementById("container"));
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x100
+ offset:0,0 size:320x100
+ offset:0,0 size:100x100
+ offset:0,0 size:11x90
+ offset:110,0 size:100x100
+ offset:0,0 size:100x50
+ offset:0,0 size:45x50
+ offset:0,0 size:22x50
+ offset:55,0 size:45x50
+ offset:0,0 size:22x20
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGColumnLayoutAlgorithmTest, NestedWithTallBorder) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ .outer { columns:3; height:100px; width:320px; }
+ .inner { columns:2; height:50px; border-top:100px solid; }
+ .outer, .inner { column-gap:10px; column-fill:auto; }
+ </style>
+ <div id="container">
+ <div class="outer">
+ <div class="inner">
+ <div style="width:22px; height:70px;"></div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+
+ String dump = DumpFragmentTree(GetElementById("container"));
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x100
+ offset:0,0 size:320x100
+ offset:0,0 size:100x100
+ offset:0,0 size:100x100
+ offset:110,0 size:100x100
+ offset:0,0 size:100x50
+ offset:0,0 size:45x50
+ offset:0,0 size:22x50
+ offset:55,0 size:45x50
+ offset:0,0 size:22x20
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGColumnLayoutAlgorithmTest, NestedWithTallSpanner) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ .outer { columns:3; height:100px; width:320px; column-fill:auto; }
+ .inner { columns:2; }
+ .outer, .inner { column-gap:10px; }
+ </style>
+ <div id="container">
+ <div class="outer">
+ <div class="inner">
+ <div style="column-span:all; width:22px; height:100px;"></div>
+ <div style="width:22px; height:70px;"></div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+
+ String dump = DumpFragmentTree(GetElementById("container"));
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x100
+ offset:0,0 size:320x100
+ offset:0,0 size:100x100
+ offset:0,0 size:100x100
+ offset:0,0 size:22x100
+ offset:110,0 size:100x100
+ offset:0,0 size:100x35
+ offset:0,0 size:45x35
+ offset:0,0 size:22x35
+ offset:55,0 size:45x35
+ offset:0,0 size:22x35
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
TEST_F(NGColumnLayoutAlgorithmTest, AbsposFitsInOneColumn) {
SetBodyInnerHTML(R"HTML(
<div id="container">
@@ -5523,14 +5537,11 @@ TEST_F(NGColumnLayoutAlgorithmTest, AvoidSoftBreakBetweenSpanners3) {
offset:0,0 size:100x100
offset:0,0 size:11x100
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x100
offset:0,0 size:100x80
offset:0,0 size:11x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:55x60
)DUMP";
EXPECT_EQ(expectation, dump);
@@ -6084,15 +6095,11 @@ TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenHonorOrphansWidows) {
offset:0,0 size:100x100
offset:0,0 size:100x100
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x100
offset:0,0 size:100x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:100x30
)DUMP";
EXPECT_EQ(expectation, dump);
@@ -6135,9 +6142,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenHonorOrphansWidows2) {
offset:110,0 size:100x100
offset:0,0 size:100x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:100x30
)DUMP";
EXPECT_EQ(expectation, dump);
@@ -6186,22 +6191,15 @@ TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenHonorOrphansWidows3) {
offset:0,0 size:100x100
offset:0,0 size:100x100
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x100
offset:0,0 size:100x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:100x60
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:0x20
- offset:0,9 size:0x1
)DUMP";
EXPECT_EQ(expectation, dump);
}
@@ -6243,11 +6241,9 @@ TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenIgnoreOrphansWidows) {
offset:0,0 size:100x40
offset:0,40 size:100x60
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:110,0 size:100x100
offset:0,0 size:100x20
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:100x30
)DUMP";
EXPECT_EQ(expectation, dump);
@@ -6296,9 +6292,7 @@ TEST_F(NGColumnLayoutAlgorithmTest, AvoidBreakBetweenLinesInsideBreakAvoid) {
offset:110,0 size:100x100
offset:0,0 size:35x40
offset:0,0 size:0x20
- offset:0,9 size:0x1
offset:0,20 size:0x20
- offset:0,9 size:0x1
offset:0,40 size:36x30
)DUMP";
EXPECT_EQ(expectation, dump);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
index c219e2f14f3..e916c433314 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
@@ -35,8 +35,7 @@ static_assert(sizeof(NGConstraintSpace) == sizeof(SameSizeAsNGConstraintSpace),
} // namespace
NGConstraintSpace NGConstraintSpace::CreateFromLayoutObject(
- const LayoutBlock& block,
- bool is_layout_root) {
+ const LayoutBlock& block) {
// We should only ever create a constraint space from legacy layout if the
// object is a new formatting context.
DCHECK(block.CreatesNewFormattingContext());
@@ -77,28 +76,14 @@ NGConstraintSpace NGConstraintSpace::CreateFromLayoutObject(
/* is_new_fc */ true,
!parallel_containing_block);
- auto* previous_result = block.GetCachedLayoutResult();
- if (is_layout_root && previous_result) {
- // Due to layout-roots (starting layout at an arbirary node, instead of the
- // |LayoutView|), we can end up with a situation where we'll miss our cache
- // due to baseline-requests not matching.
- //
- // For the case where we start at a layout-root, the baselines don't
- // particularly matter, so we just request exactly the same as the previous
- // layout.
- builder.AddBaselineRequests(
- previous_result->GetConstraintSpaceForCaching().BaselineRequests());
- } else if (!block.IsWritingModeRoot() || block.IsGridItem()) {
- // Add all types because we don't know which baselines will be requested.
- FontBaseline baseline_type = style.GetFontBaseline();
- bool synthesize_inline_block_baseline =
- block.UseLogicalBottomMarginEdgeForInlineBlockBaseline();
- if (!synthesize_inline_block_baseline) {
- builder.AddBaselineRequest(
- {NGBaselineAlgorithmType::kAtomicInline, baseline_type});
- }
- builder.AddBaselineRequest(
- {NGBaselineAlgorithmType::kFirstLine, baseline_type});
+ if (!block.IsWritingModeRoot() || block.IsGridItem()) {
+ // We don't know if the parent layout will require our baseline, so always
+ // request it.
+ builder.SetNeedsBaseline(true);
+ builder.SetBaselineAlgorithmType(block.IsInline() &&
+ block.IsAtomicInlineLevel()
+ ? NGBaselineAlgorithmType::kInlineBlock
+ : NGBaselineAlgorithmType::kFirstLine);
}
if (block.IsTableCell()) {
@@ -123,6 +108,10 @@ NGConstraintSpace NGConstraintSpace::CreateFromLayoutObject(
table_style.BorderCollapse() == EBorderCollapse::kSeparate);
}
+ if (block.IsAtomicInlineLevel() || block.IsFlexItem() || block.IsGridItem() ||
+ block.IsFloating())
+ builder.SetIsPaintedAtomically(true);
+
builder.SetAvailableSize(available_size);
builder.SetPercentageResolutionSize(percentage_size);
builder.SetIsFixedInlineSize(fixed_inline);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
index 91ec55842b2..e409701f6ce 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h
@@ -13,7 +13,6 @@
#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h"
#include "third_party/blink/renderer/core/layout/ng/ng_break_appeal.h"
#include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
@@ -68,6 +67,28 @@ enum NGPercentageStorage {
kRareDataPercentage
};
+// Some layout algorithms (flow, tables) calculate their alignment baseline
+// differently if they are within an atomic-inline context.
+//
+// Other more modern layout algorithms (flex, grid) however ignore this flag
+// and always calculate the alignment baseline in the same way (returning the
+// "first-line").
+enum class NGBaselineAlgorithmType {
+ // Compute the baseline of the first line box.
+ kFirstLine,
+ // Compute the baseline(s) for when we are within an inline-block context. If
+ // the child is block-flow it will produce both the first, and last baselines.
+ kInlineBlock
+};
+
+// Some layout algorithms have multiple layout passes. Between passes they
+// typically have different results which we need to cache separately for
+// performance reasons.
+//
+// This enum gives the caching logic a hint into which cache "slot" it should
+// store a result in.
+enum class NGCacheSlot { kLayout, kMeasure };
+
// The NGConstraintSpace represents a set of constraints and available space
// which a layout algorithm may produce a NGFragment within.
class CORE_EXPORT NGConstraintSpace final {
@@ -134,8 +155,7 @@ class CORE_EXPORT NGConstraintSpace final {
// Creates NGConstraintSpace representing LayoutObject's containing block.
// This should live on NGBlockNode or another layout bridge and probably take
// a root NGConstraintSpace.
- static NGConstraintSpace CreateFromLayoutObject(const LayoutBlock&,
- bool is_layout_root);
+ static NGConstraintSpace CreateFromLayoutObject(const LayoutBlock&);
const NGExclusionSpace& ExclusionSpace() const { return exclusion_space_; }
@@ -239,6 +259,36 @@ class CORE_EXPORT NGConstraintSpace final {
return LayoutUnit();
}
+ // Inline/block target stretch size constraints.
+ // See:
+ // https://mathml-refresh.github.io/mathml-core/#dfn-inline-stretch-size-constraint
+ LayoutUnit TargetStretchInlineSize() const {
+ return HasRareData() ? rare_data_->TargetStretchInlineSize()
+ : kIndefiniteSize;
+ }
+
+ bool HasTargetStretchInlineSize() const {
+ return TargetStretchInlineSize() != kIndefiniteSize;
+ }
+
+ LayoutUnit TargetStretchAscentSize() const {
+ return HasRareData() ? rare_data_->TargetStretchAscentSize()
+ : kIndefiniteSize;
+ }
+
+ bool HasTargetStretchAscentSize() const {
+ return TargetStretchAscentSize() != kIndefiniteSize;
+ }
+
+ LayoutUnit TargetStretchDescentSize() const {
+ return HasRareData() ? rare_data_->TargetStretchDescentSize()
+ : kIndefiniteSize;
+ }
+
+ bool HasTargetStretchDescentSize() const {
+ return TargetStretchDescentSize() != kIndefiniteSize;
+ }
+
// Return the borders which should be used for a table-cell.
NGBoxStrut TableCellBorders() const {
return HasRareData() ? rare_data_->TableCellBorders() : NGBoxStrut();
@@ -322,6 +372,24 @@ class CORE_EXPORT NGConstraintSpace final {
return bitfields_.ancestor_has_clearance_past_adjoining_floats;
}
+ // Returns if the parent layout needs the baseline from this layout.
+ //
+ // This bit is only used for skipping querying baseline information from
+ // legacy layout.
+ bool NeedsBaseline() const { return bitfields_.needs_baseline; }
+
+ // How the baseline for the fragment should be calculated, see documentation
+ // for |NGBaselineAlgorithmType|.
+ NGBaselineAlgorithmType BaselineAlgorithmType() const {
+ return static_cast<NGBaselineAlgorithmType>(
+ bitfields_.baseline_algorithm_type);
+ }
+
+ // Which cache slot the output layout result should be stored in.
+ NGCacheSlot CacheSlot() const {
+ return static_cast<NGCacheSlot>(bitfields_.cache_slot);
+ }
+
// Some layout modes “stretch” their children to a fixed size (e.g. flex,
// grid). These flags represented whether a layout needs to produce a
// fragment that satisfies a fixed constraint in the inline and block
@@ -342,6 +410,8 @@ class CORE_EXPORT NGConstraintSpace final {
// (ie. fit-content). This is used for inline-block, floats, etc.
bool IsShrinkToFit() const { return bitfields_.is_shrink_to_fit; }
+ bool IsPaintedAtomically() const { return bitfields_.is_painted_atomically; }
+
// If specified a layout should produce a Fragment which fragments at the
// blockSize if possible.
NGFragmentationType BlockFragmentationType() const {
@@ -387,7 +457,7 @@ class CORE_EXPORT NGConstraintSpace final {
// Return true if the block size of the table-cell should be considered
// restricted (e.g. height of the cell or its table is non-auto).
bool IsRestrictedBlockSizeTableCell() const {
- return bitfields_.is_restricted_block_size_table_cell;
+ return HasRareData() && rare_data_->is_restricted_block_size_table_cell;
}
NGMarginStrut MarginStrut() const {
@@ -488,8 +558,12 @@ class CORE_EXPORT NGConstraintSpace final {
return HasRareData() ? rare_data_->ClearanceOffset() : LayoutUnit::Min();
}
- const NGBaselineRequestList BaselineRequests() const {
- return NGBaselineRequestList(bitfields_.baseline_requests);
+ bool ForceTruncateAtLineClamp() const {
+ return HasRareData() ? rare_data_->ForceTruncateAtLineClamp() : true;
+ }
+
+ base::Optional<int> LinesUntilClamp() const {
+ return HasRareData() ? rare_data_->LinesUntilClamp() : base::nullopt;
}
// Return true if the two constraint spaces are similar enough that it *may*
@@ -567,9 +641,6 @@ class CORE_EXPORT NGConstraintSpace final {
private:
friend class NGConstraintSpaceBuilder;
- explicit NGConstraintSpace(WritingMode writing_mode)
- : bfc_offset_(), bitfields_(writing_mode) {}
-
// This struct defines all of the inputs to layout which we consider rare.
// Primarily this is:
// - Percentage resolution sizes which differ from the available size or
@@ -577,6 +648,7 @@ class CORE_EXPORT NGConstraintSpace final {
// - The margin strut.
// - Anything to do with floats (the exclusion space, clearance offset, etc).
// - Anything to do with fragmentation.
+ // - Anything to do with stretching of math operators.
//
// This information is kept in a separate in this heap-allocated struct to
// reduce memory usage. Over time this may have to change based on usage data.
@@ -584,9 +656,20 @@ class CORE_EXPORT NGConstraintSpace final {
USING_FAST_MALLOC(RareData);
public:
+ // |RareData| unions different types of data which are mutually exclusive.
+ // They fall into the following categories:
+ enum DataUnionType {
+ kNone,
+ kBlockData, // An inflow block which doesn't establish a new FC.
+ kTableCellData, // A table-cell (display: table-cell).
+ kCustomData, // A custom layout (display: layout(foo)).
+ kStretchData // The target inline/block stretch sizes for MathML.
+ };
+
explicit RareData(const NGBfcOffset bfc_offset)
: bfc_offset(bfc_offset),
data_union_type(static_cast<unsigned>(kNone)),
+ is_restricted_block_size_table_cell(false),
hide_table_cell_if_empty(false),
block_direction_fragmentation_type(
static_cast<unsigned>(kFragmentNone)),
@@ -601,6 +684,8 @@ class CORE_EXPORT NGConstraintSpace final {
fragmentainer_block_size(other.fragmentainer_block_size),
fragmentainer_offset_at_bfc(other.fragmentainer_offset_at_bfc),
data_union_type(other.data_union_type),
+ is_restricted_block_size_table_cell(
+ other.is_restricted_block_size_table_cell),
hide_table_cell_if_empty(other.hide_table_cell_if_empty),
block_direction_fragmentation_type(
other.block_direction_fragmentation_type),
@@ -619,6 +704,9 @@ class CORE_EXPORT NGConstraintSpace final {
case kCustomData:
new (&custom_data_) CustomData(other.custom_data_);
break;
+ case kStretchData:
+ new (&stretch_data_) StretchData(other.stretch_data_);
+ break;
default:
NOTREACHED();
}
@@ -636,38 +724,20 @@ class CORE_EXPORT NGConstraintSpace final {
case kCustomData:
custom_data_.~CustomData();
break;
+ case kStretchData:
+ stretch_data_.~StretchData();
+ break;
default:
NOTREACHED();
}
}
- // |RareData| unions different types of data which are mutually exclusive.
- // They fall into the following categories:
- enum DataUnionType {
- kNone,
- kBlockData, // An inflow block which doesn't establish a new FC.
- kTableCellData, // A table-cell (display: table-cell).
- kCustomData // A custom layout (display: layout(foo)).
- };
-
- LogicalSize percentage_resolution_size;
- LayoutUnit replaced_percentage_resolution_block_size;
- NGBfcOffset bfc_offset;
-
- LayoutUnit fragmentainer_block_size = kIndefiniteSize;
- LayoutUnit fragmentainer_offset_at_bfc;
-
- unsigned data_union_type : 2;
- unsigned hide_table_cell_if_empty : 1;
- unsigned block_direction_fragmentation_type : 2;
- unsigned is_inside_balanced_columns : 1;
- unsigned is_in_column_bfc : 1;
- unsigned early_break_appeal : 2; // NGBreakAppeal
-
bool MaySkipLayout(const RareData& other) const {
if (fragmentainer_block_size != other.fragmentainer_block_size ||
fragmentainer_offset_at_bfc != other.fragmentainer_offset_at_bfc ||
data_union_type != other.data_union_type ||
+ is_restricted_block_size_table_cell !=
+ other.is_restricted_block_size_table_cell ||
hide_table_cell_if_empty != other.hide_table_cell_if_empty ||
block_direction_fragmentation_type !=
other.block_direction_fragmentation_type ||
@@ -680,19 +750,23 @@ class CORE_EXPORT NGConstraintSpace final {
return true;
if (data_union_type == kBlockData)
- return true;
+ return block_data_.MaySkipLayout(other.block_data_);
if (data_union_type == kTableCellData)
return table_cell_data_.MaySkipLayout(other.table_cell_data_);
- DCHECK_EQ(data_union_type, kCustomData);
- return custom_data_.MaySkipLayout(other.custom_data_);
+ if (data_union_type == kCustomData)
+ return custom_data_.MaySkipLayout(other.custom_data_);
+
+ DCHECK_EQ(data_union_type, kStretchData);
+ return stretch_data_.MaySkipLayout(other.stretch_data_);
}
// Must be kept in sync with members checked within |MaySkipLayout|.
bool IsInitialForMaySkipLayout() const {
if (fragmentainer_block_size != kIndefiniteSize ||
- fragmentainer_offset_at_bfc || hide_table_cell_if_empty ||
+ fragmentainer_offset_at_bfc || is_restricted_block_size_table_cell ||
+ hide_table_cell_if_empty ||
block_direction_fragmentation_type != kFragmentNone ||
is_inside_balanced_columns || is_in_column_bfc ||
early_break_appeal != kBreakAppealLastResort)
@@ -702,13 +776,16 @@ class CORE_EXPORT NGConstraintSpace final {
return true;
if (data_union_type == kBlockData)
- return true;
+ return block_data_.IsInitialForMaySkipLayout();
if (data_union_type == kTableCellData)
return table_cell_data_.IsInitialForMaySkipLayout();
- DCHECK_EQ(data_union_type, kCustomData);
- return custom_data_.IsInitialForMaySkipLayout();
+ if (data_union_type == kCustomData)
+ return custom_data_.IsInitialForMaySkipLayout();
+
+ DCHECK_EQ(data_union_type, kStretchData);
+ return stretch_data_.IsInitialForMaySkipLayout();
}
NGMarginStrut MarginStrut() const {
@@ -749,6 +826,25 @@ class CORE_EXPORT NGConstraintSpace final {
EnsureBlockData()->clearance_offset = clearance_offset;
}
+ base::Optional<int> LinesUntilClamp() const {
+ return data_union_type == kBlockData ? block_data_.lines_until_clamp
+ : base::nullopt;
+ }
+
+ void SetLinesUntilClamp(int value) {
+ EnsureBlockData()->lines_until_clamp = value;
+ }
+
+ int ForceTruncateAtLineClamp() const {
+ return data_union_type == kBlockData
+ ? block_data_.force_truncate_at_line_clamp
+ : true;
+ }
+
+ void SetForceTruncateAtLineClamp(bool value) {
+ EnsureBlockData()->force_truncate_at_line_clamp = value;
+ }
+
NGBoxStrut TableCellBorders() const {
return data_union_type == kTableCellData
? table_cell_data_.table_cell_borders
@@ -786,28 +882,78 @@ class CORE_EXPORT NGConstraintSpace final {
EnsureCustomData()->data = std::move(custom_layout_data);
}
+ LayoutUnit TargetStretchInlineSize() const {
+ return data_union_type == kStretchData
+ ? stretch_data_.target_stretch_inline_size
+ : kIndefiniteSize;
+ }
+
+ void SetTargetStretchInlineSize(LayoutUnit target_stretch_inline_size) {
+ EnsureStretchData()->target_stretch_inline_size =
+ target_stretch_inline_size;
+ }
+
+ LayoutUnit TargetStretchAscentSize() const {
+ return data_union_type == kStretchData
+ ? stretch_data_.target_stretch_ascent_size
+ : kIndefiniteSize;
+ }
+
+ void SetTargetStretchAscentSize(LayoutUnit target_stretch_ascent_size) {
+ EnsureStretchData()->target_stretch_ascent_size =
+ target_stretch_ascent_size;
+ }
+
+ LayoutUnit TargetStretchDescentSize() const {
+ return data_union_type == kStretchData
+ ? stretch_data_.target_stretch_descent_size
+ : kIndefiniteSize;
+ }
+
+ void SetTargetStretchDescentSize(LayoutUnit target_stretch_descent_size) {
+ EnsureStretchData()->target_stretch_descent_size =
+ target_stretch_descent_size;
+ }
+
+ LogicalSize percentage_resolution_size;
+ LayoutUnit replaced_percentage_resolution_block_size;
+ NGBfcOffset bfc_offset;
+
+ LayoutUnit fragmentainer_block_size = kIndefiniteSize;
+ LayoutUnit fragmentainer_offset_at_bfc;
+
+ unsigned data_union_type : 3;
+
+ unsigned is_restricted_block_size_table_cell : 1;
+ unsigned hide_table_cell_if_empty : 1;
+
+ unsigned block_direction_fragmentation_type : 2;
+ unsigned is_inside_balanced_columns : 1;
+ unsigned is_in_column_bfc : 1;
+ unsigned early_break_appeal : 2; // NGBreakAppeal
private:
struct BlockData {
+ bool MaySkipLayout(const BlockData& other) const {
+ return lines_until_clamp == other.lines_until_clamp &&
+ force_truncate_at_line_clamp ==
+ other.force_truncate_at_line_clamp;
+ }
+
+ bool IsInitialForMaySkipLayout() const {
+ return !lines_until_clamp.has_value() && force_truncate_at_line_clamp;
+ }
+
NGMarginStrut margin_strut;
base::Optional<LayoutUnit> optimistic_bfc_block_offset;
base::Optional<LayoutUnit> forced_bfc_block_offset;
LayoutUnit clearance_offset = LayoutUnit::Min();
+ base::Optional<int> lines_until_clamp;
+ // If true and |lines_until_clamp| == 1, then the line should be truncated
+ // regardless of whether there is more text that follows on the line.
+ bool force_truncate_at_line_clamp = true;
};
- BlockData* EnsureBlockData() {
- DCHECK(data_union_type == kNone || data_union_type == kBlockData);
- if (data_union_type != kBlockData) {
- data_union_type = kBlockData;
- new (&block_data_) BlockData();
- }
- return &block_data_;
- }
-
struct TableCellData {
- NGBoxStrut table_cell_borders;
- LayoutUnit table_cell_intrinsic_padding_block_start;
- LayoutUnit table_cell_intrinsic_padding_block_end;
-
bool MaySkipLayout(const TableCellData& other) const {
return table_cell_borders == other.table_cell_borders &&
table_cell_intrinsic_padding_block_start ==
@@ -821,16 +967,11 @@ class CORE_EXPORT NGConstraintSpace final {
table_cell_intrinsic_padding_block_start == LayoutUnit() &&
table_cell_intrinsic_padding_block_end == LayoutUnit();
}
- };
- TableCellData* EnsureTableCellData() {
- DCHECK(data_union_type == kNone || data_union_type == kTableCellData);
- if (data_union_type != kTableCellData) {
- data_union_type = kTableCellData;
- new (&table_cell_data_) TableCellData();
- }
- return &table_cell_data_;
- }
+ NGBoxStrut table_cell_borders;
+ LayoutUnit table_cell_intrinsic_padding_block_start;
+ LayoutUnit table_cell_intrinsic_padding_block_end;
+ };
struct CustomData {
scoped_refptr<SerializedScriptValue> data;
@@ -842,6 +983,42 @@ class CORE_EXPORT NGConstraintSpace final {
bool IsInitialForMaySkipLayout() const { return !data; }
};
+ struct StretchData {
+ bool MaySkipLayout(const StretchData& other) const {
+ return target_stretch_inline_size == other.target_stretch_inline_size &&
+ target_stretch_ascent_size == other.target_stretch_ascent_size &&
+ target_stretch_descent_size == other.target_stretch_descent_size;
+ }
+
+ bool IsInitialForMaySkipLayout() const {
+ return target_stretch_inline_size == kIndefiniteSize &&
+ target_stretch_ascent_size == kIndefiniteSize &&
+ target_stretch_descent_size == kIndefiniteSize;
+ }
+
+ LayoutUnit target_stretch_inline_size = kIndefiniteSize;
+ LayoutUnit target_stretch_ascent_size = kIndefiniteSize;
+ LayoutUnit target_stretch_descent_size = kIndefiniteSize;
+ };
+
+ BlockData* EnsureBlockData() {
+ DCHECK(data_union_type == kNone || data_union_type == kBlockData);
+ if (data_union_type != kBlockData) {
+ data_union_type = kBlockData;
+ new (&block_data_) BlockData();
+ }
+ return &block_data_;
+ }
+
+ TableCellData* EnsureTableCellData() {
+ DCHECK(data_union_type == kNone || data_union_type == kTableCellData);
+ if (data_union_type != kTableCellData) {
+ data_union_type = kTableCellData;
+ new (&table_cell_data_) TableCellData();
+ }
+ return &table_cell_data_;
+ }
+
CustomData* EnsureCustomData() {
DCHECK(data_union_type == kNone || data_union_type == kCustomData);
if (data_union_type != kCustomData) {
@@ -851,10 +1028,20 @@ class CORE_EXPORT NGConstraintSpace final {
return &custom_data_;
}
+ StretchData* EnsureStretchData() {
+ DCHECK(data_union_type == kNone || data_union_type == kStretchData);
+ if (data_union_type != kStretchData) {
+ data_union_type = kStretchData;
+ new (&stretch_data_) StretchData();
+ }
+ return &stretch_data_;
+ }
+
union {
BlockData block_data_;
TableCellData table_cell_data_;
CustomData custom_data_;
+ StretchData stretch_data_;
};
};
@@ -876,13 +1063,17 @@ class CORE_EXPORT NGConstraintSpace final {
is_anonymous(false),
is_new_formatting_context(false),
is_orthogonal_writing_mode_root(false),
- is_fixed_block_size_indefinite(false),
- is_restricted_block_size_table_cell(false),
+ is_painted_atomically(false),
use_first_line_style(false),
ancestor_has_clearance_past_adjoining_floats(false),
+ needs_baseline(false),
+ baseline_algorithm_type(
+ static_cast<unsigned>(NGBaselineAlgorithmType::kFirstLine)),
+ cache_slot(static_cast<unsigned>(NGCacheSlot::kLayout)),
is_shrink_to_fit(false),
is_fixed_inline_size(false),
is_fixed_block_size(false),
+ is_fixed_block_size_indefinite(false),
table_cell_child_layout_mode(static_cast<unsigned>(
NGTableCellChildLayoutMode::kNotTableCellChild)),
percentage_inline_storage(kSameAsAvailable),
@@ -898,20 +1089,20 @@ class CORE_EXPORT NGConstraintSpace final {
is_new_formatting_context == other.is_new_formatting_context &&
is_orthogonal_writing_mode_root ==
other.is_orthogonal_writing_mode_root &&
- is_fixed_block_size_indefinite ==
- other.is_fixed_block_size_indefinite &&
- is_restricted_block_size_table_cell ==
- other.is_restricted_block_size_table_cell &&
+ is_painted_atomically == other.is_painted_atomically &&
use_first_line_style == other.use_first_line_style &&
ancestor_has_clearance_past_adjoining_floats ==
other.ancestor_has_clearance_past_adjoining_floats &&
- baseline_requests == other.baseline_requests;
+ needs_baseline == other.needs_baseline &&
+ baseline_algorithm_type == other.baseline_algorithm_type;
}
bool AreSizeConstraintsEqual(const Bitfields& other) const {
return is_shrink_to_fit == other.is_shrink_to_fit &&
is_fixed_inline_size == other.is_fixed_inline_size &&
is_fixed_block_size == other.is_fixed_block_size &&
+ is_fixed_block_size_indefinite ==
+ other.is_fixed_block_size_indefinite &&
table_cell_child_layout_mode == other.table_cell_child_layout_mode;
}
@@ -925,17 +1116,20 @@ class CORE_EXPORT NGConstraintSpace final {
unsigned is_new_formatting_context : 1;
unsigned is_orthogonal_writing_mode_root : 1;
- unsigned is_fixed_block_size_indefinite : 1;
- unsigned is_restricted_block_size_table_cell : 1;
+ unsigned is_painted_atomically : 1;
unsigned use_first_line_style : 1;
unsigned ancestor_has_clearance_past_adjoining_floats : 1;
- unsigned baseline_requests : NGBaselineRequestList::kSerializedBits;
+ unsigned needs_baseline : 1;
+ unsigned baseline_algorithm_type : 1;
+
+ unsigned cache_slot : 1;
// Size constraints.
unsigned is_shrink_to_fit : 1;
unsigned is_fixed_inline_size : 1;
unsigned is_fixed_block_size : 1;
+ unsigned is_fixed_block_size_indefinite : 1;
unsigned table_cell_child_layout_mode : 2; // NGTableCellChildLayoutMode
unsigned percentage_inline_storage : 2; // NGPercentageStorage
@@ -943,6 +1137,9 @@ class CORE_EXPORT NGConstraintSpace final {
unsigned replaced_percentage_block_storage : 2; // NGPercentageStorage
};
+ explicit NGConstraintSpace(WritingMode writing_mode)
+ : bfc_offset_(), bitfields_(writing_mode) {}
+
inline bool HasRareData() const { return bitfields_.has_rare_data; }
RareData* EnsureRareData() {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
index 9a1709ec95f..68cc44fc392 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h
@@ -145,6 +145,10 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
void SetIsShrinkToFit(bool b) { space_.bitfields_.is_shrink_to_fit = b; }
+ void SetIsPaintedAtomically(bool b) {
+ space_.bitfields_.is_painted_atomically = b;
+ }
+
void SetFragmentationType(NGFragmentationType fragmentation_type) {
#if DCHECK_IS_ON()
DCHECK(!is_block_direction_fragmentation_type_set_);
@@ -172,13 +176,16 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
void SetIsRestrictedBlockSizeTableCell(bool b) {
DCHECK(space_.bitfields_.is_table_cell);
- space_.bitfields_.is_restricted_block_size_table_cell = b;
+ if (!b && !space_.rare_data_)
+ return;
+ space_.EnsureRareData()->is_restricted_block_size_table_cell = b;
}
void SetHideTableCellIfEmpty(bool b) {
DCHECK(space_.bitfields_.is_table_cell);
- if (b)
- space_.EnsureRareData()->hide_table_cell_if_empty = b;
+ if (!b && !space_.rare_data_)
+ return;
+ space_.EnsureRareData()->hide_table_cell_if_empty = b;
}
void SetIsAnonymous(bool b) { space_.bitfields_.is_anonymous = b; }
@@ -187,10 +194,6 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
space_.bitfields_.use_first_line_style = b;
}
- void SetAncestorHasClearancePastAdjoiningFloats() {
- space_.bitfields_.ancestor_has_clearance_past_adjoining_floats = true;
- }
-
void SetAdjoiningObjectTypes(NGAdjoiningObjectTypes adjoining_object_types) {
if (!is_new_fc_) {
space_.bitfields_.adjoining_object_types =
@@ -198,6 +201,20 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
}
}
+ void SetAncestorHasClearancePastAdjoiningFloats() {
+ space_.bitfields_.ancestor_has_clearance_past_adjoining_floats = true;
+ }
+
+ void SetNeedsBaseline(bool b) { space_.bitfields_.needs_baseline = b; }
+
+ void SetBaselineAlgorithmType(NGBaselineAlgorithmType type) {
+ space_.bitfields_.baseline_algorithm_type = static_cast<unsigned>(type);
+ }
+
+ void SetCacheSlot(NGCacheSlot slot) {
+ space_.bitfields_.cache_slot = static_cast<unsigned>(slot);
+ }
+
void SetMarginStrut(const NGMarginStrut& margin_strut) {
#if DCHECK_IS_ON()
DCHECK(!is_margin_strut_set_);
@@ -301,12 +318,41 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
}
}
- void AddBaselineRequests(const NGBaselineRequestList requests) {
- DCHECK(baseline_requests_.IsEmpty());
- baseline_requests_.AppendVector(requests);
+ void SetForceTruncateAtLineClamp(bool value) {
+#if DCHECK_IS_ON()
+ DCHECK(!is_force_truncate_at_line_clamp_set_);
+ is_force_truncate_at_line_clamp_set_ = true;
+#endif
+ if (!value)
+ space_.EnsureRareData()->SetForceTruncateAtLineClamp(value);
}
- void AddBaselineRequest(const NGBaselineRequest request) {
- baseline_requests_.push_back(request);
+
+ void SetLinesUntilClamp(const base::Optional<int>& clamp) {
+#if DCHECK_IS_ON()
+ DCHECK(!is_lines_until_clamp_set_);
+ is_lines_until_clamp_set_ = true;
+#endif
+ DCHECK(!is_new_fc_);
+ if (clamp)
+ space_.EnsureRareData()->SetLinesUntilClamp(*clamp);
+ }
+
+ void SetTargetStretchInlineSize(LayoutUnit target_stretch_inline_size) {
+ DCHECK_GE(target_stretch_inline_size, LayoutUnit());
+ space_.EnsureRareData()->SetTargetStretchInlineSize(
+ target_stretch_inline_size);
+ }
+
+ void SetTargetStretchAscentSize(LayoutUnit target_stretch_ascent_size) {
+ DCHECK_GE(target_stretch_ascent_size, LayoutUnit());
+ space_.EnsureRareData()->SetTargetStretchAscentSize(
+ target_stretch_ascent_size);
+ }
+
+ void SetTargetStretchDescentSize(LayoutUnit target_stretch_descent_size) {
+ DCHECK_GE(target_stretch_descent_size, LayoutUnit());
+ space_.EnsureRareData()->SetTargetStretchDescentSize(
+ target_stretch_descent_size);
}
// Creates a new constraint space.
@@ -326,7 +372,6 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
"simultaneously. Inferred means the constraints are in parent "
"writing mode, forced means they are in child writing mode.";
- space_.bitfields_.baseline_requests = baseline_requests_.Serialize();
return std::move(space_);
}
@@ -355,11 +400,11 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
bool is_table_cell_borders_set_ = false;
bool is_table_cell_intrinsic_padding_set_ = false;
bool is_custom_layout_data_set_ = false;
+ bool is_lines_until_clamp_set_ = false;
+ bool is_force_truncate_at_line_clamp_set_ = false;
bool to_constraint_space_called_ = false;
#endif
-
- NGBaselineRequestList baseline_requests_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
index 6e6115501e8..4c26a00648f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc
@@ -101,7 +101,7 @@ void NGContainerFragmentBuilder::PropagateChildData(
// have a child positioned above our block-start edge.
if ((child_offset.block_offset < LayoutUnit() &&
!child.IsOutOfFlowPositioned()) ||
- (!child.IsBlockFormattingContextRoot() && !child.IsLineBox() &&
+ (!child.IsFormattingContextRoot() && !child.IsLineBox() &&
child.MayHaveDescendantAboveBlockStart()))
may_have_descendant_above_block_start_ = true;
@@ -120,7 +120,7 @@ void NGContainerFragmentBuilder::PropagateChildData(
// If a fragment doesn't have any adjoining object descendants, and is
// self-collapsing, it can be "shifted" anywhere.
if (!has_adjoining_object_descendants_) {
- if (!child.IsBlockFormattingContextRoot() &&
+ if (!child.IsFormattingContextRoot() &&
child.HasAdjoiningObjectDescendants())
has_adjoining_object_descendants_ = true;
}
@@ -132,7 +132,6 @@ void NGContainerFragmentBuilder::PropagateChildData(
if (const NGBreakToken* child_break_token = child.BreakToken()) {
switch (child.Type()) {
case NGPhysicalFragment::kFragmentBox:
- case NGPhysicalFragment::kFragmentRenderedLegend:
child_break_tokens_.push_back(child_break_token);
break;
case NGPhysicalFragment::kFragmentLineBox:
@@ -163,33 +162,6 @@ void NGContainerFragmentBuilder::AddChildInternal(
children_.emplace_back(child_offset, std::move(child));
}
-LogicalOffset NGContainerFragmentBuilder::GetChildOffset(
- const LayoutObject* object) const {
- for (const auto& child : children_) {
- if (child.fragment->GetLayoutObject() == object)
- return child.offset;
-
- // TODO(layout-dev): ikilpatrick thinks we may need to traverse
- // further than the initial line-box children for a nested inline
- // container. We could not come up with a testcase, it would be
- // something with split inlines, and nested oof/fixed descendants maybe.
- if (child.fragment->IsLineBox()) {
- const auto& line_box_fragment =
- To<NGPhysicalLineBoxFragment>(*child.fragment);
- for (const auto& line_box_child : line_box_fragment.Children()) {
- if (line_box_child->GetLayoutObject() == object) {
- return child.offset + line_box_child.Offset().ConvertToLogical(
- GetWritingMode(), Direction(),
- line_box_fragment.Size(),
- line_box_child->Size());
- }
- }
- }
- }
- NOTREACHED();
- return LogicalOffset();
-}
-
void NGContainerFragmentBuilder::AddOutOfFlowChildCandidate(
NGBlockNode child,
const LogicalOffset& child_offset,
@@ -197,8 +169,17 @@ void NGContainerFragmentBuilder::AddOutOfFlowChildCandidate(
NGLogicalStaticPosition::BlockEdge block_edge) {
DCHECK(child);
+ // If an OOF-positioned candidate has a static-position which uses a
+ // non-block-start edge, we need to adjust its static-position when the final
+ // block-size is known.
+ bool needs_block_offset_adjustment =
+ block_edge != NGLogicalStaticPosition::BlockEdge::kBlockStart;
+ has_oof_candidate_that_needs_block_offset_adjustment_ |=
+ needs_block_offset_adjustment;
+
oof_positioned_candidates_.emplace_back(
- child, NGLogicalStaticPosition{child_offset, inline_edge, block_edge});
+ child, NGLogicalStaticPosition{child_offset, inline_edge, block_edge},
+ /* inline_container */ nullptr, needs_block_offset_adjustment);
}
void NGContainerFragmentBuilder::AddOutOfFlowInlineChildCandidate(
@@ -226,6 +207,27 @@ void NGContainerFragmentBuilder::SwapOutOfFlowPositionedCandidates(
Vector<NGLogicalOutOfFlowPositionedNode>* candidates) {
DCHECK(candidates->IsEmpty());
std::swap(oof_positioned_candidates_, *candidates);
+
+ if (!has_oof_candidate_that_needs_block_offset_adjustment_)
+ return;
+
+ using BlockEdge = NGLogicalStaticPosition::BlockEdge;
+
+ // We might have an OOF-positioned candidate whose static-position depends on
+ // the final block-size of this fragment.
+ DCHECK_NE(BlockSize(), kIndefiniteSize);
+ for (auto& candidate : *candidates) {
+ if (!candidate.needs_block_offset_adjustment)
+ continue;
+
+ if (candidate.static_position.block_edge == BlockEdge::kBlockCenter)
+ candidate.static_position.offset.block_offset += BlockSize() / 2;
+ else if (candidate.static_position.block_edge == BlockEdge::kBlockEnd)
+ candidate.static_position.offset.block_offset += BlockSize();
+ candidate.needs_block_offset_adjustment = false;
+ }
+
+ has_oof_candidate_that_needs_block_offset_adjustment_ = false;
}
void NGContainerFragmentBuilder::
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
index 0ca512fee7f..a76a849df0b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h
@@ -88,10 +88,6 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
const ChildrenVector& Children() const { return children_; }
- // Returns offset for given child. DCHECK if child not found.
- // Warning: Do not call unless necessary.
- LogicalOffset GetChildOffset(const LayoutObject* child) const;
-
// Builder has non-trivial OOF-positioned methods.
// They are intended to be used by a layout algorithm like this:
//
@@ -183,8 +179,9 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
#endif
protected:
- friend class NGPhysicalContainerFragment;
+ friend class NGInlineLayoutStateStack;
friend class NGLayoutResult;
+ friend class NGPhysicalContainerFragment;
NGContainerFragmentBuilder(NGLayoutInputNode node,
scoped_refptr<const ComputedStyle> style,
@@ -240,6 +237,8 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGFragmentBuilder {
bool has_block_fragmentation_ = false;
bool is_fragmentation_context_root_ = false;
bool may_have_descendant_above_block_start_ = false;
+
+ bool has_oof_candidate_that_needs_block_offset_adjustment_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
index 79bf0f09f45..02c3b80ed79 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
@@ -21,16 +22,30 @@ namespace blink {
NGFieldsetLayoutAlgorithm::NGFieldsetLayoutAlgorithm(
const NGLayoutAlgorithmParams& params)
: NGLayoutAlgorithm(params),
+ writing_mode_(ConstraintSpace().GetWritingMode()),
border_padding_(params.fragment_geometry.border +
- params.fragment_geometry.padding) {
+ params.fragment_geometry.padding),
+ consumed_block_size_(BreakToken() ? BreakToken()->ConsumedBlockSize()
+ : LayoutUnit()) {
container_builder_.SetIsNewFormattingContext(
params.space.IsNewFormattingContext());
container_builder_.SetInitialFragmentGeometry(params.fragment_geometry);
+
+ borders_ = container_builder_.Borders();
+ padding_ = container_builder_.Padding();
+ border_box_size_ = container_builder_.InitialBorderBoxSize();
+ block_start_padding_edge_ = borders_.block_start;
+
+ // Leading border and padding should only apply to the first fragment. We
+ // don't adjust the value of border_padding_ itself so that it can be used
+ // when calculating the block size of the last fragment.
+ adjusted_border_padding_ = border_padding_;
+ AdjustForFragmentation(BreakToken(), &adjusted_border_padding_);
}
scoped_refptr<const NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() {
- // TODO(mstensho): Support block fragmentation.
- DCHECK(!BreakToken());
+ // TODO(almaher): Make sure the border start is handled correctly during
+ // fragmentation.
// Layout of a fieldset container consists of two parts: Create a child
// fragment for the rendered legend (if any), and create a child fragment for
@@ -42,87 +57,32 @@ scoped_refptr<const NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() {
// with the actual fieldset contents. Since scrollbars are handled by the
// anonymous child box, and since padding is inside the scrollport, padding
// also needs to be handled by the anonymous child.
- NGBoxStrut borders = container_builder_.Borders();
- NGBoxStrut padding = container_builder_.Padding();
- LogicalSize border_box_size = container_builder_.InitialBorderBoxSize();
- const auto writing_mode = ConstraintSpace().GetWritingMode();
- LayoutUnit block_start_padding_edge =
- container_builder_.Borders().block_start;
-
- // TODO(vmpstr): Skip child (including legend) layout for fieldset elements.
- if (NGBlockNode legend = Node().GetRenderedLegend()) {
- // Lay out the legend. While the fieldset container normally ignores its
- // padding, the legend is laid out within what would have been the content
- // box had the fieldset been a regular block with no weirdness.
- LogicalSize content_box_size =
- ShrinkAvailableSize(border_box_size, border_padding_);
- auto legend_space =
- CreateConstraintSpaceForLegend(legend, content_box_size);
- auto result = legend.Layout(legend_space, BreakToken());
- const auto& physical_fragment = result->PhysicalFragment();
- NGBoxStrut legend_margins =
- ComputeMarginsFor(legend_space, legend.Style(), ConstraintSpace());
- // If the margin box of the legend is at least as tall as the fieldset
- // block-start border width, it will start at the block-start border edge of
- // the fieldset. As a paint effect, the block-start border will be pushed so
- // that the center of the border will be flush with the center of the
- // border-box of the legend.
- // TODO(mstensho): inline alignment
- LogicalOffset legend_offset = LogicalOffset(
- border_padding_.inline_start + legend_margins.inline_start,
- legend_margins.block_start);
- LayoutUnit legend_margin_box_block_size =
- NGFragment(writing_mode, physical_fragment).BlockSize() +
- legend_margins.BlockSum();
- LayoutUnit space_left = borders.block_start - legend_margin_box_block_size;
- if (space_left > LayoutUnit()) {
- // If the border is the larger one, though, it will stay put at the
- // border-box block-start edge of the fieldset. Then it's the legend that
- // needs to be pushed. We'll center the margin box in this case, to make
- // sure that both margins remain within the area occupied by the border
- // also after adjustment.
- legend_offset.block_offset += space_left / 2;
- } else {
- // If the legend is larger than the width of the fieldset block-start
- // border, the actual padding edge of the fieldset will be moved
- // accordingly. This will be the block-start offset for the fieldset
- // contents anonymous box.
- block_start_padding_edge = legend_margin_box_block_size;
- }
-
- container_builder_.AddChild(physical_fragment, legend_offset);
- }
- NGBoxStrut borders_with_legend = borders;
- borders_with_legend.block_start = block_start_padding_edge;
- LayoutUnit intrinsic_block_size = borders_with_legend.BlockSum();
+ if (ConstraintSpace().HasBlockFragmentation()) {
+ container_builder_.SetHasBlockFragmentation();
+ // The whereabouts of our container's so far best breakpoint is none of our
+ // business, but we store its appeal, so that we don't look for breakpoints
+ // with lower appeal than that.
+ container_builder_.SetBreakAppeal(ConstraintSpace().EarlyBreakAppeal());
- // Proceed with normal fieldset children (excluding the rendered legend). They
- // all live inside an anonymous child box of the fieldset container.
- if (auto fieldset_content = Node().GetFieldsetContent()) {
- LogicalSize adjusted_padding_box_size =
- ShrinkAvailableSize(border_box_size, borders_with_legend);
- auto child_space =
- CreateConstraintSpaceForFieldsetContent(adjusted_padding_box_size);
- auto result = fieldset_content.Layout(child_space, BreakToken());
- const auto& physical_fragment = result->PhysicalFragment();
- container_builder_.AddChild(physical_fragment,
- borders_with_legend.StartOffset());
+ if (ConstraintSpace().IsInitialColumnBalancingPass())
+ container_builder_.SetIsInitialColumnBalancingPass();
+ }
- intrinsic_block_size +=
- NGFragment(writing_mode, physical_fragment).BlockSize();
- } else {
- // There was no anonymous child to provide the padding, so we have to add it
- // ourselves.
- intrinsic_block_size += padding.BlockSum();
+ NGBreakStatus break_status = LayoutChildren();
+ if (break_status == NGBreakStatus::kNeedsEarlierBreak) {
+ // We need to abort the layout. No fragment will be generated.
+ return container_builder_.Abort(NGLayoutResult::kNeedsEarlierBreak);
}
- intrinsic_block_size = ClampIntrinsicBlockSize(
- ConstraintSpace(), Node(), border_padding_, intrinsic_block_size);
+ intrinsic_block_size_ =
+ ClampIntrinsicBlockSize(ConstraintSpace(), Node(),
+ adjusted_border_padding_, intrinsic_block_size_);
// Recompute the block-axis size now that we know our content size.
- border_box_size.block_size = ComputeBlockSizeForFragment(
- ConstraintSpace(), Style(), border_padding_, intrinsic_block_size);
+ border_box_size_.block_size =
+ ComputeBlockSizeForFragment(ConstraintSpace(), Style(), border_padding_,
+ intrinsic_block_size_ + consumed_block_size_);
// The above computation utility knows nothing about fieldset weirdness. The
// legend may eat from the available content box block size. Make room for
@@ -131,34 +91,291 @@ scoped_refptr<const NGLayoutResult> NGFieldsetLayoutAlgorithm::Layout() {
// contents, with the conjecture being that legend is part of the contents.
// Thus, only do this adjustment if we do not contain size.
if (!Node().ShouldApplySizeContainment()) {
- LayoutUnit minimum_border_box_block_size =
- borders_with_legend.BlockSum() + padding.BlockSum();
- border_box_size.block_size =
- std::max(border_box_size.block_size, minimum_border_box_block_size);
+ // Similar to how we add the consumed block size to the intrinsic
+ // block size when calculating border_box_size_.block_size, we also need to
+ // do so when the fieldset is adjusted to encompass the legend.
+ border_box_size_.block_size =
+ std::max(border_box_size_.block_size,
+ minimum_border_box_block_size_ + consumed_block_size_);
}
+ // TODO(almaher): end border and padding may overflow the parent
+ // fragmentainer, and we should avoid that.
+ LayoutUnit block_size = border_box_size_.block_size - consumed_block_size_;
+
container_builder_.SetIsFieldsetContainer();
- container_builder_.SetIntrinsicBlockSize(intrinsic_block_size);
- container_builder_.SetBlockSize(border_box_size.block_size);
+ if (ConstraintSpace().HasKnownFragmentainerBlockSize()) {
+ FinishFragmentation(
+ ConstraintSpace(), BreakToken(), block_size, intrinsic_block_size_,
+ FragmentainerSpaceAtBfcStart(ConstraintSpace()), &container_builder_);
+ } else {
+ container_builder_.SetIntrinsicBlockSize(intrinsic_block_size_);
+ container_builder_.SetBlockSize(block_size);
+ }
- NGOutOfFlowLayoutPart(Node(), ConstraintSpace(), borders_with_legend,
+ NGOutOfFlowLayoutPart(Node(), ConstraintSpace(), borders_with_legend_,
&container_builder_)
.Run();
return container_builder_.ToBoxFragment();
}
-base::Optional<MinMaxSize> NGFieldsetLayoutAlgorithm::ComputeMinMaxSize(
- const MinMaxSizeInput& input) const {
- MinMaxSize sizes;
+NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutChildren() {
+ scoped_refptr<const NGBlockBreakToken> legend_break_token;
+ scoped_refptr<const NGBlockBreakToken> content_break_token;
+ bool has_seen_all_children = false;
+ if (const auto* token = BreakToken()) {
+ const auto child_tokens = token->ChildBreakTokens();
+ if (wtf_size_t break_token_count = child_tokens.size()) {
+ DCHECK_LE(break_token_count, 2u);
+ for (wtf_size_t break_token_idx = 0; break_token_idx < break_token_count;
+ break_token_idx++) {
+ scoped_refptr<const NGBlockBreakToken> child_token =
+ To<NGBlockBreakToken>(child_tokens[break_token_idx]);
+ if (child_token && child_token->InputNode().IsRenderedLegend()) {
+ DCHECK_EQ(break_token_idx, 0u);
+ legend_break_token = child_token;
+ } else {
+ content_break_token = child_token;
+ }
+ }
+ }
+ if (token->HasSeenAllChildren()) {
+ container_builder_.SetHasSeenAllChildren();
+ has_seen_all_children = true;
+ }
+ }
+
+ NGBlockNode legend = Node().GetRenderedLegend();
+ bool legend_needs_layout =
+ legend && (legend_break_token || !IsResumingLayout(BreakToken()));
- bool apply_size_containment = node_.ShouldApplySizeContainment();
- // TODO(crbug.com/1011842): Need to consider content-size here.
- if (apply_size_containment) {
- if (input.size_type == NGMinMaxSizeType::kContentBoxSize)
- return sizes;
+ if (legend_needs_layout) {
+ NGBreakStatus break_status = LayoutLegend(legend, legend_break_token);
+ if (break_status != NGBreakStatus::kContinue)
+ return break_status;
+ }
+
+ borders_with_legend_ = borders_;
+ borders_with_legend_.block_start = block_start_padding_edge_;
+
+ // The legend may eat from the available content box block size. If the
+ // border_box_size_ is expanded to encompass the legend, then update the
+ // border_box_size_ here, as well, to ensure the fieldset content gets the
+ // correct size.
+ if (!Node().ShouldApplySizeContainment() && legend_needs_layout) {
+ minimum_border_box_block_size_ =
+ borders_with_legend_.BlockSum() + padding_.BlockSum();
+ if (border_box_size_.block_size != kIndefiniteSize) {
+ border_box_size_.block_size =
+ std::max(border_box_size_.block_size, minimum_border_box_block_size_);
+ }
+ }
+
+ LogicalSize adjusted_padding_box_size =
+ ShrinkAvailableSize(border_box_size_, borders_with_legend_);
+
+ // If the legend has been laid out in previous fragments,
+ // adjusted_padding_box_size will need to be adjusted further to account for
+ // block size taken up by the legend.
+ if (legend && adjusted_padding_box_size.block_size != kIndefiniteSize) {
+ LayoutUnit content_consumed_block_size =
+ content_break_token ? content_break_token->ConsumedBlockSize()
+ : LayoutUnit();
+ LayoutUnit legend_block_size =
+ consumed_block_size_ - content_consumed_block_size;
+ adjusted_padding_box_size.block_size =
+ std::max(padding_.BlockSum(),
+ adjusted_padding_box_size.block_size - legend_block_size);
+ }
+
+ if ((IsResumingLayout(content_break_token.get())) ||
+ (!block_start_padding_edge_adjusted_ && IsResumingLayout(BreakToken()))) {
+ borders_with_legend_.block_start = LayoutUnit();
+ }
+ intrinsic_block_size_ = borders_with_legend_.BlockSum();
+
+ // Proceed with normal fieldset children (excluding the rendered legend). They
+ // all live inside an anonymous child box of the fieldset container.
+ auto fieldset_content = Node().GetFieldsetContent();
+ if (fieldset_content && (content_break_token || !has_seen_all_children)) {
+ LayoutUnit fragmentainer_block_offset;
+ if (ConstraintSpace().HasBlockFragmentation()) {
+ fragmentainer_block_offset =
+ ConstraintSpace().FragmentainerOffsetAtBfc() + intrinsic_block_size_;
+ if (legend_broke_ &&
+ IsFragmentainerOutOfSpace(fragmentainer_block_offset))
+ return NGBreakStatus::kContinue;
+ }
+ NGBreakStatus break_status = LayoutFieldsetContent(
+ fieldset_content, content_break_token, adjusted_padding_box_size,
+ fragmentainer_block_offset, !!legend);
+ if (break_status == NGBreakStatus::kNeedsEarlierBreak)
+ return break_status;
+ }
+
+ if (!fieldset_content) {
+ container_builder_.SetHasSeenAllChildren();
+ // There was no anonymous child to provide the padding, so we have to add it
+ // ourselves.
+ intrinsic_block_size_ += padding_.BlockSum();
}
+ return NGBreakStatus::kContinue;
+}
+
+NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutLegend(
+ NGBlockNode& legend,
+ scoped_refptr<const NGBlockBreakToken> legend_break_token) {
+ // Lay out the legend. While the fieldset container normally ignores its
+ // padding, the legend is laid out within what would have been the content
+ // box had the fieldset been a regular block with no weirdness.
+ LogicalSize content_box_size =
+ ShrinkAvailableSize(border_box_size_, adjusted_border_padding_);
+ LogicalSize percentage_size =
+ CalculateChildPercentageSize(ConstraintSpace(), Node(), content_box_size);
+ NGBoxStrut legend_margins = ComputeMarginsFor(
+ legend.Style(), percentage_size.inline_size,
+ ConstraintSpace().GetWritingMode(), ConstraintSpace().Direction());
+
+ if (legend_break_token)
+ legend_margins.block_start = LayoutUnit();
+
+ LogicalOffset legend_offset;
+ scoped_refptr<const NGLayoutResult> result;
+ scoped_refptr<const NGLayoutResult> previous_result;
+ LayoutUnit block_offset = legend_margins.block_start;
+ do {
+ auto legend_space = CreateConstraintSpaceForLegend(
+ legend, content_box_size, percentage_size, block_offset);
+ result = legend.Layout(legend_space, legend_break_token.get());
+
+ // TODO(layout-dev): Handle abortions caused by block fragmentation.
+ DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
+
+ if (ConstraintSpace().HasBlockFragmentation()) {
+ NGBreakStatus break_status = BreakBeforeChildIfNeeded(
+ ConstraintSpace(), legend, *result.get(),
+ ConstraintSpace().FragmentainerOffsetAtBfc() + block_offset,
+ /*has_container_separation*/ false, &container_builder_);
+ if (break_status != NGBreakStatus::kContinue)
+ return break_status;
+ EBreakBetween break_after = JoinFragmentainerBreakValues(
+ result->FinalBreakAfter(), legend.Style().BreakAfter());
+ container_builder_.SetPreviousBreakAfter(break_after);
+ }
+
+ const auto& physical_fragment = result->PhysicalFragment();
+ legend_broke_ = physical_fragment.BreakToken();
+
+ // We have already adjusted the legend block offset, no need to adjust
+ // again.
+ if (block_offset != legend_margins.block_start) {
+ // If adjusting the block_offset caused the legend to break, revert back
+ // to the previous result.
+ if (legend_broke_) {
+ result = std::move(previous_result);
+ block_offset = legend_margins.block_start;
+ }
+ break;
+ }
+
+ LayoutUnit legend_margin_box_block_size =
+ NGFragment(writing_mode_, physical_fragment).BlockSize() +
+ legend_margins.BlockSum();
+ LayoutUnit space_left = borders_.block_start - legend_margin_box_block_size;
+ if (space_left > LayoutUnit()) {
+ // Don't adjust the block_offset if the legend broke.
+ if (legend_break_token || legend_broke_)
+ break;
+
+ // If the border is the larger one, though, it will stay put at the
+ // border-box block-start edge of the fieldset. Then it's the legend
+ // that needs to be pushed. We'll center the margin box in this case, to
+ // make sure that both margins remain within the area occupied by the
+ // border also after adjustment.
+ block_offset += space_left / 2;
+ if (ConstraintSpace().HasBlockFragmentation()) {
+ // Save the previous result in case adjusting the block_offset causes
+ // the legend to break.
+ previous_result = std::move(result);
+ continue;
+ }
+ } else {
+ // If the legend is larger than the width of the fieldset block-start
+ // border, the actual padding edge of the fieldset will be moved
+ // accordingly. This will be the block-start offset for the fieldset
+ // contents anonymous box.
+ block_start_padding_edge_ = legend_margin_box_block_size;
+ block_start_padding_edge_adjusted_ = true;
+ }
+ break;
+ } while (true);
+
+ // If the margin box of the legend is at least as tall as the fieldset
+ // block-start border width, it will start at the block-start border edge
+ // of the fieldset. As a paint effect, the block-start border will be
+ // pushed so that the center of the border will be flush with the center
+ // of the border-box of the legend.
+ // TODO(mstensho): inline alignment
+ legend_offset = LogicalOffset(
+ adjusted_border_padding_.inline_start + legend_margins.inline_start,
+ block_offset);
+
+ container_builder_.AddResult(*result, legend_offset);
+ return NGBreakStatus::kContinue;
+}
+
+NGBreakStatus NGFieldsetLayoutAlgorithm::LayoutFieldsetContent(
+ NGBlockNode& fieldset_content,
+ scoped_refptr<const NGBlockBreakToken> content_break_token,
+ LogicalSize adjusted_padding_box_size,
+ LayoutUnit fragmentainer_block_offset,
+ bool has_legend) {
+ auto child_space = CreateConstraintSpaceForFieldsetContent(
+ fieldset_content, adjusted_padding_box_size,
+ borders_with_legend_.block_start);
+ auto result = fieldset_content.Layout(child_space, content_break_token.get());
+
+ // TODO(layout-dev): Handle abortions caused by block fragmentation.
+ DCHECK_EQ(result->Status(), NGLayoutResult::kSuccess);
+
+ NGBreakStatus break_status = NGBreakStatus::kContinue;
+ if (ConstraintSpace().HasBlockFragmentation()) {
+ // TODO(almaher): The legend should be treated as out-of-flow.
+ break_status = BreakBeforeChildIfNeeded(
+ ConstraintSpace(), fieldset_content, *result.get(),
+ fragmentainer_block_offset,
+ /*has_container_separation*/ has_legend, &container_builder_);
+ EBreakBetween break_after = JoinFragmentainerBreakValues(
+ result->FinalBreakAfter(), fieldset_content.Style().BreakAfter());
+ container_builder_.SetPreviousBreakAfter(break_after);
+ }
+
+ if (break_status == NGBreakStatus::kContinue) {
+ container_builder_.AddResult(*result, borders_with_legend_.StartOffset());
+ intrinsic_block_size_ +=
+ NGFragment(writing_mode_, result->PhysicalFragment()).BlockSize();
+ container_builder_.SetHasSeenAllChildren();
+ }
+
+ return break_status;
+}
+
+bool NGFieldsetLayoutAlgorithm::IsFragmentainerOutOfSpace(
+ LayoutUnit block_offset) const {
+ if (!ConstraintSpace().HasKnownFragmentainerBlockSize())
+ return false;
+ return block_offset >= FragmentainerSpaceAtBfcStart(ConstraintSpace());
+}
+
+base::Optional<MinMaxSizes> NGFieldsetLayoutAlgorithm::ComputeMinMaxSizes(
+ const MinMaxSizesInput& input) const {
+ MinMaxSizes sizes;
+
+ // TODO(crbug.com/1011842): Need to consider content-size here.
+ bool apply_size_containment = Node().ShouldApplySizeContainment();
+
// Size containment does not consider the legend for sizing.
if (!apply_size_containment) {
if (NGBlockNode legend = Node().GetRenderedLegend()) {
@@ -170,42 +387,51 @@ base::Optional<MinMaxSize> NGFieldsetLayoutAlgorithm::ComputeMinMaxSize(
// The fieldset content includes the fieldset padding (and any scrollbars),
// while the legend is a regular child and doesn't. We may have a fieldset
// without any content or legend, so add the padding here, on the outside.
- sizes += ComputePadding(ConstraintSpace(), node_.Style()).InlineSum();
+ sizes += ComputePadding(ConstraintSpace(), Style()).InlineSum();
// Size containment does not consider the content for sizing.
if (!apply_size_containment) {
if (NGBlockNode content = Node().GetFieldsetContent()) {
- MinMaxSize content_minmax =
+ MinMaxSizes content_min_max_sizes =
ComputeMinAndMaxContentContribution(Style(), content, input);
- content_minmax += ComputeMinMaxMargins(Style(), content).InlineSum();
- sizes.Encompass(content_minmax);
+ content_min_max_sizes +=
+ ComputeMinMaxMargins(Style(), content).InlineSum();
+ sizes.Encompass(content_min_max_sizes);
}
}
- sizes += ComputeBorders(ConstraintSpace(), node_).InlineSum();
+ sizes += ComputeBorders(ConstraintSpace(), Style()).InlineSum();
return sizes;
}
const NGConstraintSpace
NGFieldsetLayoutAlgorithm::CreateConstraintSpaceForLegend(
NGBlockNode legend,
- LogicalSize available_size) {
+ LogicalSize available_size,
+ LogicalSize percentage_size,
+ LayoutUnit block_offset) {
NGConstraintSpaceBuilder builder(
ConstraintSpace(), legend.Style().GetWritingMode(), /* is_new_fc */ true);
SetOrthogonalFallbackInlineSizeIfNeeded(Style(), legend, &builder);
builder.SetAvailableSize(available_size);
- LogicalSize percentage_size =
- CalculateChildPercentageSize(ConstraintSpace(), Node(), available_size);
builder.SetPercentageResolutionSize(percentage_size);
builder.SetIsShrinkToFit(legend.Style().LogicalWidth().IsAuto());
builder.SetTextDirection(legend.Style().Direction());
+
+ if (ConstraintSpace().HasBlockFragmentation()) {
+ SetupFragmentation(ConstraintSpace(), legend, block_offset, &builder,
+ /* is_new_fc */ true);
+ builder.SetEarlyBreakAppeal(container_builder_.BreakAppeal());
+ }
return builder.ToConstraintSpace();
}
const NGConstraintSpace
NGFieldsetLayoutAlgorithm::CreateConstraintSpaceForFieldsetContent(
- LogicalSize padding_box_size) {
+ NGBlockNode fieldset_content,
+ LogicalSize padding_box_size,
+ LayoutUnit block_offset) {
NGConstraintSpaceBuilder builder(ConstraintSpace(),
ConstraintSpace().GetWritingMode(),
/* is_new_fc */ true);
@@ -213,6 +439,12 @@ NGFieldsetLayoutAlgorithm::CreateConstraintSpaceForFieldsetContent(
builder.SetPercentageResolutionSize(
ConstraintSpace().PercentageResolutionSize());
builder.SetIsFixedBlockSize(padding_box_size.block_size != kIndefiniteSize);
+
+ if (ConstraintSpace().HasBlockFragmentation()) {
+ SetupFragmentation(ConstraintSpace(), fieldset_content, block_offset,
+ &builder, /* is_new_fc */ true);
+ builder.SetEarlyBreakAppeal(container_builder_.BreakAppeal());
+ }
return builder.ToConstraintSpace();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h
index df5a8d3538b..c375081737a 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm.h
@@ -12,6 +12,7 @@
namespace blink {
+enum class NGBreakStatus;
class NGBlockBreakToken;
class NGConstraintSpace;
@@ -24,16 +25,63 @@ class CORE_EXPORT NGFieldsetLayoutAlgorithm
scoped_refptr<const NGLayoutResult> Layout() override;
- base::Optional<MinMaxSize> ComputeMinMaxSize(
- const MinMaxSizeInput&) const override;
+ base::Optional<MinMaxSizes> ComputeMinMaxSizes(
+ const MinMaxSizesInput&) const override;
+
+ private:
+ NGBreakStatus LayoutChildren();
+ NGBreakStatus LayoutLegend(
+ NGBlockNode& legend,
+ scoped_refptr<const NGBlockBreakToken> legend_break_token);
+ NGBreakStatus LayoutFieldsetContent(
+ NGBlockNode& fieldset_content,
+ scoped_refptr<const NGBlockBreakToken> content_break_token,
+ LogicalSize adjusted_padding_box_size,
+ LayoutUnit fragmentainer_block_offset,
+ bool has_legend);
const NGConstraintSpace CreateConstraintSpaceForLegend(
NGBlockNode legend,
- LogicalSize available_size);
+ LogicalSize available_size,
+ LogicalSize percentage_size,
+ LayoutUnit block_offset);
const NGConstraintSpace CreateConstraintSpaceForFieldsetContent(
- LogicalSize padding_box_size);
+ NGBlockNode fieldset_content,
+ LogicalSize padding_box_size,
+ LayoutUnit block_offset);
+
+ bool IsFragmentainerOutOfSpace(LayoutUnit block_offset) const;
+
+ const WritingMode writing_mode_;
const NGBoxStrut border_padding_;
+ NGBoxStrut borders_;
+ NGBoxStrut padding_;
+
+ // The border and padding after adjusting to ensure that the leading border
+ // and padding are only applied to the first fragment.
+ NGBoxStrut adjusted_border_padding_;
+
+ // The result of borders_ after positioning the fieldset's legend element.
+ NGBoxStrut borders_with_legend_;
+
+ LayoutUnit block_start_padding_edge_;
+ LayoutUnit intrinsic_block_size_;
+ const LayoutUnit consumed_block_size_;
+ LogicalSize border_box_size_;
+
+ // The legend may eat from the available content box block size. This
+ // represents the minimum block size needed by the border box to encompass
+ // the legend.
+ LayoutUnit minimum_border_box_block_size_;
+
+ // If true, this indicates the block_start_padding_edge_ had changed from its
+ // initial value during the current layout pass.
+ bool block_start_padding_edge_adjusted_ = false;
+
+ // If true, this indicates that the legend broke during the current layout
+ // pass.
+ bool legend_broke_ = false;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
index ab1718db0e4..36789003311 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fieldset_layout_algorithm_test.cc
@@ -35,25 +35,26 @@ class NGFieldsetLayoutAlgorithmTest
return NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(container, space);
}
- MinMaxSize RunComputeMinAndMax(NGBlockNode node) {
+ MinMaxSizes RunComputeMinMaxSizes(NGBlockNode node) {
NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
WritingMode::kHorizontalTb, TextDirection::kLtr,
- LogicalSize(LayoutUnit(), LayoutUnit()));
+ LogicalSize(LayoutUnit(), LayoutUnit()), false,
+ node.CreatesNewFormattingContext());
NGFragmentGeometry fragment_geometry =
CalculateInitialMinMaxFragmentGeometry(space, node);
NGFieldsetLayoutAlgorithm algorithm({node, fragment_geometry, space});
- MinMaxSizeInput input(
+ MinMaxSizesInput input(
/* percentage_resolution_block_size */ (LayoutUnit()));
- auto min_max = algorithm.ComputeMinMaxSize(input);
+ auto min_max = algorithm.ComputeMinMaxSizes(input);
EXPECT_TRUE(min_max.has_value());
return *min_max;
}
- MinMaxSize RunComputeMinAndMax(const char* element_id) {
+ MinMaxSizes RunComputeMinMaxSizes(const char* element_id) {
Element* element = GetDocument().getElementById(element_id);
NGBlockNode node(ToLayoutBox(element->GetLayoutObject()));
- return RunComputeMinAndMax(node);
+ return RunComputeMinMaxSizes(node);
}
String DumpFragmentTree(const NGPhysicalBoxFragment* fragment) {
@@ -349,7 +350,7 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, ZeroHeight) {
offset:unplaced size:1000x53
offset:0,0 size:126x53
offset:13,0 size:30x30
- offset:3,30 size:120x0
+ offset:3,30 size:120x20
offset:10,10 size:100x200
)DUMP";
EXPECT_EQ(expectation, dump);
@@ -444,6 +445,46 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, LegendPercentHeightQuirks) {
EXPECT_EQ(expectation, dump);
}
+// This test makes sure that the fieldset content handles fieldset padding
+// when the fieldset is expanded to encompass the legend.
+TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetPaddingWithLegend) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:none; margin:0; padding:10px; width: 150px; height: 100px;
+ }
+ #legend {
+ padding:0px; margin:0; width: 50px; height: 120px;
+ }
+ #child {
+ width: 100px; height: 40px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend"></legend>
+ <div id="child"></div>
+ </fieldset>
+ )HTML");
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext());
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:170x140
+ offset:10,0 size:50x120
+ offset:0,120 size:170x20
+ offset:10,10 size:100x40
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
TEST_F(NGFieldsetLayoutAlgorithmTest, MinMax) {
SetBodyInnerHTML(R"HTML(
<style>
@@ -483,31 +524,1455 @@ TEST_F(NGFieldsetLayoutAlgorithmTest, MinMax) {
</div>
)HTML");
- MinMaxSize size;
+ MinMaxSizes sizes;
+
+ sizes = RunComputeMinMaxSizes("fieldset1");
+ EXPECT_EQ(sizes.min_size, LayoutUnit(26));
+ EXPECT_EQ(sizes.max_size, LayoutUnit(26));
+
+ sizes = RunComputeMinMaxSizes("fieldset2");
+ EXPECT_EQ(sizes.min_size, LayoutUnit(102));
+ EXPECT_EQ(sizes.max_size, LayoutUnit(102));
+
+ sizes = RunComputeMinMaxSizes("fieldset3");
+ EXPECT_EQ(sizes.min_size, LayoutUnit(102));
+ EXPECT_EQ(sizes.max_size, LayoutUnit(126));
+
+ sizes = RunComputeMinMaxSizes("fieldset4");
+ EXPECT_EQ(sizes.min_size, LayoutUnit(152));
+ EXPECT_EQ(sizes.max_size, LayoutUnit(202));
+
+ sizes = RunComputeMinMaxSizes("fieldset5");
+ EXPECT_EQ(sizes.min_size, LayoutUnit(152));
+ EXPECT_EQ(sizes.max_size, LayoutUnit(176));
+
+ sizes = RunComputeMinMaxSizes("fieldset6");
+ EXPECT_EQ(sizes.min_size, LayoutUnit(76));
+ EXPECT_EQ(sizes.max_size, LayoutUnit(126));
+}
+
+// Tests that a fieldset won't fragment if it doesn't reach the fragmentation
+// line.
+TEST_F(NGFieldsetLayoutAlgorithmTest, NoFragmentation) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ fieldset {
+ border:3px solid; margin:0; padding:10px; width: 150px; height: 100px;
+ }
+ </style>
+ <fieldset id="fieldset"></fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(200);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ // We should only have one 176x126 fragment with no fragmentation.
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ EXPECT_EQ(PhysicalSize(176, 126), fragment->Size());
+ ASSERT_FALSE(fragment->BreakToken());
+}
+
+// Tests that a fieldset will fragment if it reaches the fragmentation line.
+TEST_F(NGFieldsetLayoutAlgorithmTest, SimpleFragmentation) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:3px solid; margin:0; padding:10px; width: 150px; height: 500px;
+ }
+ </style>
+ <fieldset id="fieldset"></fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(200);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ EXPECT_EQ(PhysicalSize(176, 200), fragment->Size());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ EXPECT_EQ(PhysicalSize(176, 200), fragment->Size());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ EXPECT_EQ(PhysicalSize(176, 126), fragment->Size());
+ ASSERT_FALSE(fragment->BreakToken());
+}
+
+// Tests that a fieldset with no content or padding will fragment if it reaches
+// the fragmentation line.
+TEST_F(NGFieldsetLayoutAlgorithmTest, FragmentationNoPadding) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset { margin:0; border:10px solid; padding:0px; width:100px; }
+ </style>
+ <fieldset id="fieldset"></fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(10);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:120x10
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:120x10
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Tests that a fieldset with auto height will fragment when its content reaches
+// the fragmentation line.
+TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetContentFragmentationAutoHeight) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:3px solid; margin:0; padding:10px; width: 150px;
+ }
+ #child {
+ margin:0; width: 50px; height: 500px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <div id="child"></div>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(200);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x200
+ offset:3,3 size:170x197
+ offset:10,10 size:50x187
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x200
+ offset:3,0 size:170x200
+ offset:10,0 size:50x200
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x126
+ offset:3,0 size:170x123
+ offset:10,0 size:50x113
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Tests that a fieldset with a set height will fragment when its content
+// reaches the fragmentation line.
+TEST_F(NGFieldsetLayoutAlgorithmTest, FieldsetContentFragmentation) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:3px solid; margin:0; padding:10px; width: 150px; height: 100px;
+ }
+ #child {
+ margin:0; width: 50px; height: 500px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <div id="child"></div>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(200);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x126
+ offset:3,3 size:170x120
+ offset:10,10 size:50x187
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x0
+ offset:3,0 size:170x0
+ offset:10,0 size:50x200
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x0
+ offset:3,0 size:170x0
+ offset:10,0 size:50x113
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Tests that a fieldset with auto height will fragment when its legend reaches
+// the fragmentation line.
+TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationAutoHeight) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:3px solid; margin:0; padding:10px; width: 150px;
+ }
+ #legend {
+ padding:0px; margin:0; width: 50px; height: 500px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend"></legend>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(200);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x200
+ offset:13,0 size:50x200
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x200
+ offset:13,0 size:50x200
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x123
+ offset:13,0 size:50x100
+ offset:3,100 size:170x20
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Tests that a fieldset with a set height will fragment when its legend
+// reaches the fragmentation line. The used height should also be extended to
+// encompass the legend.
+TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentation) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:3px solid; margin:0; padding:10px; width: 150px; height: 100px;
+ }
+ #legend {
+ padding:0px; margin:0; width: 50px; height: 500px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend"></legend>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(200);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x200
+ offset:13,0 size:50x200
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x200
+ offset:13,0 size:50x200
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x123
+ offset:13,0 size:50x100
+ offset:3,100 size:170x20
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Tests that a fieldset with auto height will fragment when its legend/content
+// reaches the fragmentation line.
+TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentationAutoHeight) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:3px solid; margin:0; padding:10px; width: 150px;
+ }
+ #legend {
+ padding:0px; margin:0; width: 50px; height: 500px;
+ }
+ #child {
+ margin:0; width: 100px; height: 200px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend"></legend>
+ <div id="child"></div>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(200);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x200
+ offset:13,0 size:50x200
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x200
+ offset:13,0 size:50x200
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x200
+ offset:13,0 size:50x100
+ offset:3,100 size:170x100
+ offset:10,10 size:100x90
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x123
+ offset:3,0 size:170x120
+ offset:10,0 size:100x110
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Tests that a fieldset with a set height will fragment when its legend/content
+// reaches the fragmentation line.
+TEST_F(NGFieldsetLayoutAlgorithmTest, LegendAndContentFragmentation) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:3px solid; margin:0; padding:10px; width: 150px; height: 100px;
+ }
+ #legend {
+ padding:0px; margin:0; width: 50px; height: 500px;
+ }
+ #child {
+ margin:0; width: 100px; height: 200px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend"></legend>
+ <div id="child"></div>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(200);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x200
+ offset:13,0 size:50x200
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x200
+ offset:13,0 size:50x200
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x123
+ offset:13,0 size:50x100
+ offset:3,100 size:170x20
+ offset:10,10 size:100x90
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:176x0
+ offset:3,0 size:170x0
+ offset:10,0 size:100x110
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Tests fragmentation when a legend's child content overflows.
+TEST_F(NGFieldsetLayoutAlgorithmTest, LegendFragmentationWithOverflow) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ fieldset, legend { margin:0; border:none; padding:0; }
+ </style>
+ <fieldset id="fieldset">
+ <legend style="height:30px;">
+ <div style="width:55px; height:150px;"></div>
+ </legend>
+ <div style="width:44px; height:150px;"></div>
+ </div>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(100);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x100
+ offset:0,0 size:55x30
+ offset:0,0 size:55x100
+ offset:0,30 size:1000x70
+ offset:0,0 size:44x70
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x80
+ offset:0,0 size:55x0
+ offset:0,0 size:55x50
+ offset:0,0 size:1000x80
+ offset:0,0 size:44x80
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Tests that fragmentation works as expected when the fieldset content has a
+// negative margin block start.
+TEST_F(NGFieldsetLayoutAlgorithmTest,
+ LegendAndContentFragmentationNegativeMargin) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:none; margin:0; padding:0px; width: 150px; height: 100px;
+ }
+ #legend {
+ padding:0px; margin:0; width: 50px; height: 100px;
+ }
+ #child {
+ margin-top: -20px; width: 100px; height: 40px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend"></legend>
+ <div id="child"></div>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(100);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:150x100
+ offset:0,0 size:50x100
+ offset:0,100 size:150x0
+ offset:0,-20 size:100x20
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:150x0
+ offset:0,0 size:150x0
+ offset:0,0 size:100x20
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, OverflowedLegend) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:none; margin:0; padding:0px; width: 100px; height: 100px;
+ }
+ #legend {
+ padding:0px; margin:0px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend" style="width:75%; height:60px;">
+ <div id="grandchild1" style="width:50px; height:120px;"></div>
+ <div id="grandchild2" style="width:40px; height:20px;"></div>
+ </legend>
+ <div id="child" style="width:85%; height:10px;"></div>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(100);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x100
+ offset:0,0 size:75x60
+ offset:0,0 size:50x100
+ offset:0,60 size:100x40
+ offset:0,0 size:85x10
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x0
+ offset:0,0 size:75x0
+ offset:0,0 size:50x20
+ offset:0,20 size:40x20
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, OverflowedFieldsetContent) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:none; margin:0; padding:0px; width: 100px; height: 100px;
+ }
+ #legend {
+ padding:0px; margin:0px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend" style="width:75%; height:10px;">
+ <div style="width:50px; height:220px;"></div>
+ </legend>
+ <div style="width:85%; height:10px;"></div>
+ <div id="child" style="width:65%; height:10px;">
+ <div style="width:51px; height:220px;"></div>
+ </div>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(100);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x100
+ offset:0,0 size:75x10
+ offset:0,0 size:50x100
+ offset:0,10 size:100x90
+ offset:0,0 size:85x10
+ offset:0,10 size:65x10
+ offset:0,0 size:51x80
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x0
+ offset:0,0 size:75x0
+ offset:0,0 size:50x100
+ offset:0,0 size:100x0
+ offset:0,0 size:65x0
+ offset:0,0 size:51x100
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x0
+ offset:0,0 size:75x0
+ offset:0,0 size:50x20
+ offset:0,0 size:100x0
+ offset:0,0 size:65x0
+ offset:0,0 size:51x40
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, BreakInsideAvoid) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:none; margin:0; padding:0px; width: 100px; height: 100px;
+ }
+ #legend {
+ padding:0px; margin:0px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend" style="width:10px; height:50px;"></legend>
+ <div style="break-inside:avoid; width:20px; height:70px;"></div>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(100);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x100
+ offset:0,0 size:10x50
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x0
+ offset:0,0 size:100x0
+ offset:0,0 size:20x70
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, BreakInsideAvoidTallBlock) {
+ // The block that has break-inside:avoid is too tall to fit in one
+ // fragmentainer. So a break is unavoidable. Let's check that:
+ // 1. The block is still shifted to the start of the next fragmentainer
+ // 2. We give up shifting it any further (would cause infinite an loop)
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:none; margin:0; padding:0px; width: 100px; height: 100px;
+ }
+ #legend {
+ padding:0px; margin:0px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend" style="width:10px; height:50px;"></legend>
+ <div style="break-inside:avoid; width:20px; height:170px;"></div>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(100);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x100
+ offset:0,0 size:10x50
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x0
+ offset:0,0 size:100x0
+ offset:0,0 size:20x100
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x0
+ offset:0,0 size:100x0
+ offset:0,0 size:20x70
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakInsideAvoid) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:none; margin:0; padding:0px; width: 100px; height: 50px;
+ }
+ #legend {
+ padding:0px; margin:0px;
+ }
+ </style>
+ <div id="container">
+ <div style="width:20px; height:50px;"></div>
+ <fieldset id="fieldset">
+ <legend id="legend" style="break-inside:avoid; width:10px; height:60px;">
+ </legend>
+ </fieldset>
+ </div>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(100);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("container")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x100
+ offset:0,0 size:20x50
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x60
+ offset:0,0 size:100x60
+ offset:0,0 size:10x60
+ offset:0,60 size:100x0
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, BreakBeforeAvoid) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:none; margin:0; padding:0px; width: 100px;
+ }
+ #legend {
+ padding:0px; margin:0px;
+ }
+ </style>
+ <div id="container">
+ <div style="width:20px; height:50px;"></div>
+ <fieldset id="fieldset">
+ <legend id="legend" style="width:10px; height:25px;"></legend>
+ <div style="width:30px; height:25px;"></div>
+ <div style="break-before:avoid; width:15px; height:25px;"></div>
+ </fieldset>
+ </div>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(100);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("container")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x75
+ offset:0,0 size:20x50
+ offset:0,50 size:100x25
+ offset:0,0 size:10x25
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x50
+ offset:0,0 size:100x50
+ offset:0,0 size:100x50
+ offset:0,0 size:30x25
+ offset:0,25 size:15x25
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakBeforeAvoid) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:10px solid; margin:0; padding:0px; width: 100px;
+ }
+ #legend {
+ padding:0px; margin:10px; width:10px; height:25px;
+ }
+ </style>
+ <div id="container">
+ <div style="width:20px; height:90px;"></div>
+ <fieldset id="fieldset">
+ <legend id="legend" style="break-before:avoid;"></legend>
+ </fieldset>
+ </div>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(100);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("container")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x100
+ offset:0,0 size:20x90
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x55
+ offset:0,0 size:120x55
+ offset:20,10 size:10x25
+ offset:10,45 size:100x0
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, BreakAfterAvoid) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:none; margin:0; padding:0px; width: 100px;
+ }
+ #legend {
+ padding:0px; margin:0px;
+ }
+ </style>
+ <div id="container">
+ <div style="width:20px; height:50px;"></div>
+ <fieldset id="fieldset">
+ <legend id="legend" style="width:10px; height:25px;"></legend>
+ <div style="break-after:avoid; width:30px; height:25px;"></div>
+ <div style="width:15px; height:25px;"></div>
+ </fieldset>
+ </div>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(100);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("container")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x75
+ offset:0,0 size:20x50
+ offset:0,50 size:100x25
+ offset:0,0 size:10x25
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x50
+ offset:0,0 size:100x50
+ offset:0,0 size:100x50
+ offset:0,0 size:30x25
+ offset:0,25 size:15x25
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, LegendBreakAfterAvoid) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:0px solid; margin:0; padding:0px; width: 100px;
+ }
+ #legend {
+ padding:0px; margin:0px; width:10px; height:50px;
+ }
+ </style>
+ <div id="container">
+ <div style="width:20px; height:50px;"></div>
+ <fieldset id="fieldset">
+ <legend id="legend" style="break-after:avoid;"></legend>
+ <div style="width:15px; height:25px;"></div>
+ </fieldset>
+ </div>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(100);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("container")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x100
+ offset:0,0 size:20x50
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:1000x75
+ offset:0,0 size:100x75
+ offset:0,0 size:10x50
+ offset:0,50 size:100x25
+ offset:0,0 size:15x25
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, MarginTopPastEndOfFragmentainer) {
+ // A block whose border box would start past the end of the current
+ // fragmentainer should start exactly at the start of the next fragmentainer,
+ // discarding what's left of the margin.
+ // https://www.w3.org/TR/css-break-3/#break-margins
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:none; margin:0; padding:0px; width: 100px; height: 100px;
+ }
+ #legend {
+ padding:0px; margin:0px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend" style="margin-top:60px; width:10px; height:20px;"></legend>
+ <div style="width:20px; height:20px;"></div>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(50);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x50
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x50
+ offset:0,0 size:10x20
+ offset:0,20 size:100x30
+ offset:0,0 size:20x20
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+TEST_F(NGFieldsetLayoutAlgorithmTest, MarginBottomPastEndOfFragmentainer) {
+ // A block whose border box would start past the end of the current
+ // fragmentainer should start exactly at the start of the next fragmentainer,
+ // discarding what's left of the margin.
+ // https://www.w3.org/TR/css-break-3/#break-margins
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset {
+ border:none; margin:0; padding:0px; width: 100px; height: 100px;
+ }
+ #legend {
+ padding:0px; margin:0px;
+ }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend" style="margin-bottom:20px; height:90px;"></legend>
+ <div style="width:20px; height:20px;"></div>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(100);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x100
+ offset:0,0 size:0x90
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_FALSE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:100x0
+ offset:0,0 size:100x0
+ offset:0,0 size:20x20
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Tests that a fieldset with a large border and a small legend fragment
+// correctly. In this case, the legend block offset is not adjusted because the
+// legend is broken across multiple fragments.
+TEST_F(NGFieldsetLayoutAlgorithmTest, SmallLegendLargeBorderFragmentation) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset { margin:0; border:60px solid; padding:0px; width:100px;
+ height:10px; }
+ #legend { padding:0; width:10px; height:50px; }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend"></legend>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(40);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:220x40
+ offset:60,0 size:10x40
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:220x40
+ offset:60,0 size:10x10
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:220x40
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ // TODO(almaher): There should be no break token here. In this case the bottom
+ // border never reduces in size, causing fragmentation to continue infinitely.
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:220x10
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Tests that a fieldset with a large border and a small legend fragment
+// correctly. In this case, the legend block offset is adjusted because the
+// legend fits inside the first fragment.
+TEST_F(NGFieldsetLayoutAlgorithmTest, SmallerLegendLargeBorderFragmentation) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset { margin:0; border:60px solid; padding:0px; width:100px;
+ height:10px; }
+ #legend { padding:0; width:10px; height:5px; }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend"></legend>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(40);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:220x40
+ offset:60,27.5 size:10x5
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:220x40
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:220x40
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ // TODO(almaher): There should be no break token here. In this case the bottom
+ // border never reduces in size, causing fragmentation to continue infinitely.
+ ASSERT_TRUE(fragment->BreakToken());
+
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:220x10
+)DUMP";
+ EXPECT_EQ(expectation, dump);
+}
+
+// Tests that a fieldset with a large border and a small legend fragment
+// correctly. In this case, the legend block offset is not adjusted because the
+// legend breaks after attempting to adjust the offset.
+TEST_F(NGFieldsetLayoutAlgorithmTest, SmallerLegendLargeBorderWithBreak) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #fieldset { margin:0; border:60px solid; padding:0px; width:100px;
+ height:10px; }
+ #legend { padding:0; width:10px; height:5px; margin-top:16px; }
+ </style>
+ <fieldset id="fieldset">
+ <legend id="legend"></legend>
+ </fieldset>
+ )HTML");
+
+ LayoutUnit kFragmentainerSpaceAvailable(40);
+
+ NGBlockNode node(ToLayoutBox(GetLayoutObjectByElementId("fieldset")));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize), false,
+ node.CreatesNewFormattingContext(), kFragmentainerSpaceAvailable);
+
+ scoped_refptr<const NGPhysicalBoxFragment> fragment =
+ NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(node, space);
+ ASSERT_TRUE(fragment->BreakToken());
+
+ String dump = DumpFragmentTree(fragment.get());
+ String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:220x40
+ offset:60,16 size:10x5
+)DUMP";
+ EXPECT_EQ(expectation, dump);
- size = RunComputeMinAndMax("fieldset1");
- EXPECT_EQ(size.min_size, LayoutUnit(26));
- EXPECT_EQ(size.max_size, LayoutUnit(26));
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
- size = RunComputeMinAndMax("fieldset2");
- EXPECT_EQ(size.min_size, LayoutUnit(102));
- EXPECT_EQ(size.max_size, LayoutUnit(102));
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:220x40
+)DUMP";
+ EXPECT_EQ(expectation, dump);
- size = RunComputeMinAndMax("fieldset3");
- EXPECT_EQ(size.min_size, LayoutUnit(102));
- EXPECT_EQ(size.max_size, LayoutUnit(126));
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ ASSERT_TRUE(fragment->BreakToken());
- size = RunComputeMinAndMax("fieldset4");
- EXPECT_EQ(size.min_size, LayoutUnit(152));
- EXPECT_EQ(size.max_size, LayoutUnit(202));
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:220x40
+)DUMP";
+ EXPECT_EQ(expectation, dump);
- size = RunComputeMinAndMax("fieldset5");
- EXPECT_EQ(size.min_size, LayoutUnit(152));
- EXPECT_EQ(size.max_size, LayoutUnit(176));
+ fragment = NGBaseLayoutAlgorithmTest::RunFieldsetLayoutAlgorithm(
+ node, space, fragment->BreakToken());
+ // TODO(almaher): There should be no break token here. In this case the bottom
+ // border never reduces in size, causing fragmentation to continue infinitely.
+ ASSERT_TRUE(fragment->BreakToken());
- size = RunComputeMinAndMax("fieldset6");
- EXPECT_EQ(size.min_size, LayoutUnit(76));
- EXPECT_EQ(size.max_size, LayoutUnit(126));
+ dump = DumpFragmentTree(fragment.get());
+ expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+ offset:unplaced size:220x10
+)DUMP";
+ EXPECT_EQ(expectation, dump);
}
} // anonymous namespace
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_child_iterator.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_child_iterator.cc
new file mode 100644
index 00000000000..350d605af11
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_child_iterator.cc
@@ -0,0 +1,38 @@
+// Copyright 2019 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/ng/ng_flex_child_iterator.h"
+
+namespace blink {
+
+NGFlexChildIterator::NGFlexChildIterator(const NGBlockNode node) {
+ bool is_deprecated_webkit_box = node.Style().IsDeprecatedWebkitBox();
+ int initial_order = is_deprecated_webkit_box
+ ? ComputedStyleInitialValues::InitialBoxOrdinalGroup()
+ : ComputedStyleInitialValues::InitialOrder();
+ bool needs_sort = false;
+
+ // Collect all our children, and order them by either their
+ // -webkit-box-ordinal-group/order property.
+ for (NGLayoutInputNode child = node.FirstChild(); child;
+ child = child.NextSibling()) {
+ int order = is_deprecated_webkit_box ? child.Style().BoxOrdinalGroup()
+ : child.Style().Order();
+ needs_sort |= order != initial_order;
+ children_.emplace_back(To<NGBlockNode>(child), order);
+ }
+
+ // We only need to sort this vector if we encountered a non-initial
+ // -webkit-box-ordinal-group/order property.
+ if (needs_sort) {
+ std::stable_sort(children_.begin(), children_.end(),
+ [](const ChildWithOrder& c1, const ChildWithOrder& c2) {
+ return c1.order < c2.order;
+ });
+ }
+
+ iterator_ = children_.begin();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_child_iterator.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_child_iterator.h
new file mode 100644
index 00000000000..609483fc790
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_child_iterator.h
@@ -0,0 +1,53 @@
+// Copyright 2019 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FLEX_CHILD_ITERATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FLEX_CHILD_ITERATOR_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+// A utility class for flex layout which given the current node will iterate
+// through its children.
+//
+// TODO(layout-dev): Once flex layout supports NG-fragmentation this will need
+// to be updated to accept a break-token.
+//
+// This class does not handle modifications to its arguments after it has been
+// constructed.
+class CORE_EXPORT NGFlexChildIterator {
+ STACK_ALLOCATED();
+
+ public:
+ NGFlexChildIterator(const NGBlockNode node);
+
+ // Returns the next block node which should be laid out.
+ NGBlockNode NextChild() {
+ if (iterator_ == children_.end())
+ return nullptr;
+
+ return (*iterator_++).child;
+ }
+
+ struct ChildWithOrder {
+ DISALLOW_NEW();
+ ChildWithOrder(NGBlockNode child, int order) : child(child), order(order) {}
+ NGBlockNode child;
+ int order;
+ };
+
+ private:
+ Vector<ChildWithOrder, 4> children_;
+ Vector<ChildWithOrder, 4>::const_iterator iterator_;
+};
+
+} // namespace blink
+
+WTF_ALLOW_MOVE_AND_INIT_WITH_MEM_FUNCTIONS(
+ blink::NGFlexChildIterator::ChildWithOrder)
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FLEX_CHILD_ITERATOR_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
index 9bbdcdbedba..21c01f8a5be 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc
@@ -9,12 +9,16 @@
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_flex_child_iterator.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_space_utils.h"
+#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
@@ -27,10 +31,18 @@ NGFlexLayoutAlgorithm::NGFlexLayoutAlgorithm(
border_scrollbar_padding_(border_padding_ +
params.fragment_geometry.scrollbar),
is_column_(Style().ResolvedIsColumnFlexDirection()),
- is_horizontal_flow_(FlexLayoutAlgorithm::IsHorizontalFlow(Style())) {
+ is_horizontal_flow_(FlexLayoutAlgorithm::IsHorizontalFlow(Style())),
+ is_cross_size_definite_(IsContainerCrossSizeDefinite()) {
container_builder_.SetIsNewFormattingContext(
params.space.IsNewFormattingContext());
container_builder_.SetInitialFragmentGeometry(params.fragment_geometry);
+
+ border_box_size_ = container_builder_.InitialBorderBoxSize();
+ content_box_size_ =
+ ShrinkAvailableSize(border_box_size_, border_scrollbar_padding_);
+ child_percentage_size_ = CalculateChildPercentageSize(
+ ConstraintSpace(), Node(), content_box_size_);
+ algorithm_.emplace(&Style(), MainAxisContentExtent(LayoutUnit::Max()));
}
bool NGFlexLayoutAlgorithm::MainAxisIsInlineAxis(
@@ -40,26 +52,101 @@ bool NGFlexLayoutAlgorithm::MainAxisIsInlineAxis(
}
LayoutUnit NGFlexLayoutAlgorithm::MainAxisContentExtent(
- LayoutUnit sum_hypothetical_main_size) {
+ LayoutUnit sum_hypothetical_main_size) const {
if (Style().ResolvedIsColumnFlexDirection()) {
return ComputeBlockSizeForFragment(
ConstraintSpace(), Style(), border_padding_,
- sum_hypothetical_main_size + (border_padding_).BlockSum()) -
+ sum_hypothetical_main_size +
+ border_scrollbar_padding_.BlockSum()) -
border_scrollbar_padding_.BlockSum();
}
return content_box_size_.inline_size;
}
+namespace {
+
+enum AxisEdge { kStart, kCenter, kEnd };
+
+// Maps the resolved justify-content value to a static-position edge.
+AxisEdge MainAxisStaticPositionEdge(const ComputedStyle& style,
+ bool is_column) {
+ const StyleContentAlignmentData justify =
+ FlexLayoutAlgorithm::ResolvedJustifyContent(style);
+ const ContentPosition content_position = justify.GetPosition();
+ bool is_reverse_flex = is_column
+ ? style.ResolvedIsColumnReverseFlexDirection()
+ : style.ResolvedIsRowReverseFlexDirection();
+
+ if (content_position == ContentPosition::kFlexEnd)
+ return is_reverse_flex ? AxisEdge::kStart : AxisEdge::kEnd;
+
+ if (content_position == ContentPosition::kCenter ||
+ justify.Distribution() == ContentDistributionType::kSpaceAround ||
+ justify.Distribution() == ContentDistributionType::kSpaceEvenly)
+ return AxisEdge::kCenter;
+
+ return is_reverse_flex ? AxisEdge::kEnd : AxisEdge::kStart;
+}
+
+// Maps the resolved alignment value to a static-position edge.
+AxisEdge CrossAxisStaticPositionEdge(const ComputedStyle& style,
+ const ComputedStyle& child_style) {
+ ItemPosition alignment =
+ FlexLayoutAlgorithm::AlignmentForChild(style, child_style);
+ bool is_wrap_reverse = style.FlexWrap() == EFlexWrap::kWrapReverse;
+
+ if (alignment == ItemPosition::kFlexEnd)
+ return is_wrap_reverse ? AxisEdge::kStart : AxisEdge::kEnd;
+
+ if (alignment == ItemPosition::kCenter)
+ return AxisEdge::kCenter;
+
+ return is_wrap_reverse ? AxisEdge::kEnd : AxisEdge::kStart;
+}
+
+} // namespace
+
void NGFlexLayoutAlgorithm::HandleOutOfFlowPositioned(NGBlockNode child) {
- // TODO(dgrogan): There's stuff from
- // https://www.w3.org/TR/css-flexbox-1/#abspos-items that isn't done here.
- // Specifically, neither rtl nor alignment is handled here, at least.
- // Look at LayoutFlexibleBox::PrepareChildForPositionedLayout and
- // SetStaticPositionForPositionedLayout to see how to statically position
- // this.
- container_builder_.AddOutOfFlowChildCandidate(
- child, {border_scrollbar_padding_.inline_start,
- border_scrollbar_padding_.block_start});
+ AxisEdge main_axis_edge = MainAxisStaticPositionEdge(Style(), is_column_);
+ AxisEdge cross_axis_edge =
+ CrossAxisStaticPositionEdge(Style(), child.Style());
+
+ AxisEdge inline_axis_edge = is_column_ ? cross_axis_edge : main_axis_edge;
+ AxisEdge block_axis_edge = is_column_ ? main_axis_edge : cross_axis_edge;
+
+ using InlineEdge = NGLogicalStaticPosition::InlineEdge;
+ using BlockEdge = NGLogicalStaticPosition::BlockEdge;
+
+ InlineEdge inline_edge;
+ BlockEdge block_edge;
+ LogicalOffset offset(border_scrollbar_padding_.inline_start,
+ border_scrollbar_padding_.block_start);
+
+ // Determine the static-position based off the axis-edge.
+ if (inline_axis_edge == AxisEdge::kStart) {
+ inline_edge = InlineEdge::kInlineStart;
+ } else if (inline_axis_edge == AxisEdge::kCenter) {
+ inline_edge = InlineEdge::kInlineCenter;
+ offset.inline_offset += content_box_size_.inline_size / 2;
+ } else {
+ inline_edge = InlineEdge::kInlineEnd;
+ offset.inline_offset += content_box_size_.inline_size;
+ }
+
+ // We may not know the final block-size of the fragment yet. This will be
+ // adjusted within the |NGContainerFragmentBuilder| once set.
+ if (block_axis_edge == AxisEdge::kStart) {
+ block_edge = BlockEdge::kBlockStart;
+ } else if (block_axis_edge == AxisEdge::kCenter) {
+ block_edge = BlockEdge::kBlockCenter;
+ offset.block_offset -= border_scrollbar_padding_.BlockSum() / 2;
+ } else {
+ block_edge = BlockEdge::kBlockEnd;
+ offset.block_offset -= border_scrollbar_padding_.BlockSum();
+ }
+
+ container_builder_.AddOutOfFlowChildCandidate(child, offset, inline_edge,
+ block_edge);
}
bool NGFlexLayoutAlgorithm::IsColumnContainerMainSizeDefinite() const {
@@ -110,13 +197,27 @@ bool NGFlexLayoutAlgorithm::DoesItemStretch(const NGBlockNode& child) const {
ItemPosition::kStretch;
}
+bool NGFlexLayoutAlgorithm::IsItemFlexBasisDefinite(
+ const NGBlockNode& child) const {
+ const Length& flex_basis = child.Style().FlexBasis();
+ DCHECK(!flex_basis.IsAuto())
+ << "This is never called with flex_basis.IsAuto, but it'd be trivial to "
+ "support.";
+ if (!is_column_)
+ return true;
+ return !BlockLengthUnresolvable(BuildSpaceForFlexBasis(child), flex_basis,
+ LengthResolvePhase::kLayout);
+}
+
// This behavior is under discussion: the item's pre-flexing main size
// definiteness may no longer imply post-flexing definiteness.
// TODO(dgrogan): Have https://crbug.com/1003506 and
// https://github.com/w3c/csswg-drafts/issues/4305 been resolved yet?
bool NGFlexLayoutAlgorithm::IsItemMainSizeDefinite(
const NGBlockNode& child) const {
- DCHECK(is_column_);
+ DCHECK(is_column_)
+ << "This method doesn't work with row flexboxes because we assume "
+ "main size is block size when we call BlockLengthUnresolvable.";
// Inline sizes are always definite.
// TODO(dgrogan): The relevant tests, the last two cases in
// css/css-flexbox/percentage-heights-003.html passed even without this, so it
@@ -126,9 +227,8 @@ bool NGFlexLayoutAlgorithm::IsItemMainSizeDefinite(
// We need a constraint space for the child to determine resolvability and the
// space for flex-basis is sufficient, even though it has some unnecessary
// stuff (ShrinkToFit and fixed cross sizes).
- NGConstraintSpace child_space =
- BuildConstraintSpaceForDeterminingFlexBasis(child);
- return !BlockLengthUnresolvable(child_space, child.Style().LogicalHeight(),
+ return !BlockLengthUnresolvable(BuildSpaceForFlexBasis(child),
+ child.Style().LogicalHeight(),
LengthResolvePhase::kLayout);
}
@@ -143,9 +243,8 @@ bool NGFlexLayoutAlgorithm::IsItemCrossAxisLengthDefinite(
if (!MainAxisIsInlineAxis(child))
return true;
// If we get here, cross axis is block axis.
- return !BlockLengthUnresolvable(
- BuildConstraintSpaceForDeterminingFlexBasis(child), length,
- LengthResolvePhase::kLayout);
+ return !BlockLengthUnresolvable(BuildSpaceForFlexBasis(child), length,
+ LengthResolvePhase::kLayout);
}
bool NGFlexLayoutAlgorithm::DoesItemCrossSizeComputeToAuto(
@@ -197,139 +296,157 @@ bool NGFlexLayoutAlgorithm::ShouldItemShrinkToFit(
bool NGFlexLayoutAlgorithm::WillChildCrossSizeBeContainerCrossSize(
const NGBlockNode& child) const {
- return !algorithm_->IsMultiline() && IsContainerCrossSizeDefinite() &&
+ return !algorithm_->IsMultiline() && is_cross_size_definite_ &&
DoesItemStretch(child);
}
-NGConstraintSpace
-NGFlexLayoutAlgorithm::BuildConstraintSpaceForDeterminingFlexBasis(
- const NGBlockNode& flex_item) const {
+double NGFlexLayoutAlgorithm::GetMainOverCrossAspectRatio(
+ const NGBlockNode& child) const {
+ DCHECK(child.HasAspectRatio());
+ LogicalSize aspect_ratio = child.GetAspectRatio();
+
+ DCHECK_GT(aspect_ratio.inline_size, 0);
+ DCHECK_GT(aspect_ratio.block_size, 0);
+
+ double ratio =
+ aspect_ratio.inline_size.ToDouble() / aspect_ratio.block_size.ToDouble();
+ // Multiplying by ratio will take something in the item's block axis and
+ // convert it to the inline axis. We want to convert from cross size to main
+ // size. If block axis and cross axis are the same, then we already have what
+ // we need. Otherwise we need to use the reciprocal.
+ if (!MainAxisIsInlineAxis(child))
+ ratio = 1 / ratio;
+ return ratio;
+}
+
+namespace {
+
+LayoutUnit CalculateFixedCrossSize(LayoutUnit available_size,
+ const MinMaxSizes& cross_axis_min_max,
+ LayoutUnit margin_sum) {
+ return cross_axis_min_max.ClampSizeToMinAndMax(available_size - margin_sum);
+}
+
+} // namespace
+
+NGConstraintSpace NGFlexLayoutAlgorithm::BuildSpaceForIntrinsicBlockSize(
+ const NGBlockNode& flex_item,
+ const NGPhysicalBoxStrut& physical_margins,
+ const MinMaxSizes& cross_axis_min_max) const {
const ComputedStyle& child_style = flex_item.Style();
NGConstraintSpaceBuilder space_builder(ConstraintSpace(),
child_style.GetWritingMode(),
/* is_new_fc */ true);
SetOrthogonalFallbackInlineSizeIfNeeded(Style(), flex_item, &space_builder);
+ space_builder.SetCacheSlot(NGCacheSlot::kMeasure);
+ space_builder.SetIsPaintedAtomically(true);
- if (ShouldItemShrinkToFit(flex_item))
+ NGBoxStrut margins = physical_margins.ConvertToLogical(
+ ConstraintSpace().GetWritingMode(), Style().Direction());
+ LogicalSize child_available_size = content_box_size_;
+ if (ShouldItemShrinkToFit(flex_item)) {
space_builder.SetIsShrinkToFit(true);
- if (WillChildCrossSizeBeContainerCrossSize(flex_item)) {
+ } else if (WillChildCrossSizeBeContainerCrossSize(flex_item)) {
if (is_column_) {
space_builder.SetIsFixedInlineSize(true);
+ child_available_size.inline_size =
+ CalculateFixedCrossSize(child_available_size.inline_size,
+ cross_axis_min_max, margins.InlineSum());
} else {
space_builder.SetIsFixedBlockSize(true);
DCHECK_NE(content_box_size_.block_size, kIndefiniteSize);
+ child_available_size.block_size =
+ CalculateFixedCrossSize(child_available_size.block_size,
+ cross_axis_min_max, margins.BlockSum());
}
}
+ space_builder.SetNeedsBaseline(
+ ConstraintSpace().NeedsBaseline() ||
+ FlexLayoutAlgorithm::AlignmentForChild(Style(), child_style) ==
+ ItemPosition::kBaseline);
+
+ // For determining the intrinsic block-size we make %-block-sizes resolve
+ // against an indefinite size.
+ LogicalSize child_percentage_size = child_percentage_size_;
+ if (is_column_)
+ child_percentage_size.block_size = kIndefiniteSize;
+
+ space_builder.SetAvailableSize(child_available_size);
+ space_builder.SetPercentageResolutionSize(child_percentage_size);
+ // TODO(dgrogan): The SetReplacedPercentageResolutionSize calls in this file
+ // may be untested. Write a test or determine why they're unnecessary.
+ space_builder.SetReplacedPercentageResolutionSize(child_percentage_size);
+ space_builder.SetTextDirection(child_style.Direction());
+ return space_builder.ToConstraintSpace();
+}
+
+NGConstraintSpace NGFlexLayoutAlgorithm::BuildSpaceForFlexBasis(
+ const NGBlockNode& flex_item) const {
+ NGConstraintSpaceBuilder space_builder(ConstraintSpace(),
+ flex_item.Style().GetWritingMode(),
+ /* is_new_fc */ true);
+ SetOrthogonalFallbackInlineSizeIfNeeded(Style(), flex_item, &space_builder);
+
+ // This space is only used for resolving lengths, not for layout. We only
+ // need the available and percentage sizes.
space_builder.SetAvailableSize(content_box_size_);
space_builder.SetPercentageResolutionSize(child_percentage_size_);
- space_builder.SetTextDirection(child_style.Direction());
+ space_builder.SetReplacedPercentageResolutionSize(child_percentage_size_);
return space_builder.ToConstraintSpace();
}
void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
- for (NGLayoutInputNode generic_child = Node().FirstChild(); generic_child;
- generic_child = generic_child.NextSibling()) {
- auto child = To<NGBlockNode>(generic_child);
+ NGFlexChildIterator iterator(Node());
+ for (NGBlockNode child = iterator.NextChild(); child;
+ child = iterator.NextChild()) {
if (child.IsOutOfFlowPositioned()) {
HandleOutOfFlowPositioned(child);
continue;
}
const ComputedStyle& child_style = child.Style();
- NGConstraintSpace child_space =
- BuildConstraintSpaceForDeterminingFlexBasis(child);
+ NGConstraintSpace flex_basis_space = BuildSpaceForFlexBasis(child);
+
+ NGPhysicalBoxStrut physical_child_margins =
+ ComputePhysicalMargins(flex_basis_space, child_style);
NGBoxStrut border_padding_in_child_writing_mode =
- ComputeBorders(child_space, child) +
- ComputePadding(child_space, child_style);
- NGBoxStrut border_scrollbar_padding_in_child_writing_mode =
- border_padding_in_child_writing_mode +
- ComputeScrollbars(child_space, child);
+ ComputeBorders(flex_basis_space, child_style) +
+ ComputePadding(flex_basis_space, child_style);
NGPhysicalBoxStrut physical_border_padding(
border_padding_in_child_writing_mode.ConvertToPhysical(
child_style.GetWritingMode(), child_style.Direction()));
- NGPhysicalBoxStrut physical_border_scrollbar_padding(
- border_scrollbar_padding_in_child_writing_mode.ConvertToPhysical(
- child_style.GetWritingMode(), child_style.Direction()));
LayoutUnit main_axis_border_padding =
is_horizontal_flow_ ? physical_border_padding.HorizontalSum()
: physical_border_padding.VerticalSum();
- LayoutUnit main_axis_border_scrollbar_padding =
- is_horizontal_flow_ ? physical_border_scrollbar_padding.HorizontalSum()
- : physical_border_scrollbar_padding.VerticalSum();
-
- // We want the child's min/max size in its writing mode, not ours. We'll
- // only ever use it if the child's inline axis is our main axis.
- MinMaxSizeInput input(
- /* percentage_resolution_block_size */ content_box_size_.block_size);
- MinMaxSize intrinsic_sizes_border_box = child.ComputeMinMaxSize(
- child_style.GetWritingMode(), input, &child_space);
- // TODO(dgrogan): Don't layout every time, just when you need to.
- // Use ChildHasIntrinsicMainAxisSize as a guide.
- scoped_refptr<const NGLayoutResult> layout_result =
- child.Layout(child_space, nullptr /*break token*/);
- NGFragment fragment_in_child_writing_mode(
- child_style.GetWritingMode(), layout_result->PhysicalFragment());
-
- LayoutUnit flex_base_border_box;
- const Length& specified_length_in_main_axis =
- is_horizontal_flow_ ? child_style.Width() : child_style.Height();
- const Length& flex_basis = child_style.FlexBasis();
- // TODO(dgrogan): Generalize IsAuto: See the <'width'> section of
- // https://drafts.csswg.org/css-flexbox/#valdef-flex-flex-basis
- // and https://drafts.csswg.org/css-flexbox/#flex-basis-property, which says
- // that if a flex-basis value would resolve to auto (but not literally auto)
- // we should interpret it as flex-basis:content.
- if (flex_basis.IsAuto() && specified_length_in_main_axis.IsAuto()) {
- if (MainAxisIsInlineAxis(child))
- flex_base_border_box = intrinsic_sizes_border_box.max_size;
- else
- flex_base_border_box = fragment_in_child_writing_mode.BlockSize();
- } else {
- // TODO(dgrogan): Check for definiteness.
- // This block covers case A in
- // https://drafts.csswg.org/css-flexbox/#algo-main-item.
- const Length& length_to_resolve =
- flex_basis.IsAuto() ? specified_length_in_main_axis : flex_basis;
- DCHECK(!length_to_resolve.IsAuto());
-
- if (MainAxisIsInlineAxis(child)) {
- flex_base_border_box = ResolveMainInlineLength(
- child_space, child_style, border_padding_in_child_writing_mode,
- intrinsic_sizes_border_box, length_to_resolve);
- } else {
- // Flex container's main axis is in child's block direction. Child's
- // flex basis is in child's block direction.
- flex_base_border_box = ResolveMainBlockLength(
- child_space, child_style, border_padding_in_child_writing_mode,
- length_to_resolve, fragment_in_child_writing_mode.BlockSize(),
- LengthResolvePhase::kLayout);
+ LayoutUnit cross_axis_border_padding =
+ is_horizontal_flow_ ? physical_border_padding.VerticalSum()
+ : physical_border_padding.HorizontalSum();
+
+ base::Optional<MinMaxSizes> min_max_size;
+ auto MinMaxSizesFunc = [&]() -> MinMaxSizes {
+ if (!min_max_size) {
+ if (child.Style().OverflowBlockDirection() == EOverflow::kAuto) {
+ // Ensure this child has been laid out so its auto scrollbars are
+ // included in its intrinsic sizes.
+ child.Layout(flex_basis_space);
+ }
+ // We want the child's min/max size in its writing mode, not ours.
+ // We'll only ever use it if the child's inline axis is our main axis.
+ min_max_size = child.ComputeMinMaxSizes(
+ child_style.GetWritingMode(),
+ MinMaxSizesInput(content_box_size_.block_size), &flex_basis_space);
}
- }
+ return *min_max_size;
+ };
- // Spec calls this "flex base size"
- // https://www.w3.org/TR/css-flexbox-1/#algo-main-item
- // Blink's FlexibleBoxAlgorithm expects it to be content + scrollbar widths,
- // but no padding or border.
- LayoutUnit flex_base_content_size =
- flex_base_border_box - main_axis_border_padding;
-
- NGPhysicalBoxStrut physical_child_margins =
- ComputePhysicalMargins(child_space, child_style);
- // Set margin because FlexibleBoxAlgorithm reads it from legacy.
- child.GetLayoutBox()->SetMargin(physical_child_margins);
-
- LayoutUnit main_axis_margin = is_horizontal_flow_
- ? physical_child_margins.HorizontalSum()
- : physical_child_margins.VerticalSum();
-
- MinMaxSize min_max_sizes_in_main_axis_direction{LayoutUnit(),
- LayoutUnit::Max()};
- MinMaxSize min_max_sizes_in_cross_axis_direction{LayoutUnit(),
+ MinMaxSizes min_max_sizes_in_main_axis_direction{main_axis_border_padding,
LayoutUnit::Max()};
+ MinMaxSizes min_max_sizes_in_cross_axis_direction{LayoutUnit(),
+ LayoutUnit::Max()};
const Length& max_property_in_main_axis = is_horizontal_flow_
? child.Style().MaxWidth()
: child.Style().MaxHeight();
@@ -341,112 +458,282 @@ void NGFlexLayoutAlgorithm::ConstructAndAppendFlexItems() {
: child.Style().MinWidth();
if (MainAxisIsInlineAxis(child)) {
min_max_sizes_in_main_axis_direction.max_size = ResolveMaxInlineLength(
- child_space, child_style, border_padding_in_child_writing_mode,
- intrinsic_sizes_border_box, max_property_in_main_axis,
+ flex_basis_space, child_style, border_padding_in_child_writing_mode,
+ MinMaxSizesFunc, max_property_in_main_axis,
LengthResolvePhase::kLayout);
- min_max_sizes_in_cross_axis_direction.max_size =
- ResolveMaxBlockLength(child_space, child_style,
- border_scrollbar_padding_in_child_writing_mode,
- max_property_in_cross_axis,
- fragment_in_child_writing_mode.BlockSize(),
- LengthResolvePhase::kLayout);
- min_max_sizes_in_cross_axis_direction.min_size =
- ResolveMinBlockLength(child_space, child_style,
- border_scrollbar_padding_in_child_writing_mode,
- min_property_in_cross_axis,
- fragment_in_child_writing_mode.BlockSize(),
- LengthResolvePhase::kLayout);
+ min_max_sizes_in_cross_axis_direction.max_size = ResolveMaxBlockLength(
+ flex_basis_space, child_style, border_padding_in_child_writing_mode,
+ max_property_in_cross_axis, LengthResolvePhase::kLayout);
+ min_max_sizes_in_cross_axis_direction.min_size = ResolveMinBlockLength(
+ flex_basis_space, child_style, border_padding_in_child_writing_mode,
+ min_property_in_cross_axis, LengthResolvePhase::kLayout);
} else {
min_max_sizes_in_main_axis_direction.max_size = ResolveMaxBlockLength(
- child_space, child_style, border_padding_in_child_writing_mode,
- max_property_in_main_axis, fragment_in_child_writing_mode.BlockSize(),
- LengthResolvePhase::kLayout);
+ flex_basis_space, child_style, border_padding_in_child_writing_mode,
+ max_property_in_main_axis, LengthResolvePhase::kLayout);
min_max_sizes_in_cross_axis_direction.max_size = ResolveMaxInlineLength(
- child_space, child_style,
- border_scrollbar_padding_in_child_writing_mode,
- intrinsic_sizes_border_box, max_property_in_cross_axis,
+ flex_basis_space, child_style, border_padding_in_child_writing_mode,
+ MinMaxSizesFunc, max_property_in_cross_axis,
LengthResolvePhase::kLayout);
min_max_sizes_in_cross_axis_direction.min_size = ResolveMinInlineLength(
- child_space, child_style,
- border_scrollbar_padding_in_child_writing_mode,
- intrinsic_sizes_border_box, min_property_in_cross_axis,
+ flex_basis_space, child_style, border_padding_in_child_writing_mode,
+ MinMaxSizesFunc, min_property_in_cross_axis,
LengthResolvePhase::kLayout);
}
+ base::Optional<LayoutUnit> intrinsic_block_size;
+ auto IntrinsicBlockSizeFunc = [&]() -> LayoutUnit {
+ if (!intrinsic_block_size) {
+ NGConstraintSpace child_space = BuildSpaceForIntrinsicBlockSize(
+ child, physical_child_margins,
+ min_max_sizes_in_cross_axis_direction);
+ scoped_refptr<const NGLayoutResult> layout_result =
+ child.Layout(child_space, /* break_token */ nullptr);
+ intrinsic_block_size = layout_result->IntrinsicBlockSize();
+ }
+ return *intrinsic_block_size;
+ };
+
+ // The logic that calculates flex_base_border_box assumes that the used
+ // value of the flex-basis property is either definite or 'content'.
+ LayoutUnit flex_base_border_box;
+ const Length& specified_length_in_main_axis =
+ is_horizontal_flow_ ? child_style.Width() : child_style.Height();
+ const Length& flex_basis = child_style.FlexBasis();
+ Length length_to_resolve = Length::Auto();
+ if (flex_basis.IsAuto()) {
+ if (!is_column_ || IsItemMainSizeDefinite(child))
+ length_to_resolve = specified_length_in_main_axis;
+ } else if (IsItemFlexBasisDefinite(child)) {
+ length_to_resolve = flex_basis;
+ }
+
+ if (length_to_resolve.IsAuto()) {
+ // This block means that the used flex-basis is 'content'. In here we
+ // implement parts B,C,D,E of 9.2.3
+ // https://drafts.csswg.org/css-flexbox/#algo-main-item
+ const Length& cross_axis_length =
+ is_horizontal_flow_ ? child.Style().Height() : child.Style().Width();
+ if (child.HasAspectRatio() &&
+ (IsItemCrossAxisLengthDefinite(child, cross_axis_length))) {
+ // This is Part B of 9.2.3
+ // https://drafts.csswg.org/css-flexbox/#algo-main-item It requires that
+ // the item has a definite cross size.
+ //
+ // But for determining the flex-basis of aspect ratio items, both legacy
+ // and FF both ignore part of the flex spec that has a more lenient
+ // definition of definite.
+ // https://drafts.csswg.org/css-flexbox/#definite says "If a single-line
+ // flex container has a definite cross size, the outer cross size of any
+ // stretched flex items is the flex container's inner cross size
+ // (clamped to the flex item's min and max cross size) and is considered
+ // definite". But when this happens, neither legacy nor firefox use the
+ // container's cross size to calculate the item's main size, they just
+ // fall to block E. E.g. Legacy and FF show a 16x100 green square
+ // instead of a 100x100 green square for
+ // https://jsfiddle.net/dgrogan/djh5wu0x/1/. I think it should be
+ // 100x100.
+ LayoutUnit cross_size;
+ if (MainAxisIsInlineAxis(child)) {
+ cross_size = ResolveMainBlockLength(
+ flex_basis_space, child_style,
+ border_padding_in_child_writing_mode, cross_axis_length,
+ kIndefiniteSize, LengthResolvePhase::kLayout);
+ } else {
+ cross_size =
+ ResolveMainInlineLength(flex_basis_space, child_style,
+ border_padding_in_child_writing_mode,
+ MinMaxSizesFunc, cross_axis_length);
+ }
+ cross_size = min_max_sizes_in_cross_axis_direction.ClampSizeToMinAndMax(
+ cross_size);
+ flex_base_border_box =
+ LayoutUnit(cross_size * GetMainOverCrossAspectRatio(child));
+ } else if (MainAxisIsInlineAxis(child)) {
+ // We're now in parts C, D, and E for what are usually (horizontal-tb
+ // containers AND children) row flex containers. I _think_ the C and D
+ // cases are correctly handled by this code, which was originally
+ // written for case E.
+ if (child.HasAspectRatio()) {
+ // Legacy uses child.PreferredLogicalWidths() for this case, which
+ // is not exactly correct.
+ // TODO(dgrogan): Replace with a variant of ComputeReplacedSize that
+ // ignores min-width, width, max-width.
+ flex_base_border_box =
+ child.GetLayoutBox()->PreferredLogicalWidths().max_size;
+ } else {
+ flex_base_border_box = MinMaxSizesFunc().max_size;
+ }
+ } else {
+ // Parts C, D, and E for what are usually column flex containers.
+ //
+ // This is the post-layout height for aspect-ratio items, which matches
+ // legacy but isn't always correct.
+ // TODO(dgrogan): Replace with a variant of ComputeReplacedSize that
+ // ignores min-height, height, max-height.
+ flex_base_border_box = IntrinsicBlockSizeFunc();
+ }
+ } else {
+ // Part A of 9.2.3 https://drafts.csswg.org/css-flexbox/#algo-main-item
+ if (MainAxisIsInlineAxis(child)) {
+ flex_base_border_box = ResolveMainInlineLength(
+ flex_basis_space, child_style, border_padding_in_child_writing_mode,
+ MinMaxSizesFunc, length_to_resolve);
+ } else {
+ // Flex container's main axis is in child's block direction. Child's
+ // flex basis is in child's block direction.
+ flex_base_border_box = ResolveMainBlockLength(
+ flex_basis_space, child_style, border_padding_in_child_writing_mode,
+ length_to_resolve, IntrinsicBlockSizeFunc,
+ LengthResolvePhase::kLayout);
+ }
+ }
+
+ // Spec calls this "flex base size"
+ // https://www.w3.org/TR/css-flexbox-1/#algo-main-item
+ // Blink's FlexibleBoxAlgorithm expects it to be content + scrollbar widths,
+ // but no padding or border.
+ // The ClampNegativeToZero is needed for the last canvas element in
+ // flexbox-flex-basis-content-001a.html. It's possibly only needed because
+ // we don't properly account for borders+padding when multiplying by the
+ // aspect ratio.
+ LayoutUnit flex_base_content_size =
+ (flex_base_border_box - main_axis_border_padding).ClampNegativeToZero();
+
const Length& min = is_horizontal_flow_ ? child.Style().MinWidth()
: child.Style().MinHeight();
+ // TODO(dgrogan): min.IsIntrinsic should enter this block when it's in the
+ // item's block direction.
if (min.IsAuto()) {
if (algorithm_->ShouldApplyMinSizeAutoForChild(*child.GetLayoutBox())) {
- // TODO(dgrogan): Do the aspect ratio parts of
- // https://www.w3.org/TR/css-flexbox-1/#min-size-auto
-
- LayoutUnit content_size_suggestion =
- MainAxisIsInlineAxis(child) ? intrinsic_sizes_border_box.min_size
- : layout_result->IntrinsicBlockSize();
- content_size_suggestion =
- std::min(content_size_suggestion,
- min_max_sizes_in_main_axis_direction.max_size);
-
- if (child.MayHaveAspectRatio()) {
- // TODO(dgrogan): We're including borders/padding in both
- // content_size_suggestion and min_max_sizes_in_cross_axis_direction.
- // Maybe we need to multiply the content size by the aspect ratio and
- // then apply the border/padding from the other axis inside the
- // Adjust* function. Test legacy/firefox. Start with
- // https://jsfiddle.net/dgrogan/9uyg3aro/
- content_size_suggestion =
- AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
- child, content_size_suggestion,
- min_max_sizes_in_cross_axis_direction.min_size,
- min_max_sizes_in_cross_axis_direction.max_size);
- }
+ // TODO(dgrogan): This should probably apply to column flexboxes also,
+ // but that's not what legacy does.
+ if (child.IsTable() && !is_column_) {
+ MinMaxSizes table_preferred_widths =
+ ComputeMinAndMaxContentContribution(
+ Style(), child,
+ MinMaxSizesInput(child_percentage_size_.block_size));
+ min_max_sizes_in_main_axis_direction.min_size =
+ table_preferred_widths.min_size;
+ } else {
+ LayoutUnit content_size_suggestion;
+ if (MainAxisIsInlineAxis(child)) {
+ content_size_suggestion = MinMaxSizesFunc().min_size;
+ } else {
+ LayoutUnit intrinsic_block_size;
+ if (child.HasAspectRatio()) {
+ base::Optional<LayoutUnit> computed_inline_size;
+ base::Optional<LayoutUnit> computed_block_size;
+ child.IntrinsicSize(&computed_inline_size, &computed_block_size);
+
+ // The 150 is for elements that have an aspect ratio but no size,
+ // which SVG can have (maybe others?).
+ intrinsic_block_size =
+ computed_block_size.value_or(LayoutUnit(150));
+ } else {
+ intrinsic_block_size = IntrinsicBlockSizeFunc();
+ }
+ content_size_suggestion = intrinsic_block_size;
+ }
- LayoutUnit specified_size_suggestion(LayoutUnit::Max());
- // If the item’s computed main size property is definite, then the
- // specified size suggestion is that size.
- if (MainAxisIsInlineAxis(child)) {
- if (!specified_length_in_main_axis.IsAuto()) {
- // TODO(dgrogan): Optimization opportunity: we may have already
- // resolved specified_length_in_main_axis in the flex basis
- // calculation. Reuse that if possible.
- specified_size_suggestion = ResolveMainInlineLength(
- child_space, child_style, border_padding_in_child_writing_mode,
- intrinsic_sizes_border_box, specified_length_in_main_axis);
+
+ if (child.HasAspectRatio()) {
+ // TODO(dgrogan): We're including borders/padding in both
+ // content_size_suggestion and
+ // min_max_sizes_in_cross_axis_direction. Maybe we need to multiply
+ // the content size by the aspect ratio and then apply the
+ // border/padding from the other axis inside the Adjust* function.
+ // Test legacy/firefox. Start with
+ // https://jsfiddle.net/dgrogan/9uyg3aro/
+ content_size_suggestion =
+ AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
+ child, content_size_suggestion,
+ min_max_sizes_in_cross_axis_direction.min_size,
+ min_max_sizes_in_cross_axis_direction.max_size);
+ }
+
+ LayoutUnit specified_size_suggestion = LayoutUnit::Max();
+ // If the item’s computed main size property is definite, then the
+ // specified size suggestion is that size.
+ if (MainAxisIsInlineAxis(child)) {
+ if (!specified_length_in_main_axis.IsAuto()) {
+ // TODO(dgrogan): Optimization opportunity: we may have already
+ // resolved specified_length_in_main_axis in the flex basis
+ // calculation. Reuse that if possible.
+ specified_size_suggestion = ResolveMainInlineLength(
+ flex_basis_space, child_style,
+ border_padding_in_child_writing_mode, MinMaxSizesFunc,
+ specified_length_in_main_axis);
+ }
+ } else if (!BlockLengthUnresolvable(flex_basis_space,
+ specified_length_in_main_axis,
+ LengthResolvePhase::kLayout)) {
+ specified_size_suggestion = ResolveMainBlockLength(
+ flex_basis_space, child_style,
+ border_padding_in_child_writing_mode,
+ specified_length_in_main_axis, IntrinsicBlockSizeFunc,
+ LengthResolvePhase::kLayout);
+ DCHECK_NE(specified_size_suggestion, kIndefiniteSize);
}
- } else if (!BlockLengthUnresolvable(child_space,
- specified_length_in_main_axis,
- LengthResolvePhase::kLayout)) {
- specified_size_suggestion = ResolveMainBlockLength(
- child_space, child_style, border_padding_in_child_writing_mode,
- specified_length_in_main_axis,
- layout_result->IntrinsicBlockSize(), LengthResolvePhase::kLayout);
- DCHECK_NE(specified_size_suggestion, kIndefiniteSize);
- }
- // Spec says to clamp specified_size_suggestion by max size but because
- // content_size_suggestion already is, and we take the min of those
- // two, we don't need to clamp specified_size_suggestion.
- // https://github.com/w3c/csswg-drafts/issues/3669
- min_max_sizes_in_main_axis_direction.min_size =
- std::min(specified_size_suggestion, content_size_suggestion);
+ LayoutUnit transferred_size_suggestion = LayoutUnit::Max();
+ if (specified_size_suggestion == LayoutUnit::Max() &&
+ child.HasAspectRatio()) {
+ const Length& cross_axis_length = is_horizontal_flow_
+ ? child_style.Height()
+ : child_style.Width();
+ if (IsItemCrossAxisLengthDefinite(child, cross_axis_length)) {
+ LayoutUnit cross_axis_size;
+ if (MainAxisIsInlineAxis(child)) {
+ cross_axis_size = ResolveMainBlockLength(
+ flex_basis_space, child_style,
+ border_padding_in_child_writing_mode, cross_axis_length,
+ kIndefiniteSize, LengthResolvePhase::kLayout);
+ DCHECK_NE(cross_axis_size, kIndefiniteSize);
+ } else {
+ cross_axis_size = ResolveMainInlineLength(
+ flex_basis_space, child_style,
+ border_padding_in_child_writing_mode, MinMaxSizesFunc,
+ cross_axis_length);
+ }
+ double ratio = GetMainOverCrossAspectRatio(child);
+ transferred_size_suggestion = LayoutUnit(
+ ratio *
+ min_max_sizes_in_cross_axis_direction.ClampSizeToMinAndMax(
+ cross_axis_size));
+ }
+ }
+
+ DCHECK(specified_size_suggestion == LayoutUnit::Max() ||
+ transferred_size_suggestion == LayoutUnit::Max());
+
+ min_max_sizes_in_main_axis_direction.min_size =
+ std::min({specified_size_suggestion, content_size_suggestion,
+ transferred_size_suggestion,
+ min_max_sizes_in_main_axis_direction.max_size});
+ }
}
} else if (MainAxisIsInlineAxis(child)) {
min_max_sizes_in_main_axis_direction.min_size = ResolveMinInlineLength(
- child_space, child_style, border_padding_in_child_writing_mode,
- intrinsic_sizes_border_box, min, LengthResolvePhase::kLayout);
+ flex_basis_space, child_style, border_padding_in_child_writing_mode,
+ MinMaxSizesFunc, min, LengthResolvePhase::kLayout);
} else {
min_max_sizes_in_main_axis_direction.min_size = ResolveMinBlockLength(
- child_space, child_style, border_padding_in_child_writing_mode, min,
- fragment_in_child_writing_mode.BlockSize(),
- LengthResolvePhase::kLayout);
+ flex_basis_space, child_style, border_padding_in_child_writing_mode,
+ min, LengthResolvePhase::kLayout);
}
- // TODO(dgrogan): Should this include scrollbar?
- min_max_sizes_in_main_axis_direction -= main_axis_border_scrollbar_padding;
+ min_max_sizes_in_main_axis_direction -= main_axis_border_padding;
+ DCHECK_GE(min_max_sizes_in_main_axis_direction.min_size, 0);
+ DCHECK_GE(min_max_sizes_in_main_axis_direction.max_size, 0);
+
+ // TODO(dgrogan): Should min_max_sizes_in_cross_axis_direction include
+ // cross_axis_border_padding?
algorithm_
- ->emplace_back(child.GetLayoutBox(), flex_base_content_size,
+ ->emplace_back(nullptr, child.Style(), flex_base_content_size,
min_max_sizes_in_main_axis_direction,
min_max_sizes_in_cross_axis_direction,
- main_axis_border_padding, main_axis_margin)
+ main_axis_border_padding, cross_axis_border_padding,
+ physical_child_margins)
.ng_input_node = child;
}
}
@@ -457,33 +744,16 @@ NGFlexLayoutAlgorithm::AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
LayoutUnit content_suggestion,
LayoutUnit cross_min,
LayoutUnit cross_max) {
- DCHECK(child.MayHaveAspectRatio());
+ DCHECK(child.HasAspectRatio());
+
+ double ratio = GetMainOverCrossAspectRatio(child);
// Clamp content_suggestion by any definite min and max cross size properties
// converted through the aspect ratio.
-
- base::Optional<LayoutUnit> computed_inline_size;
- base::Optional<LayoutUnit> computed_block_size;
- LogicalSize aspect_ratio;
-
- child.IntrinsicSize(&computed_inline_size, &computed_block_size,
- &aspect_ratio);
-
- // TODO(dgrogan): Should we quit here if only the denominator is 0?
- if (aspect_ratio.inline_size == 0 || aspect_ratio.block_size == 0)
- return content_suggestion;
-
- double ratio = aspect_ratio.inline_size / aspect_ratio.block_size;
-
- // Multiplying by ratio will take something in the item's block axis and
- // convert it to the inline axis. We want to convert from cross size to main
- // size. If block axis and cross axis are the same, then we already have what
- // we need. Otherwise we need to use the reciprocal.
- if (!MainAxisIsInlineAxis(child))
- ratio = 1 / ratio;
-
const Length& cross_max_length = is_horizontal_flow_
? child.Style().MaxHeight()
: child.Style().MaxWidth();
+ // TODO(dgrogan): No tests fail if we unconditionally apply max_main_length.
+ // Either add a test that needs it or remove it.
if (IsItemCrossAxisLengthDefinite(child, cross_max_length)) {
LayoutUnit max_main_length = LayoutUnit(cross_max * ratio);
content_suggestion = std::min(max_main_length, content_suggestion);
@@ -492,6 +762,8 @@ NGFlexLayoutAlgorithm::AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
const Length& cross_min_length = is_horizontal_flow_
? child.Style().MinHeight()
: child.Style().MinWidth();
+ // TODO(dgrogan): Same as above with min_main_length here -- it may be
+ // unneeded or untested.
if (IsItemCrossAxisLengthDefinite(child, cross_min_length)) {
LayoutUnit min_main_length = LayoutUnit(cross_min * ratio);
content_suggestion = std::max(min_main_length, content_suggestion);
@@ -500,15 +772,7 @@ NGFlexLayoutAlgorithm::AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
}
scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
- border_box_size_ = container_builder_.InitialBorderBoxSize();
- content_box_size_ =
- ShrinkAvailableSize(border_box_size_, border_scrollbar_padding_);
- child_percentage_size_ = CalculateChildPercentageSize(
- ConstraintSpace(), Node(), content_box_size_);
-
- const LayoutUnit line_break_length = MainAxisContentExtent(LayoutUnit::Max());
- algorithm_.emplace(&Style(), line_break_length);
-
+ PaintLayerScrollableArea::DelayScrollOffsetClampScope delay_clamp_scope;
ConstructAndAppendFlexItems();
LayoutUnit main_axis_start_offset;
@@ -542,22 +806,29 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
for (wtf_size_t i = 0; i < line->line_items.size(); ++i) {
FlexItem& flex_item = line->line_items[i];
- WritingMode child_writing_mode =
- flex_item.ng_input_node.Style().GetWritingMode();
+ const ComputedStyle& child_style = flex_item.ng_input_node.Style();
NGConstraintSpaceBuilder space_builder(ConstraintSpace(),
- child_writing_mode,
+ child_style.GetWritingMode(),
/* is_new_fc */ true);
SetOrthogonalFallbackInlineSizeIfNeeded(Style(), flex_item.ng_input_node,
&space_builder);
- space_builder.SetTextDirection(
- flex_item.ng_input_node.Style().Direction());
+ space_builder.SetTextDirection(child_style.Direction());
+ space_builder.SetIsPaintedAtomically(true);
LogicalSize available_size;
+ NGBoxStrut margins = flex_item.physical_margins.ConvertToLogical(
+ ConstraintSpace().GetWritingMode(), Style().Direction());
if (is_column_) {
available_size.inline_size = content_box_size_.inline_size;
available_size.block_size =
flex_item.flexed_content_size + flex_item.main_axis_border_padding;
space_builder.SetIsFixedBlockSize(true);
+ if (WillChildCrossSizeBeContainerCrossSize(flex_item.ng_input_node)) {
+ space_builder.SetIsFixedInlineSize(true);
+ available_size.inline_size = CalculateFixedCrossSize(
+ available_size.inline_size, flex_item.min_max_cross_sizes.value(),
+ margins.InlineSum());
+ }
// https://drafts.csswg.org/css-flexbox/#definite-sizes
// If the flex container has a definite main size, a flex item's
// post-flexing main size is treated as definite, even though it can
@@ -571,16 +842,22 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
flex_item.flexed_content_size + flex_item.main_axis_border_padding;
available_size.block_size = content_box_size_.block_size;
space_builder.SetIsFixedInlineSize(true);
- }
- if (WillChildCrossSizeBeContainerCrossSize(flex_item.ng_input_node)) {
- if (is_column_)
- space_builder.SetIsFixedInlineSize(true);
- else
+ if (WillChildCrossSizeBeContainerCrossSize(flex_item.ng_input_node)) {
space_builder.SetIsFixedBlockSize(true);
+ available_size.block_size = CalculateFixedCrossSize(
+ available_size.block_size, flex_item.min_max_cross_sizes.value(),
+ margins.BlockSum());
+ }
}
+ space_builder.SetNeedsBaseline(
+ ConstraintSpace().NeedsBaseline() ||
+ FlexLayoutAlgorithm::AlignmentForChild(Style(), child_style) ==
+ ItemPosition::kBaseline);
+
space_builder.SetAvailableSize(available_size);
space_builder.SetPercentageResolutionSize(child_percentage_size_);
+ space_builder.SetReplacedPercentageResolutionSize(child_percentage_size_);
// https://drafts.csswg.org/css-flexbox/#algo-cross-item
// Determine the hypothetical cross size of each item by performing layout
@@ -592,6 +869,10 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
NGConstraintSpace child_space = space_builder.ToConstraintSpace();
flex_item.layout_result =
flex_item.ng_input_node.Layout(child_space, nullptr /*break token*/);
+
+ // TODO(layout-dev): Handle abortions caused by block fragmentation.
+ DCHECK_EQ(flex_item.layout_result->Status(), NGLayoutResult::kSuccess);
+
flex_item.cross_axis_size =
is_horizontal_flow_
? flex_item.layout_result->PhysicalFragment().Size().height
@@ -627,12 +908,13 @@ scoped_refptr<const NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
}
void NGFlexLayoutAlgorithm::ApplyStretchAlignmentToChild(FlexItem& flex_item) {
- WritingMode child_writing_mode =
- flex_item.ng_input_node.Style().GetWritingMode();
- NGConstraintSpaceBuilder space_builder(ConstraintSpace(), child_writing_mode,
+ const ComputedStyle& child_style = flex_item.ng_input_node.Style();
+ NGConstraintSpaceBuilder space_builder(ConstraintSpace(),
+ child_style.GetWritingMode(),
/* is_new_fc */ true);
SetOrthogonalFallbackInlineSizeIfNeeded(Style(), flex_item.ng_input_node,
&space_builder);
+ space_builder.SetIsPaintedAtomically(true);
LogicalSize available_size(
flex_item.flexed_content_size + flex_item.main_axis_border_padding,
@@ -644,9 +926,16 @@ void NGFlexLayoutAlgorithm::ApplyStretchAlignmentToChild(FlexItem& flex_item) {
space_builder.SetIsFixedBlockSizeIndefinite(true);
}
}
- space_builder.SetTextDirection(flex_item.ng_input_node.Style().Direction());
+
+ space_builder.SetNeedsBaseline(
+ ConstraintSpace().NeedsBaseline() ||
+ FlexLayoutAlgorithm::AlignmentForChild(Style(), child_style) ==
+ ItemPosition::kBaseline);
+
+ space_builder.SetTextDirection(child_style.Direction());
space_builder.SetAvailableSize(available_size);
space_builder.SetPercentageResolutionSize(child_percentage_size_);
+ space_builder.SetReplacedPercentageResolutionSize(child_percentage_size_);
space_builder.SetIsFixedInlineSize(true);
space_builder.SetIsFixedBlockSize(true);
NGConstraintSpace child_space = space_builder.ToConstraintSpace();
@@ -687,6 +976,9 @@ void NGFlexLayoutAlgorithm::GiveLinesAndItemsFinalPositionAndSize() {
border_scrollbar_padding_.block_start);
}
+ base::Optional<LayoutUnit> fallback_baseline;
+
+ LayoutUnit overflow_block_size;
for (FlexLine& line_context : line_contexts) {
for (wtf_size_t child_number = 0;
child_number < line_context.line_items.size(); ++child_number) {
@@ -695,6 +987,9 @@ void NGFlexLayoutAlgorithm::GiveLinesAndItemsFinalPositionAndSize() {
if (DoesItemStretch(flex_item.ng_input_node))
ApplyStretchAlignmentToChild(flex_item);
+ const auto& physical_fragment = To<NGPhysicalBoxFragment>(
+ flex_item.layout_result->PhysicalFragment());
+
// flex_item.desired_location stores the main axis offset in X and the
// cross axis offset in Y. But AddChild wants offset from parent
// rectangle, so we have to transpose for columns. AddChild takes care of
@@ -702,16 +997,70 @@ void NGFlexLayoutAlgorithm::GiveLinesAndItemsFinalPositionAndSize() {
LayoutPoint location = is_column_
? flex_item.desired_location.TransposedPoint()
: flex_item.desired_location;
- container_builder_.AddChild(flex_item.layout_result->PhysicalFragment(),
+
+ NGBoxFragment fragment(ConstraintSpace().GetWritingMode(),
+ ConstraintSpace().Direction(), physical_fragment);
+ // Only propagate baselines from children on the first flex-line.
+ if (&line_context == line_contexts.begin()) {
+ PropagateBaselineFromChild(flex_item, fragment, location.Y(),
+ &fallback_baseline);
+ }
+
+ container_builder_.AddChild(physical_fragment,
{location.X(), location.Y()});
+
+ flex_item.ng_input_node.StoreMargins(flex_item.physical_margins);
+
+ LayoutUnit margin_block_end =
+ flex_item.physical_margins
+ .ConvertToLogical(ConstraintSpace().GetWritingMode(),
+ ConstraintSpace().Direction())
+ .block_end;
+ overflow_block_size =
+ std::max(overflow_block_size,
+ location.Y() + fragment.BlockSize() + margin_block_end);
}
}
+
+ container_builder_.SetOverflowBlockSize(overflow_block_size +
+ border_scrollbar_padding_.block_end);
+
+ // Set the baseline to the fallback, if we didn't find any children with
+ // baseline alignment.
+ if (!container_builder_.Baseline() && fallback_baseline)
+ container_builder_.SetBaseline(*fallback_baseline);
+}
+
+void NGFlexLayoutAlgorithm::PropagateBaselineFromChild(
+ const FlexItem& flex_item,
+ const NGBoxFragment& fragment,
+ LayoutUnit block_offset,
+ base::Optional<LayoutUnit>* fallback_baseline) {
+ // Check if we've already found an appropriate baseline.
+ if (container_builder_.Baseline())
+ return;
+
+ LayoutUnit baseline_offset =
+ block_offset + fragment.Baseline().value_or(fragment.BlockSize());
+
+ // We prefer a baseline from a child with baseline alignment, and no
+ // auto-margins in the cross axis (even if we have to synthesize the
+ // baseline).
+ if (FlexLayoutAlgorithm::AlignmentForChild(Style(), flex_item.style) ==
+ ItemPosition::kBaseline &&
+ !flex_item.HasAutoMarginsInCrossAxis()) {
+ container_builder_.SetBaseline(baseline_offset);
+ return;
+ }
+
+ // Set the fallback baseline if it doesn't have a value yet.
+ *fallback_baseline = fallback_baseline->value_or(baseline_offset);
}
-base::Optional<MinMaxSize> NGFlexLayoutAlgorithm::ComputeMinMaxSize(
- const MinMaxSizeInput& input) const {
- base::Optional<MinMaxSize> sizes = CalculateMinMaxSizesIgnoringChildren(
- Node(), border_scrollbar_padding_, input.size_type);
+base::Optional<MinMaxSizes> NGFlexLayoutAlgorithm::ComputeMinMaxSizes(
+ const MinMaxSizesInput& input) const {
+ base::Optional<MinMaxSizes> sizes =
+ CalculateMinMaxSizesIgnoringChildren(Node(), border_scrollbar_padding_);
if (sizes)
return sizes;
@@ -721,21 +1070,15 @@ base::Optional<MinMaxSize> NGFlexLayoutAlgorithm::ComputeMinMaxSize(
ConstraintSpace(), Node(), border_padding_,
input.percentage_resolution_block_size);
- // Use default MinMaxSizeInput:
- // - Children of flexbox ignore any specified float properties, so children
- // never have to take floated siblings into account, and external floats
- // don't make it through the new formatting context that flexbox
- // establishes.
- // - We want the child's border box MinMaxSize, which is the default.
- MinMaxSizeInput child_input(child_percentage_resolution_block_size);
-
- for (NGLayoutInputNode generic_child = Node().FirstChild(); generic_child;
- generic_child = generic_child.NextSibling()) {
- auto child = To<NGBlockNode>(generic_child);
+ MinMaxSizesInput child_input(child_percentage_resolution_block_size);
+
+ NGFlexChildIterator iterator(Node());
+ for (NGBlockNode child = iterator.NextChild(); child;
+ child = iterator.NextChild()) {
if (child.IsOutOfFlowPositioned())
continue;
- MinMaxSize child_min_max_sizes =
+ MinMaxSizes child_min_max_sizes =
ComputeMinAndMaxContentContribution(Style(), child, child_input);
NGBoxStrut child_margins = ComputeMinMaxMargins(Style(), child);
child_min_max_sizes += child_margins.InlineSum();
@@ -744,7 +1087,7 @@ base::Optional<MinMaxSize> NGFlexLayoutAlgorithm::ComputeMinMaxSize(
sizes->max_size = std::max(sizes->max_size, child_min_max_sizes.max_size);
} else {
sizes->max_size += child_min_max_sizes.max_size;
- if (IsMultiline()) {
+ if (algorithm_->IsMultiline()) {
sizes->min_size =
std::max(sizes->min_size, child_min_max_sizes.min_size);
} else {
@@ -757,15 +1100,8 @@ base::Optional<MinMaxSize> NGFlexLayoutAlgorithm::ComputeMinMaxSize(
// Due to negative margins, it is possible that we calculated a negative
// intrinsic width. Make sure that we never return a negative width.
sizes->Encompass(LayoutUnit());
-
- if (input.size_type == NGMinMaxSizeType::kBorderBoxSize)
- *sizes += border_scrollbar_padding_.InlineSum();
-
+ *sizes += border_scrollbar_padding_.InlineSum();
return sizes;
}
-bool NGFlexLayoutAlgorithm::IsMultiline() const {
- return Style().FlexWrap() != EFlexWrap::kNowrap;
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
index 16f6aaa02e1..066277e3075 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h
@@ -14,6 +14,7 @@ namespace blink {
class NGBlockNode;
class NGBlockBreakToken;
+class NGBoxFragment;
class CORE_EXPORT NGFlexLayoutAlgorithm
: public NGLayoutAlgorithm<NGBlockNode,
@@ -24,15 +25,17 @@ class CORE_EXPORT NGFlexLayoutAlgorithm
scoped_refptr<const NGLayoutResult> Layout() override;
- base::Optional<MinMaxSize> ComputeMinMaxSize(
- const MinMaxSizeInput&) const override;
+ base::Optional<MinMaxSizes> ComputeMinMaxSizes(
+ const MinMaxSizesInput&) const override;
private:
bool DoesItemCrossSizeComputeToAuto(const NGBlockNode& child) const;
+ bool IsItemFlexBasisDefinite(const NGBlockNode& child) const;
bool IsItemMainSizeDefinite(const NGBlockNode& child) const;
bool IsItemCrossAxisLengthDefinite(const NGBlockNode& child,
const Length& length) const;
bool ShouldItemShrinkToFit(const NGBlockNode& child) const;
+ double GetMainOverCrossAspectRatio(const NGBlockNode& child) const;
bool DoesItemStretch(const NGBlockNode& child) const;
// This implements the first of the additional scenarios where a flex item
// has definite sizes when it would not if it weren't a flex item.
@@ -47,8 +50,11 @@ class CORE_EXPORT NGFlexLayoutAlgorithm
bool IsColumnContainerMainSizeDefinite() const;
bool IsContainerCrossSizeDefinite() const;
- NGConstraintSpace BuildConstraintSpaceForDeterminingFlexBasis(
- const NGBlockNode& flex_item) const;
+ NGConstraintSpace BuildSpaceForFlexBasis(const NGBlockNode& flex_item) const;
+ NGConstraintSpace BuildSpaceForIntrinsicBlockSize(
+ const NGBlockNode& flex_item,
+ const NGPhysicalBoxStrut& physical_margins,
+ const MinMaxSizes& cross_axis) const;
void ConstructAndAppendFlexItems();
void ApplyStretchAlignmentToChild(FlexItem& flex_item);
void GiveLinesAndItemsFinalPositionAndSize();
@@ -57,20 +63,22 @@ class CORE_EXPORT NGFlexLayoutAlgorithm
// This is same method as FlexItem but we need that logic before FlexItem is
// constructed.
bool MainAxisIsInlineAxis(const NGBlockNode& child) const;
- LayoutUnit MainAxisContentExtent(LayoutUnit sum_hypothetical_main_size);
+ LayoutUnit MainAxisContentExtent(LayoutUnit sum_hypothetical_main_size) const;
void HandleOutOfFlowPositioned(NGBlockNode child);
- // TODO(dgrogan): This is redundant with FlexLayoutAlgorithm.IsMultiline() but
- // it's needed before the algorithm is instantiated. Figure out how to
- // not reimplement.
- bool IsMultiline() const;
+
+ // Propagates the baseline from the given flex-item if needed.
+ void PropagateBaselineFromChild(
+ const FlexItem&,
+ const NGBoxFragment&,
+ LayoutUnit block_offset,
+ base::Optional<LayoutUnit>* fallback_baseline);
const NGBoxStrut border_padding_;
const NGBoxStrut border_scrollbar_padding_;
const bool is_column_;
const bool is_horizontal_flow_;
- // These are populated at the top of Layout(), so aren't available in
- // ComputeMinMaxSize() or anything it calls.
+ const bool is_cross_size_definite_;
LogicalSize border_box_size_;
LogicalSize content_box_size_;
LogicalSize child_percentage_size_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
index dccc520c12e..3404db2e94f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc
@@ -6,7 +6,7 @@
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
-#include "third_party/blink/renderer/core/layout/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
@@ -66,13 +66,14 @@ NGConstraintSpace CreateConstraintSpaceForFloat(
/* is_new_fc */ true);
SetOrthogonalFallbackInlineSizeIfNeeded(unpositioned_float.parent_style,
unpositioned_float.node, &builder);
+ builder.SetIsPaintedAtomically(true);
if (origin_block_offset) {
DCHECK(parent_space.HasBlockFragmentation());
DCHECK_EQ(style.GetWritingMode(), parent_space.GetWritingMode());
- SetupFragmentation(parent_space, *origin_block_offset, &builder,
- /* is_new_fc */ true);
+ SetupFragmentation(parent_space, unpositioned_float.node,
+ *origin_block_offset, &builder, /* is_new_fc */ true);
} else {
builder.SetFragmentationType(NGFragmentationType::kFragmentNone);
}
@@ -118,7 +119,7 @@ std::unique_ptr<NGExclusionShapeData> CreateExclusionShapeData(
case CSSBoxType::kContent:
const NGConstraintSpace space =
CreateConstraintSpaceForFloat(unpositioned_float);
- NGBoxStrut strut = ComputeBorders(space, unpositioned_float.node);
+ NGBoxStrut strut = ComputeBorders(space, style);
if (style.ShapeOutside()->CssBox() == CSSBoxType::kContent)
strut += ComputePadding(space, style);
shape_insets =
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
index a1ceb920f02..f0bd55d5bc0 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h
@@ -47,6 +47,9 @@ class CORE_EXPORT NGFragmentBuilder {
void SetIsHiddenForPaint(bool value) { is_hidden_for_paint_ = value; }
+ // Specify whether this will be the first fragment generated for the node.
+ void SetIsFirstForNode(bool is_first) { is_first_for_node_ = is_first; }
+
const LayoutObject* GetLayoutObject() const { return layout_object_; }
protected:
@@ -80,6 +83,7 @@ class CORE_EXPORT NGFragmentBuilder {
LayoutObject* layout_object_ = nullptr;
scoped_refptr<NGBreakToken> break_token_;
bool is_hidden_for_paint_ = false;
+ bool is_first_for_node_ = true;
friend class NGPhysicalFragment;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.cc
new file mode 100644
index 00000000000..167e14136f6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.cc
@@ -0,0 +1,212 @@
+// Copyright 2020 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/ng/ng_fragment_child_iterator.h"
+
+#include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
+#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+
+namespace blink {
+
+NGFragmentChildIterator::NGFragmentChildIterator(
+ const NGPhysicalBoxFragment& parent,
+ const NGBlockBreakToken* parent_break_token)
+ : parent_fragment_(&parent),
+ parent_break_token_(parent_break_token),
+ is_fragmentation_context_root_(parent.IsFragmentationContextRoot()) {
+ DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
+ current_.link_.fragment = nullptr;
+ if (parent_break_token)
+ child_break_tokens_ = parent_break_token->ChildBreakTokens();
+ if (parent.HasItems()) {
+ current_.cursor_.emplace(*parent.Items());
+ current_.block_break_token_ = parent_break_token;
+ UpdateSelfFromCursor();
+ } else {
+ UpdateSelfFromFragment();
+ }
+}
+
+NGFragmentChildIterator::NGFragmentChildIterator(
+ const NGInlineCursor& parent,
+ const NGBlockBreakToken* parent_break_token,
+ base::span<const NGBreakToken* const> child_break_tokens)
+ : parent_break_token_(parent_break_token),
+ child_break_tokens_(child_break_tokens) {
+ current_.block_break_token_ = parent_break_token;
+ current_.link_.fragment = nullptr;
+ current_.cursor_ = parent.CursorForDescendants();
+ UpdateSelfFromCursor();
+}
+
+NGFragmentChildIterator NGFragmentChildIterator::Descend() const {
+ if (current_.cursor_) {
+ const NGFragmentItem* item = current_.cursor_->CurrentItem();
+ // Descend using the cursor if the current item doesn't establish a new
+ // formatting context.
+ if (!item->IsFormattingContextRoot()) {
+ return NGFragmentChildIterator(
+ *current_.cursor_,
+ current_.BlockBreakToken() ? parent_break_token_ : nullptr,
+ child_break_tokens_.subspan(child_break_token_idx_));
+ }
+ }
+ DCHECK(current_.BoxFragment());
+ return NGFragmentChildIterator(*current_.BoxFragment(),
+ current_.BlockBreakToken());
+}
+
+bool NGFragmentChildIterator::AdvanceChildFragment() {
+ DCHECK(parent_fragment_);
+ const auto children = parent_fragment_->Children();
+ const NGPhysicalBoxFragment* previous_fragment =
+ To<NGPhysicalBoxFragment>(current_.link_.fragment);
+ DCHECK(previous_fragment);
+ if (child_fragment_idx_ < children.size())
+ child_fragment_idx_++;
+ // There may be line box fragments among the children, and we're not
+ // interested in them (lines will already have been handled by the inline
+ // cursor).
+ SkipToBoxFragment();
+ if (child_fragment_idx_ >= children.size())
+ return false;
+ if (child_break_token_idx_ < child_break_tokens_.size())
+ child_break_token_idx_++;
+ UpdateSelfFromFragment(previous_fragment);
+ return true;
+}
+
+void NGFragmentChildIterator::UpdateSelfFromFragment(
+ const NGPhysicalBoxFragment* previous_fragment) {
+ DCHECK(parent_fragment_);
+ const auto children = parent_fragment_->Children();
+ if (child_fragment_idx_ >= children.size())
+ return;
+ current_.link_ = children[child_fragment_idx_];
+ DCHECK(current_.link_.fragment);
+ SkipToBlockBreakToken();
+ if (child_break_token_idx_ < child_break_tokens_.size()) {
+ current_.block_break_token_ =
+ To<NGBlockBreakToken>(child_break_tokens_[child_break_token_idx_]);
+ DCHECK(!current_.link_.fragment->GetLayoutObject() ||
+ current_.block_break_token_->InputNode().GetLayoutBox() ==
+ current_.link_.fragment->GetLayoutObject());
+ current_.break_token_for_fragmentainer_only_ = false;
+ } else if (is_fragmentation_context_root_ && previous_fragment) {
+ if (previous_fragment->IsColumnBox()) {
+ // The outgoing break token from one fragmentainer is the incoming break
+ // token to the next one. This is also true when there are column spanners
+ // between two columns (fragmentainers); the outgoing break token from the
+ // former column will be ignored by any intervening spanners, and then fed
+ // into the first column that comes after them, as an incoming break
+ // token.
+ current_.block_break_token_ =
+ To<NGBlockBreakToken>(previous_fragment->BreakToken());
+ current_.break_token_for_fragmentainer_only_ = true;
+ } else {
+ // This is a column spanner. We'll leave |current_block_break_token_|
+ // alone here, as it will be used as in incoming break token when we get
+ // to the next column.
+ DCHECK(
+ NGBlockNode(ToLayoutBox(previous_fragment->GetMutableLayoutObject()))
+ .IsColumnSpanAll());
+
+ // If the previous fragment is a column spanner, it's not expected to have
+ // a break token; if a spanner runs out of space, no columns (or spanners)
+ // would fit after it.
+ DCHECK(!previous_fragment->BreakToken());
+ }
+ } else {
+ current_.block_break_token_ = nullptr;
+ }
+}
+
+bool NGFragmentChildIterator::AdvanceWithCursor() {
+ DCHECK(current_.cursor_);
+ const NGFragmentItem* item = current_.cursor_->CurrentItem();
+ if (item->HasChildren()) {
+ // If we're advancing past a non-atomic inline, we also need to advance past
+ // any break tokens for fragments in there.
+ for (wtf_size_t remaining = item->DescendantsCount(); remaining;
+ remaining--) {
+ if (item->IsFloating()) {
+ SkipToBlockBreakToken();
+ if (child_break_token_idx_ < child_break_tokens_.size()) {
+ DCHECK_EQ(child_break_tokens_[child_break_token_idx_]
+ ->InputNode()
+ .GetLayoutBox(),
+ item->GetLayoutObject());
+ child_break_token_idx_++;
+ }
+ }
+ current_.cursor_->MoveToNext();
+ item = current_.cursor_->CurrentItem();
+ }
+ } else {
+ current_.cursor_->MoveToNext();
+ }
+ UpdateSelfFromCursor();
+ if (current_.cursor_->CurrentItem())
+ return true;
+ // If there are more items, proceed and see if we have box fragment
+ // children. There may be out-of-flow positioned child fragments.
+ if (!parent_fragment_)
+ return false;
+ current_.cursor_.reset();
+ SkipToBoxFragment();
+ UpdateSelfFromFragment();
+ return !IsAtEnd();
+}
+
+void NGFragmentChildIterator::UpdateSelfFromCursor() {
+ DCHECK(current_.cursor_);
+ // For inline items we just use the incoming break token to the containing
+ // block.
+ current_.block_break_token_ = parent_break_token_;
+ const NGFragmentItem* item = current_.cursor_->CurrentItem();
+ if (!item) {
+ current_.link_.fragment = nullptr;
+ return;
+ }
+ current_.link_ = {item->BoxFragment(), item->OffsetInContainerBlock()};
+ if (!current_.link_.fragment || !current_.link_.fragment->IsFloating()) {
+ DCHECK(!current_.link_.fragment ||
+ current_.link_.fragment->GetLayoutObject()->IsInline());
+ return;
+ }
+ if (!parent_break_token_)
+ return;
+ // Floats may fragment, in which case there's a designated break token for
+ // them.
+ SkipToBlockBreakToken();
+ if (child_break_token_idx_ >= child_break_tokens_.size()) {
+ current_.block_break_token_ = nullptr;
+ return;
+ }
+ current_.block_break_token_ =
+ To<NGBlockBreakToken>(child_break_tokens_[child_break_token_idx_]);
+ DCHECK(!current_.link_.fragment->GetLayoutObject() ||
+ current_.block_break_token_->InputNode().GetLayoutBox() ==
+ current_.link_.fragment->GetLayoutObject());
+}
+
+void NGFragmentChildIterator::SkipToBoxFragment() {
+ for (const auto children = parent_fragment_->Children();
+ child_fragment_idx_ < children.size(); child_fragment_idx_++) {
+ if (children[child_fragment_idx_].fragment->IsBox())
+ break;
+ }
+}
+
+void NGFragmentChildIterator::SkipToBlockBreakToken() {
+ // There may be inline break tokens here. Ignore them.
+ while (child_break_token_idx_ < child_break_tokens_.size() &&
+ !child_break_tokens_[child_break_token_idx_]->IsBlockType())
+ child_break_token_idx_++;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h
new file mode 100644
index 00000000000..c4927f0acad
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator.h
@@ -0,0 +1,141 @@
+// Copyright 2020 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FRAGMENT_CHILD_ITERATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FRAGMENT_CHILD_ITERATOR_H_
+
+#include "base/containers/span.h"
+#include "base/optional.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_link.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+
+namespace blink {
+
+class LayoutObject;
+class NGBlockBreakToken;
+
+// Iterator for children of a box fragment. Supports fragment items and break
+// tokens. To advance to the next sibling, call |Advance()|. To descend into
+// children of the current child, call |Descend()|.
+//
+// Using this class requires LayoutNGFragmentItem to be enabled. While fragment
+// items are in a flat list representing the contents of an inline formatting
+// context, the iterator will to a certain extent restore the object hierarchy,
+// so that we can calculate the global offset of children of a relatively
+// positioned inline correctly.
+class CORE_EXPORT NGFragmentChildIterator {
+ STACK_ALLOCATED();
+
+ public:
+ explicit NGFragmentChildIterator(
+ const NGPhysicalBoxFragment& parent,
+ const NGBlockBreakToken* parent_break_token = nullptr);
+
+ // Create a child iterator for the current child.
+ NGFragmentChildIterator Descend() const;
+
+ // Move to the next sibling. Return false if there's no next sibling. Once
+ // false is returned, this object is in an unusable state, with the exception
+ // that calling IsAtEnd() is allowed.
+ bool Advance() {
+ if (current_.cursor_)
+ return AdvanceWithCursor();
+ return AdvanceChildFragment();
+ }
+
+ bool IsAtEnd() {
+ if (current_.cursor_)
+ return !*current_.cursor_;
+ DCHECK(parent_fragment_);
+ const auto children = parent_fragment_->Children();
+ return child_fragment_idx_ >= children.size();
+ }
+
+ class Current {
+ friend class NGFragmentChildIterator;
+
+ public:
+ // Return the current NGLink. Note that its offset is relative to the inline
+ // formatting context root, if the fragment / item participates in one.
+ const NGLink& Link() const { return link_; }
+
+ const NGPhysicalBoxFragment* BoxFragment() const {
+ return To<NGPhysicalBoxFragment>(link_.fragment);
+ }
+ const NGFragmentItem* FragmentItem() const {
+ if (!cursor_)
+ return nullptr;
+ return cursor_->CurrentItem();
+ }
+
+ // Get the incoming break token for the current child, i.e. the context at
+ // which layout of this child's node was resumed. Note that for text and
+ // non-atomic inlines this will be the incoming block break token to the
+ // inline formatting context root. For monolithic content, no break token
+ // will be returned (since such content isn't considered to participate in a
+ // fragmentation context).
+ const NGBlockBreakToken* BlockBreakToken() const {
+ if (LIKELY(!block_break_token_))
+ return nullptr;
+ if (link_.fragment) {
+ // Don't pass the break token into monolithic content.
+ if (link_.fragment->IsMonolithic())
+ return nullptr;
+ // If the break token we've found is from a fragmentainer, it's only to
+ // be used by a subsequent fragmentainer. Other fragment types (such as
+ // column spanners) need to ignore it.
+ if (break_token_for_fragmentainer_only_ &&
+ !link_.fragment->IsColumnBox())
+ return nullptr;
+ }
+ return block_break_token_;
+ }
+
+ const LayoutObject* GetLayoutObject() const {
+ if (const NGFragmentItem* item = FragmentItem())
+ return item->GetLayoutObject();
+ return BoxFragment()->GetLayoutObject();
+ }
+
+ private:
+ NGLink link_;
+ base::Optional<NGInlineCursor> cursor_;
+ const NGBlockBreakToken* block_break_token_ = nullptr;
+ bool break_token_for_fragmentainer_only_ = false;
+ };
+
+ const Current& GetCurrent() const { return current_; }
+ const Current& operator*() const { return current_; }
+ const Current* operator->() const { return &current_; }
+
+ private:
+ NGFragmentChildIterator(
+ const NGInlineCursor& parent,
+ const NGBlockBreakToken* parent_break_token,
+ base::span<const NGBreakToken* const> child_break_tokens);
+
+ bool AdvanceChildFragment();
+ void UpdateSelfFromFragment(
+ const NGPhysicalBoxFragment* previous_fragment = nullptr);
+
+ bool AdvanceWithCursor();
+ void UpdateSelfFromCursor();
+ void SkipToBoxFragment();
+ void SkipToBlockBreakToken();
+
+ const NGPhysicalBoxFragment* parent_fragment_ = nullptr;
+ const NGBlockBreakToken* parent_break_token_ = nullptr;
+ Current current_;
+ base::span<const NGBreakToken* const> child_break_tokens_;
+ wtf_size_t child_fragment_idx_ = 0;
+ wtf_size_t child_break_token_idx_ = 0;
+ bool is_fragmentation_context_root_ = false;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FRAGMENT_CHILD_ITERATOR_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator_test.cc
new file mode 100644
index 00000000000..f0304c056d1
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_child_iterator_test.cc
@@ -0,0 +1,808 @@
+// Copyright 2020 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/ng/ng_fragment_child_iterator.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+
+namespace blink {
+namespace {
+
+class NGFragmentChildIteratorTest
+ : public NGBaseLayoutAlgorithmTest,
+ private ScopedLayoutNGBlockFragmentationForTest,
+ private ScopedLayoutNGFragmentItemForTest {
+ protected:
+ NGFragmentChildIteratorTest()
+ : ScopedLayoutNGBlockFragmentationForTest(true),
+ ScopedLayoutNGFragmentItemForTest(true) {}
+
+ scoped_refptr<const NGPhysicalBoxFragment> RunBlockLayoutAlgorithm(
+ Element* element) {
+ NGBlockNode container(ToLayoutBox(element->GetLayoutObject()));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize));
+ return NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(container, space);
+ }
+};
+
+TEST_F(NGFragmentChildIteratorTest, Basic) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="container">
+ <div id="child1">
+ <div id="grandchild"></div>
+ </div>
+ <div id="child2"></div>
+ </div>
+ )HTML");
+
+ const LayoutObject* child1 = GetLayoutObjectByElementId("child1");
+ const LayoutObject* child2 = GetLayoutObjectByElementId("child2");
+ const LayoutObject* grandchild = GetLayoutObjectByElementId("grandchild");
+
+ scoped_refptr<const NGPhysicalBoxFragment> container =
+ RunBlockLayoutAlgorithm(GetElementById("container"));
+ NGFragmentChildIterator iterator1(*container.get());
+ EXPECT_FALSE(iterator1.IsAtEnd());
+
+ const NGPhysicalBoxFragment* fragment = iterator1->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), child1);
+ EXPECT_FALSE(iterator1.IsAtEnd());
+
+ NGFragmentChildIterator iterator2 = iterator1.Descend();
+ EXPECT_FALSE(iterator2.IsAtEnd());
+ fragment = iterator2->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), grandchild);
+ EXPECT_FALSE(iterator2.IsAtEnd());
+ EXPECT_FALSE(iterator2.Advance());
+ EXPECT_TRUE(iterator2.IsAtEnd());
+
+ EXPECT_TRUE(iterator1.Advance());
+ fragment = iterator1->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), child2);
+ EXPECT_FALSE(iterator1.IsAtEnd());
+
+ // #child2 has no children.
+ EXPECT_TRUE(iterator1.Descend().IsAtEnd());
+
+ // No more children left.
+ EXPECT_FALSE(iterator1.Advance());
+ EXPECT_TRUE(iterator1.IsAtEnd());
+}
+
+TEST_F(NGFragmentChildIteratorTest, BasicInline) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="container">
+ xxx
+ <span id="span1" style="border:solid;">
+ <div id="float1" style="float:left;"></div>
+ xxx
+ </span>
+ xxx
+ </div>
+ )HTML");
+
+ const LayoutObject* span1 = GetLayoutObjectByElementId("span1");
+ const LayoutObject* float1 = GetLayoutObjectByElementId("float1");
+
+ scoped_refptr<const NGPhysicalBoxFragment> container =
+ RunBlockLayoutAlgorithm(GetElementById("container"));
+ NGFragmentChildIterator iterator1(*container.get());
+
+ EXPECT_FALSE(iterator1->BoxFragment());
+ const NGFragmentItem* fragment_item = iterator1->FragmentItem();
+ ASSERT_TRUE(fragment_item);
+ EXPECT_EQ(fragment_item->Type(), NGFragmentItem::kLine);
+
+ // Descend into the line box.
+ NGFragmentChildIterator iterator2 = iterator1.Descend();
+ fragment_item = iterator2->FragmentItem();
+ ASSERT_TRUE(fragment_item);
+ EXPECT_TRUE(fragment_item->IsText());
+
+ EXPECT_TRUE(iterator2.Advance());
+ const NGPhysicalBoxFragment* fragment = iterator2->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), span1);
+
+ // Descend into children of #span1.
+ NGFragmentChildIterator iterator3 = iterator2.Descend();
+ fragment = iterator3->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), float1);
+
+ EXPECT_TRUE(iterator3.Advance());
+ fragment_item = iterator3->FragmentItem();
+ ASSERT_TRUE(fragment_item);
+ EXPECT_TRUE(fragment_item->IsText());
+ EXPECT_FALSE(iterator3.Advance());
+
+ // Continue with siblings of #span1.
+ EXPECT_TRUE(iterator2.Advance());
+ fragment_item = iterator2->FragmentItem();
+ ASSERT_TRUE(fragment_item);
+ EXPECT_TRUE(fragment_item->IsText());
+
+ EXPECT_FALSE(iterator2.Advance());
+ EXPECT_FALSE(iterator1.Advance());
+}
+
+TEST_F(NGFragmentChildIteratorTest, InlineBlock) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="container">
+ xxx
+ <span id="inlineblock">
+ <div id="float1" style="float:left;"></div>
+ </span>
+ xxx
+ </div>
+ )HTML");
+
+ const LayoutObject* inlineblock = GetLayoutObjectByElementId("inlineblock");
+ const LayoutObject* float1 = GetLayoutObjectByElementId("float1");
+
+ scoped_refptr<const NGPhysicalBoxFragment> container =
+ RunBlockLayoutAlgorithm(GetElementById("container"));
+ NGFragmentChildIterator iterator1(*container.get());
+
+ EXPECT_FALSE(iterator1->BoxFragment());
+ const NGFragmentItem* fragment_item = iterator1->FragmentItem();
+ ASSERT_TRUE(fragment_item);
+ EXPECT_EQ(fragment_item->Type(), NGFragmentItem::kLine);
+
+ // Descend into the line box.
+ NGFragmentChildIterator iterator2 = iterator1.Descend();
+ fragment_item = iterator2->FragmentItem();
+ ASSERT_TRUE(fragment_item);
+ EXPECT_TRUE(fragment_item->IsText());
+
+ EXPECT_TRUE(iterator2.Advance());
+ const NGPhysicalBoxFragment* fragment = iterator2->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), inlineblock);
+
+ // Descend into children of #inlineblock.
+ NGFragmentChildIterator iterator3 = iterator2.Descend();
+ fragment = iterator3->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), float1);
+ EXPECT_FALSE(iterator3.Advance());
+
+ // Continue with siblings of #inlineblock.
+ EXPECT_TRUE(iterator2.Advance());
+ fragment_item = iterator2->FragmentItem();
+ ASSERT_TRUE(fragment_item);
+ EXPECT_TRUE(fragment_item->IsText());
+
+ EXPECT_FALSE(iterator2.Advance());
+ EXPECT_FALSE(iterator1.Advance());
+}
+
+TEST_F(NGFragmentChildIteratorTest, FloatsInInline) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="container">
+ <span id="span1" style="border:solid;">
+ <div id="float1" style="float:left;">
+ <div id="child"></div>
+ </div>
+ </span>
+ </div>
+ )HTML");
+
+ const LayoutObject* span1 = GetLayoutObjectByElementId("span1");
+ const LayoutObject* float1 = GetLayoutObjectByElementId("float1");
+ const LayoutObject* child = GetLayoutObjectByElementId("child");
+
+ scoped_refptr<const NGPhysicalBoxFragment> container =
+ RunBlockLayoutAlgorithm(GetElementById("container"));
+ NGFragmentChildIterator iterator1(*container.get());
+
+ const NGPhysicalBoxFragment* fragment = iterator1->BoxFragment();
+ EXPECT_FALSE(fragment);
+ const NGFragmentItem* item = iterator1->FragmentItem();
+ ASSERT_TRUE(item);
+ EXPECT_EQ(item->Type(), NGFragmentItem::kLine);
+
+ // Descend into the line box.
+ NGFragmentChildIterator iterator2 = iterator1.Descend();
+ fragment = iterator2->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), span1);
+
+ // Descend into children of #span1.
+ NGFragmentChildIterator iterator3 = iterator2.Descend();
+ fragment = iterator3->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), float1);
+
+ // Descend into children of #float1.
+ NGFragmentChildIterator iterator4 = iterator3.Descend();
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), child);
+
+ EXPECT_FALSE(iterator4.Advance());
+ EXPECT_FALSE(iterator3.Advance());
+ EXPECT_FALSE(iterator2.Advance());
+ EXPECT_FALSE(iterator1.Advance());
+}
+
+TEST_F(NGFragmentChildIteratorTest, AbsposAndLine) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="container" style="position:relative;">
+ <div id="abspos" style="position:absolute;"></div>
+ xxx
+ </div>
+ )HTML");
+
+ const LayoutObject* abspos = GetLayoutObjectByElementId("abspos");
+
+ scoped_refptr<const NGPhysicalBoxFragment> container =
+ RunBlockLayoutAlgorithm(GetElementById("container"));
+ NGFragmentChildIterator iterator1(*container.get());
+
+ const NGPhysicalBoxFragment* fragment = iterator1->BoxFragment();
+ EXPECT_FALSE(fragment);
+ const NGFragmentItem* item = iterator1->FragmentItem();
+ ASSERT_TRUE(item);
+ EXPECT_EQ(item->Type(), NGFragmentItem::kLine);
+
+ // Descend into the line box.
+ NGFragmentChildIterator iterator2 = iterator1.Descend();
+
+ fragment = iterator2->BoxFragment();
+ EXPECT_FALSE(fragment);
+ item = iterator2->FragmentItem();
+ ASSERT_TRUE(item);
+ EXPECT_TRUE(item->IsText());
+ EXPECT_FALSE(iterator2.Advance());
+
+ // The abspos is a sibling of the line box.
+ EXPECT_TRUE(iterator1.Advance());
+ fragment = iterator1->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), abspos);
+ EXPECT_FALSE(iterator1.Advance());
+}
+
+TEST_F(NGFragmentChildIteratorTest, BasicMulticol) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="container">
+ <div id="mc" style="columns:3; padding:2px; column-fill:auto; column-gap:10px; width:320px; height:100px;">
+ <div id="child" style="margin-top:30px; margin-left:4px; height:200px;"></div>
+ </div>
+ </div>
+ )HTML");
+
+ const LayoutObject* mc = GetLayoutObjectByElementId("mc");
+ const LayoutObject* child = GetLayoutObjectByElementId("child");
+
+ scoped_refptr<const NGPhysicalBoxFragment> container =
+ RunBlockLayoutAlgorithm(GetElementById("container"));
+ NGFragmentChildIterator iterator(*container.get());
+
+ const NGPhysicalBoxFragment* fragment = iterator->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), mc);
+
+ // First column.
+ NGFragmentChildIterator child_iterator = iterator.Descend();
+ fragment = child_iterator->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_EQ(child_iterator->Link().offset.top, LayoutUnit(2));
+ EXPECT_EQ(child_iterator->Link().offset.left, LayoutUnit(2));
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(100));
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ EXPECT_FALSE(child_iterator->BlockBreakToken());
+
+ NGFragmentChildIterator grandchild_iterator = child_iterator.Descend();
+ fragment = grandchild_iterator->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(grandchild_iterator->Link().offset.top, LayoutUnit(30));
+ EXPECT_EQ(grandchild_iterator->Link().offset.left, LayoutUnit(4));
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(70));
+ EXPECT_EQ(fragment->GetLayoutObject(), child);
+ EXPECT_FALSE(grandchild_iterator.Advance());
+ EXPECT_FALSE(grandchild_iterator->BlockBreakToken());
+
+ // Second column.
+ ASSERT_TRUE(child_iterator.Advance());
+ fragment = child_iterator->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_EQ(child_iterator->Link().offset.top, LayoutUnit(2));
+ EXPECT_EQ(child_iterator->Link().offset.left, LayoutUnit(112));
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(100));
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ const auto* break_token = child_iterator->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(100));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc);
+
+ grandchild_iterator = child_iterator.Descend();
+ fragment = grandchild_iterator->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(grandchild_iterator->Link().offset.top, LayoutUnit(0));
+ EXPECT_EQ(grandchild_iterator->Link().offset.left, LayoutUnit(4));
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(100));
+ EXPECT_EQ(fragment->GetLayoutObject(), child);
+ EXPECT_FALSE(grandchild_iterator.Advance());
+ break_token = grandchild_iterator->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(70));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child);
+
+ // Third column.
+ ASSERT_TRUE(child_iterator.Advance());
+ fragment = child_iterator->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_EQ(child_iterator->Link().offset.top, LayoutUnit(2));
+ EXPECT_EQ(child_iterator->Link().offset.left, LayoutUnit(222));
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(100));
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ break_token = child_iterator->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(200));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc);
+
+ grandchild_iterator = child_iterator.Descend();
+ fragment = grandchild_iterator->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(grandchild_iterator->Link().offset.top, LayoutUnit(0));
+ EXPECT_EQ(grandchild_iterator->Link().offset.left, LayoutUnit(4));
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(30));
+ EXPECT_EQ(fragment->GetLayoutObject(), child);
+ EXPECT_FALSE(grandchild_iterator.Advance());
+ break_token = grandchild_iterator->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(170));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child);
+
+ EXPECT_FALSE(child_iterator.Advance());
+ EXPECT_FALSE(iterator.Advance());
+}
+
+TEST_F(NGFragmentChildIteratorTest, ColumnSpanner) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="container">
+ <div id="mc" style="columns:2;">
+ <div id="child">
+ <div id="grandchild1" style="height:150px;"></div>
+ <div id="spanner" style="column-span:all; height:11px;"></div>
+ <div id="grandchild2" style="height:66px;"></div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+
+ scoped_refptr<const NGPhysicalBoxFragment> container =
+ RunBlockLayoutAlgorithm(GetElementById("container"));
+ NGFragmentChildIterator iterator1(*container.get());
+
+ const LayoutObject* mc = GetLayoutObjectByElementId("mc");
+ const LayoutObject* child = GetLayoutObjectByElementId("child");
+ const LayoutObject* spanner = GetLayoutObjectByElementId("spanner");
+ const LayoutObject* grandchild1 = GetLayoutObjectByElementId("grandchild1");
+ const LayoutObject* grandchild2 = GetLayoutObjectByElementId("grandchild2");
+
+ const NGPhysicalBoxFragment* fragment = iterator1->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), mc);
+
+ // First column before spanner.
+ NGFragmentChildIterator iterator2 = iterator1.Descend();
+ fragment = iterator2->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(75));
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ EXPECT_FALSE(iterator2->BlockBreakToken());
+
+ // First fragment for #child.
+ NGFragmentChildIterator iterator3 = iterator2.Descend();
+ fragment = iterator3->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(75));
+ EXPECT_EQ(fragment->GetLayoutObject(), child);
+ EXPECT_FALSE(iterator3->BlockBreakToken());
+
+ // First fragment for #grandchild1.
+ NGFragmentChildIterator iterator4 = iterator3.Descend();
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(75));
+ EXPECT_EQ(fragment->GetLayoutObject(), grandchild1);
+ EXPECT_FALSE(iterator4->BlockBreakToken());
+ EXPECT_FALSE(iterator4.Advance());
+ EXPECT_FALSE(iterator3.Advance());
+
+ // Second column before spanner.
+ EXPECT_TRUE(iterator2.Advance());
+ fragment = iterator2->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(75));
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ const auto* break_token = iterator2->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(75));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc);
+
+ // Second fragment for #child.
+ iterator3 = iterator2.Descend();
+ fragment = iterator3->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(75));
+ EXPECT_EQ(fragment->GetLayoutObject(), child);
+ break_token = iterator3->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(75));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child);
+
+ // Second fragment for #grandchild1.
+ iterator4 = iterator3.Descend();
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(75));
+ EXPECT_EQ(fragment->GetLayoutObject(), grandchild1);
+ break_token = iterator4->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(75));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), grandchild1);
+ EXPECT_FALSE(iterator4.Advance());
+ EXPECT_FALSE(iterator3.Advance());
+
+ // The spanner.
+ EXPECT_TRUE(iterator2.Advance());
+ fragment = iterator2->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(11));
+ EXPECT_EQ(fragment->GetLayoutObject(), spanner);
+ EXPECT_FALSE(iterator2->BlockBreakToken());
+
+ // First column after spanner.
+ EXPECT_TRUE(iterator2.Advance());
+ fragment = iterator2->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(33));
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ break_token = iterator2->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(150));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc);
+
+ // Third fragment for #child.
+ iterator3 = iterator2.Descend();
+ fragment = iterator3->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(33));
+ EXPECT_EQ(fragment->GetLayoutObject(), child);
+ break_token = iterator3->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(150));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child);
+
+ // First fragment for #grandchild2.
+ iterator4 = iterator3.Descend();
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(33));
+ EXPECT_EQ(fragment->GetLayoutObject(), grandchild2);
+ break_token = iterator4->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_TRUE(break_token->IsBreakBefore());
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), grandchild2);
+ EXPECT_FALSE(iterator4.Advance());
+ EXPECT_FALSE(iterator3.Advance());
+
+ // Second column after spanner.
+ EXPECT_TRUE(iterator2.Advance());
+ fragment = iterator2->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(33));
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ break_token = iterator2->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(183));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc);
+
+ // Fourth fragment for #child.
+ iterator3 = iterator2.Descend();
+ fragment = iterator3->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(33));
+ EXPECT_EQ(fragment->GetLayoutObject(), child);
+ break_token = iterator3->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(183));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child);
+
+ // Second fragment for #grandchild2.
+ iterator4 = iterator3.Descend();
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->Size().height, LayoutUnit(33));
+ EXPECT_EQ(fragment->GetLayoutObject(), grandchild2);
+ break_token = iterator4->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(33));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), grandchild2);
+ EXPECT_FALSE(iterator4.Advance());
+ EXPECT_FALSE(iterator3.Advance());
+
+ EXPECT_FALSE(iterator2.Advance());
+ EXPECT_FALSE(iterator1.Advance());
+}
+
+TEST_F(NGFragmentChildIteratorTest, NestedWithColumnSpanner) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="container">
+ <div id="mc1" style="columns:2; column-fill:auto; height:100px;">
+ <div id="mc2" style="columns:2;">
+ <div id="child1" style="height:150px;"></div>
+ <div id="spanner1" style="column-span:all;">
+ <div id="spanner1child" style="height:55px;"></div>
+ </div>
+ <div id="child2" style="height:50px;"></div>
+ <div id="spanner2" style="column-span:all;">
+ <div id="spanner2child" style="height:20px;"></div>
+ </div>
+ <div id="child3" style="height:20px;"></div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+
+ scoped_refptr<const NGPhysicalBoxFragment> container =
+ RunBlockLayoutAlgorithm(GetElementById("container"));
+ NGFragmentChildIterator iterator1(*container.get());
+
+ const LayoutObject* mc1 = GetLayoutObjectByElementId("mc1");
+ const LayoutObject* mc2 = GetLayoutObjectByElementId("mc2");
+ const LayoutObject* child1 = GetLayoutObjectByElementId("child1");
+ const LayoutObject* child2 = GetLayoutObjectByElementId("child2");
+ const LayoutObject* child3 = GetLayoutObjectByElementId("child3");
+ const LayoutObject* spanner1 = GetLayoutObjectByElementId("spanner1");
+ const LayoutObject* spanner2 = GetLayoutObjectByElementId("spanner2");
+ const LayoutObject* spanner1child =
+ GetLayoutObjectByElementId("spanner1child");
+ const LayoutObject* spanner2child =
+ GetLayoutObjectByElementId("spanner2child");
+
+ const NGPhysicalBoxFragment* fragment = iterator1->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), mc1);
+
+ // First outer column.
+ NGFragmentChildIterator iterator2 = iterator1.Descend();
+ fragment = iterator2->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ EXPECT_FALSE(iterator2->BlockBreakToken());
+
+ // First fragment for #mc2.
+ NGFragmentChildIterator iterator3 = iterator2.Descend();
+ fragment = iterator3->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), mc2);
+ EXPECT_FALSE(iterator3->BlockBreakToken());
+
+ // First inner column in first outer column.
+ NGFragmentChildIterator iterator4 = iterator3.Descend();
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ EXPECT_FALSE(iterator4->BlockBreakToken());
+
+ // First fragment for #child1.
+ NGFragmentChildIterator iterator5 = iterator4.Descend();
+ fragment = iterator5->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), child1);
+ EXPECT_FALSE(iterator5->BlockBreakToken());
+ EXPECT_FALSE(iterator5.Advance());
+
+ // Second inner column in first outer column.
+ EXPECT_TRUE(iterator4.Advance());
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ const auto* break_token = iterator4->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(75));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc2);
+
+ // Second fragment for #child1.
+ iterator5 = iterator4.Descend();
+ fragment = iterator5->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), child1);
+ break_token = iterator5->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(75));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child1);
+
+ // First fragment for #spanner1 (it's split into the first and second outer
+ // columns).
+ EXPECT_TRUE(iterator4.Advance());
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), spanner1);
+ EXPECT_FALSE(iterator4->BlockBreakToken());
+
+ // First fragment for #spanner1child
+ iterator5 = iterator4.Descend();
+ fragment = iterator5->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), spanner1child);
+ EXPECT_FALSE(iterator5->BlockBreakToken());
+ EXPECT_FALSE(iterator5.Advance());
+ EXPECT_FALSE(iterator4.Advance());
+ EXPECT_FALSE(iterator3.Advance());
+
+ // Second outer column
+ EXPECT_TRUE(iterator2.Advance());
+ fragment = iterator2->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ break_token = iterator2->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(100));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc1);
+
+ // Second fragment for #mc2.
+ iterator3 = iterator2.Descend();
+ fragment = iterator3->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), mc2);
+ break_token = iterator3->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(100));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc2);
+
+ // Second fragment for #spanner1 (it's split into the first and second outer
+ // columns).
+ iterator4 = iterator3.Descend();
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), spanner1);
+ break_token = iterator4->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(25));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), spanner1);
+
+ // Second fragment for #spanner1child.
+ iterator5 = iterator4.Descend();
+ fragment = iterator5->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), spanner1child);
+ break_token = iterator5->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(25));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), spanner1child);
+ EXPECT_FALSE(iterator5.Advance());
+
+ // First inner column after first spanner in second outer column.
+ EXPECT_TRUE(iterator4.Advance());
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ break_token = iterator4->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(150));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc2);
+
+ // First fragment for #child2.
+ iterator5 = iterator4.Descend();
+ fragment = iterator5->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), child2);
+ break_token = iterator5->BlockBreakToken();
+ EXPECT_TRUE(break_token);
+ EXPECT_TRUE(break_token->IsBreakBefore());
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child2);
+ EXPECT_FALSE(iterator5.Advance());
+
+ // Second inner column after first spanner in second outer column.
+ EXPECT_TRUE(iterator4.Advance());
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ break_token = iterator4->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(175));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc2);
+
+ // Second fragment for #child2.
+ iterator5 = iterator4.Descend();
+ fragment = iterator5->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), child2);
+ break_token = iterator5->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(25));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child2);
+ EXPECT_FALSE(iterator5.Advance());
+
+ // The only fragment for #spanner2
+ EXPECT_TRUE(iterator4.Advance());
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), spanner2);
+ EXPECT_FALSE(iterator4->BlockBreakToken());
+
+ // First fragment for #spanner2child
+ iterator5 = iterator4.Descend();
+ fragment = iterator5->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), spanner2child);
+ EXPECT_FALSE(iterator5->BlockBreakToken());
+ EXPECT_FALSE(iterator5.Advance());
+
+ // First inner column after second spanner in second outer column.
+ EXPECT_TRUE(iterator4.Advance());
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ break_token = iterator4->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(200));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc2);
+
+ // First fragment for #child3.
+ iterator5 = iterator4.Descend();
+ fragment = iterator5->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), child3);
+ break_token = iterator5->BlockBreakToken();
+ EXPECT_TRUE(break_token);
+ EXPECT_TRUE(break_token->IsBreakBefore());
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child3);
+ EXPECT_FALSE(iterator5.Advance());
+
+ // Second inner column after second spanner in second outer column.
+ EXPECT_TRUE(iterator4.Advance());
+ fragment = iterator4->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_TRUE(fragment->IsColumnBox());
+ EXPECT_FALSE(fragment->GetLayoutObject());
+ break_token = iterator4->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(210));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), mc2);
+
+ // Second fragment for #child3.
+ iterator5 = iterator4.Descend();
+ fragment = iterator5->BoxFragment();
+ ASSERT_TRUE(fragment);
+ EXPECT_EQ(fragment->GetLayoutObject(), child3);
+ break_token = iterator5->BlockBreakToken();
+ ASSERT_TRUE(break_token);
+ EXPECT_EQ(break_token->ConsumedBlockSize(), LayoutUnit(10));
+ EXPECT_EQ(break_token->InputNode().GetLayoutBox(), child3);
+ EXPECT_FALSE(iterator5.Advance());
+ EXPECT_FALSE(iterator4.Advance());
+ EXPECT_FALSE(iterator3.Advance());
+ EXPECT_FALSE(iterator2.Advance());
+ EXPECT_FALSE(iterator1.Advance());
+}
+
+} // anonymous namespace
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_test.cc
new file mode 100644
index 00000000000..a0ddc40690f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_test.cc
@@ -0,0 +1,197 @@
+// Copyright 2020 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/ng/ng_base_layout_algorithm_test.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+
+namespace blink {
+namespace {
+
+class NGFragmentationTest : public NGBaseLayoutAlgorithmTest,
+ private ScopedLayoutNGBlockFragmentationForTest {
+ protected:
+ NGFragmentationTest() : ScopedLayoutNGBlockFragmentationForTest(true) {}
+
+ scoped_refptr<const NGPhysicalBoxFragment> RunBlockLayoutAlgorithm(
+ Element* element) {
+ NGBlockNode container(ToLayoutBox(element->GetLayoutObject()));
+ NGConstraintSpace space = ConstructBlockLayoutTestConstraintSpace(
+ WritingMode::kHorizontalTb, TextDirection::kLtr,
+ LogicalSize(LayoutUnit(1000), kIndefiniteSize));
+ return NGBaseLayoutAlgorithmTest::RunBlockLayoutAlgorithm(container, space);
+ }
+};
+
+TEST_F(NGFragmentationTest, MultipleFragments) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="container">
+ <div style="columns:3; width:620px; column-fill:auto; height:100px; column-gap:10px;">
+ <div id="outer1" style="height:150px;">
+ <div id="inner1" style="height:250px;"></div>
+ <div id="inner2" style="height:10px;"></div>
+ </div>
+ <div id="outer2" style="height:90px;"></div>
+ </div>
+ </div>
+ )HTML");
+
+ RunBlockLayoutAlgorithm(GetElementById("container"));
+ const LayoutBox* outer1 = ToLayoutBox(GetLayoutObjectByElementId("outer1"));
+ const LayoutBox* outer2 = ToLayoutBox(GetLayoutObjectByElementId("outer2"));
+ const LayoutBox* inner1 = ToLayoutBox(GetLayoutObjectByElementId("inner1"));
+ const LayoutBox* inner2 = ToLayoutBox(GetLayoutObjectByElementId("inner2"));
+
+ EXPECT_EQ(outer1->PhysicalFragmentCount(), 3u);
+ EXPECT_EQ(outer2->PhysicalFragmentCount(), 2u);
+ EXPECT_EQ(inner1->PhysicalFragmentCount(), 3u);
+ EXPECT_EQ(inner2->PhysicalFragmentCount(), 1u);
+
+ // While the #outer1 box itself only needs two fragments, we need to create a
+ // third fragment to hold the overflowing children in the third column.
+ EXPECT_EQ(outer1->GetPhysicalFragment(0)->Size(), PhysicalSize(200, 100));
+ EXPECT_EQ(outer1->GetPhysicalFragment(1)->Size(), PhysicalSize(200, 50));
+ EXPECT_EQ(outer1->GetPhysicalFragment(2)->Size(), PhysicalSize(200, 0));
+
+ // #inner1 overflows its parent and uses three columns.
+ EXPECT_EQ(inner1->GetPhysicalFragment(0)->Size(), PhysicalSize(200, 100));
+ EXPECT_EQ(inner1->GetPhysicalFragment(1)->Size(), PhysicalSize(200, 100));
+ EXPECT_EQ(inner1->GetPhysicalFragment(2)->Size(), PhysicalSize(200, 50));
+
+ // #inner2 is tiny, and only needs some space in one column (the third one).
+ EXPECT_EQ(inner2->GetPhysicalFragment(0)->Size(), PhysicalSize(200, 10));
+
+ // #outer2 starts in the second column and ends in the third.
+ EXPECT_EQ(outer2->GetPhysicalFragment(0)->Size(), PhysicalSize(200, 50));
+ EXPECT_EQ(outer2->GetPhysicalFragment(1)->Size(), PhysicalSize(200, 40));
+}
+
+TEST_F(NGFragmentationTest, MultipleFragmentsAndColumnSpanner) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="container">
+ <div id="multicol" style="columns:3; width:620px; column-gap:10px; orphans:1; widows:1; line-height:20px;">
+ <div id="outer">
+ <div id="inner1"><br><br><br><br></div>
+ <div id="spanner1" style="column-span:all;"></div>
+ <div id="inner2"><br><br><br><br><br></div>
+ <div id="spanner2" style="column-span:all;"></div>
+ <div id="inner3"><br><br><br><br><br><br><br></div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+
+ RunBlockLayoutAlgorithm(GetElementById("container"));
+ const LayoutBox* multicol =
+ ToLayoutBox(GetLayoutObjectByElementId("multicol"));
+ const LayoutBox* outer = ToLayoutBox(GetLayoutObjectByElementId("outer"));
+ const LayoutBox* inner1 = ToLayoutBox(GetLayoutObjectByElementId("inner1"));
+ const LayoutBox* inner2 = ToLayoutBox(GetLayoutObjectByElementId("inner2"));
+ const LayoutBox* inner3 = ToLayoutBox(GetLayoutObjectByElementId("inner3"));
+ const LayoutBox* spanner1 =
+ ToLayoutBox(GetLayoutObjectByElementId("spanner1"));
+ const LayoutBox* spanner2 =
+ ToLayoutBox(GetLayoutObjectByElementId("spanner2"));
+
+ EXPECT_EQ(multicol->PhysicalFragmentCount(), 1u);
+
+ // #outer will create 8 fragments: 2 for the 2 columns before the first
+ // spanner, 3 for the 3 columns between the two spanners, and 3 for the 3
+ // columns after the last spanner.
+ EXPECT_EQ(outer->PhysicalFragmentCount(), 8u);
+
+ // #inner1 has 4 lines split into 2 columns.
+ EXPECT_EQ(inner1->PhysicalFragmentCount(), 2u);
+
+ // #inner2 has 5 lines split into 3 columns.
+ EXPECT_EQ(inner2->PhysicalFragmentCount(), 3u);
+
+ // #inner3 has 8 lines split into 3 columns.
+ EXPECT_EQ(inner3->PhysicalFragmentCount(), 3u);
+
+ EXPECT_EQ(spanner1->PhysicalFragmentCount(), 1u);
+ EXPECT_EQ(spanner2->PhysicalFragmentCount(), 1u);
+
+ EXPECT_EQ(multicol->GetPhysicalFragment(0)->Size(), PhysicalSize(620, 140));
+ EXPECT_EQ(outer->GetPhysicalFragment(0)->Size(), PhysicalSize(200, 40));
+ EXPECT_EQ(outer->GetPhysicalFragment(1)->Size(), PhysicalSize(200, 40));
+ EXPECT_EQ(outer->GetPhysicalFragment(2)->Size(), PhysicalSize(200, 40));
+ EXPECT_EQ(outer->GetPhysicalFragment(3)->Size(), PhysicalSize(200, 40));
+ EXPECT_EQ(outer->GetPhysicalFragment(4)->Size(), PhysicalSize(200, 20));
+ EXPECT_EQ(outer->GetPhysicalFragment(5)->Size(), PhysicalSize(200, 60));
+ EXPECT_EQ(outer->GetPhysicalFragment(6)->Size(), PhysicalSize(200, 60));
+ EXPECT_EQ(outer->GetPhysicalFragment(7)->Size(), PhysicalSize(200, 20));
+ EXPECT_EQ(inner1->GetPhysicalFragment(0)->Size(), PhysicalSize(200, 40));
+ EXPECT_EQ(inner1->GetPhysicalFragment(1)->Size(), PhysicalSize(200, 40));
+ EXPECT_EQ(inner2->GetPhysicalFragment(0)->Size(), PhysicalSize(200, 40));
+ EXPECT_EQ(inner2->GetPhysicalFragment(1)->Size(), PhysicalSize(200, 40));
+ EXPECT_EQ(inner2->GetPhysicalFragment(2)->Size(), PhysicalSize(200, 20));
+ EXPECT_EQ(inner3->GetPhysicalFragment(0)->Size(), PhysicalSize(200, 60));
+ EXPECT_EQ(inner3->GetPhysicalFragment(1)->Size(), PhysicalSize(200, 60));
+ EXPECT_EQ(inner3->GetPhysicalFragment(2)->Size(), PhysicalSize(200, 20));
+ EXPECT_EQ(spanner1->GetPhysicalFragment(0)->Size(), PhysicalSize(620, 0));
+ EXPECT_EQ(spanner2->GetPhysicalFragment(0)->Size(), PhysicalSize(620, 0));
+}
+
+TEST_F(NGFragmentationTest, MultipleFragmentsNestedMulticol) {
+ SetBodyInnerHTML(R"HTML(
+ <div id="container">
+ <div id="outer_multicol" style="columns:3; column-fill:auto; height:100px; width:620px; column-gap:10px;">
+ <div id="inner_multicol" style="columns:2;">
+ <div id="child1" style="width:11px; height:350px;"></div>
+ <div id="child2" style="width:22px; height:350px;"></div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+
+ RunBlockLayoutAlgorithm(GetElementById("container"));
+ const LayoutBox* outer_multicol =
+ ToLayoutBox(GetLayoutObjectByElementId("outer_multicol"));
+ const LayoutBox* inner_multicol =
+ ToLayoutBox(GetLayoutObjectByElementId("inner_multicol"));
+ const LayoutBox* child1 = ToLayoutBox(GetLayoutObjectByElementId("child1"));
+ const LayoutBox* child2 = ToLayoutBox(GetLayoutObjectByElementId("child2"));
+
+ EXPECT_EQ(outer_multicol->PhysicalFragmentCount(), 1u);
+
+ // The content is too tall (350px + 350px, column height 100px, 2*3 columns =
+ // 600px) and will use one more column than we have specified.
+ EXPECT_EQ(inner_multicol->PhysicalFragmentCount(), 4u);
+
+ // 350px tall content with a column height of 100px will require 4 fragments.
+ EXPECT_EQ(child1->PhysicalFragmentCount(), 4u);
+ EXPECT_EQ(child2->PhysicalFragmentCount(), 4u);
+
+ EXPECT_EQ(outer_multicol->GetPhysicalFragment(0)->Size(),
+ PhysicalSize(620, 100));
+
+ EXPECT_EQ(inner_multicol->GetPhysicalFragment(0)->Size(),
+ PhysicalSize(200, 100));
+ EXPECT_EQ(inner_multicol->GetPhysicalFragment(1)->Size(),
+ PhysicalSize(200, 100));
+ EXPECT_EQ(inner_multicol->GetPhysicalFragment(2)->Size(),
+ PhysicalSize(200, 100));
+ EXPECT_EQ(inner_multicol->GetPhysicalFragment(3)->Size(),
+ PhysicalSize(200, 100));
+
+ // #child1 starts at the beginning of a column, so the last fragment will be
+ // shorter than the rest.
+ EXPECT_EQ(child1->GetPhysicalFragment(0)->Size(), PhysicalSize(11, 100));
+ EXPECT_EQ(child1->GetPhysicalFragment(1)->Size(), PhysicalSize(11, 100));
+ EXPECT_EQ(child1->GetPhysicalFragment(2)->Size(), PhysicalSize(11, 100));
+ EXPECT_EQ(child1->GetPhysicalFragment(3)->Size(), PhysicalSize(11, 50));
+
+ // #child2 starts in the middle of a column, so the first fragment will be
+ // shorter than the rest.
+ EXPECT_EQ(child2->GetPhysicalFragment(0)->Size(), PhysicalSize(22, 50));
+ EXPECT_EQ(child2->GetPhysicalFragment(1)->Size(), PhysicalSize(22, 100));
+ EXPECT_EQ(child2->GetPhysicalFragment(2)->Size(), PhysicalSize(22, 100));
+ EXPECT_EQ(child2->GetPhysicalFragment(3)->Size(), PhysicalSize(22, 100));
+}
+
+} // anonymous namespace
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
index 72a107d1f7b..327212ca3a8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.cc
@@ -164,11 +164,20 @@ NGBreakAppeal CalculateBreakAppealInside(const NGConstraintSpace& space,
}
void SetupFragmentation(const NGConstraintSpace& parent_space,
+ const NGLayoutInputNode& child,
LayoutUnit fragmentainer_offset_delta,
NGConstraintSpaceBuilder* builder,
bool is_new_fc) {
DCHECK(parent_space.HasBlockFragmentation());
+ // If the child is truly unbreakable, it won't participate in block
+ // fragmentation. If it's too tall to fit, it will either overflow the
+ // fragmentainer or get brutally sliced into pieces (without looking for
+ // allowed breakpoints, since there are none, by definition), depending on
+ // fragmentation type (multicol vs. printing).
+ if (child.IsMonolithic())
+ return;
+
builder->SetFragmentainerBlockSize(parent_space.FragmentainerBlockSize());
builder->SetFragmentainerOffsetAtBfc(parent_space.FragmentainerOffsetAtBfc() +
fragmentainer_offset_delta);
@@ -179,11 +188,20 @@ void SetupFragmentation(const NGConstraintSpace& parent_space,
}
void FinishFragmentation(const NGConstraintSpace& space,
+ const NGBlockBreakToken* previous_break_token,
LayoutUnit block_size,
LayoutUnit intrinsic_block_size,
- LayoutUnit previously_consumed_block_size,
LayoutUnit space_left,
NGBoxFragmentBuilder* builder) {
+ LayoutUnit previously_consumed_block_size;
+ unsigned sequence_number = 0;
+ if (previous_break_token && !previous_break_token->IsBreakBefore()) {
+ previously_consumed_block_size = previous_break_token->ConsumedBlockSize();
+ sequence_number = previous_break_token->SequenceNumber() + 1;
+ builder->SetIsFirstForNode(false);
+ }
+ builder->SetSequenceNumber(sequence_number);
+
if (builder->DidBreak()) {
// One of our children broke. Even if we fit within the remaining space, we
// need to prepare a break token.
@@ -271,11 +289,13 @@ void BreakBeforeChild(const NGConstraintSpace& space,
bool is_forced_break,
NGBoxFragmentBuilder* builder) {
#if DCHECK_IS_ON()
- // In order to successfully break before a node, this has to be its first
- // fragment.
- const auto& physical_fragment = layout_result.PhysicalFragment();
- DCHECK(!physical_fragment.IsBox() ||
- To<NGPhysicalBoxFragment>(physical_fragment).IsFirstForNode());
+ if (layout_result.Status() == NGLayoutResult::kSuccess) {
+ // In order to successfully break before a node, this has to be its first
+ // fragment.
+ const auto& physical_fragment = layout_result.PhysicalFragment();
+ DCHECK(!physical_fragment.IsBox() ||
+ To<NGPhysicalBoxFragment>(physical_fragment).IsFirstForNode());
+ }
#endif
// Report space shortage. Note that we're not doing this for line boxes here
@@ -310,7 +330,10 @@ void PropagateSpaceShortage(const NGConstraintSpace& space,
LayoutUnit space_shortage;
if (layout_result.MinimalSpaceShortage() == LayoutUnit::Max()) {
// Calculate space shortage: Figure out how much more space would have been
- // sufficient to make the child fit right here in the current fragment.
+ // sufficient to make the child fragment fit right here in the current
+ // fragmentainer. If layout aborted, though, we can't propagate anything.
+ if (layout_result.Status() != NGLayoutResult::kSuccess)
+ return;
NGFragment fragment(space.GetWritingMode(),
layout_result.PhysicalFragment());
space_shortage = fragmentainer_block_offset + fragment.BlockSize() -
@@ -335,6 +358,13 @@ bool MovePastBreakpoint(const NGConstraintSpace& space,
LayoutUnit fragmentainer_block_offset,
NGBreakAppeal appeal_before,
NGBoxFragmentBuilder* builder) {
+ if (layout_result.Status() != NGLayoutResult::kSuccess) {
+ // Layout aborted - no fragment was produced. There's nothing to move
+ // past. We need to break before.
+ DCHECK_EQ(layout_result.Status(), NGLayoutResult::kOutOfFragmentainerSpace);
+ return false;
+ }
+
const auto& physical_fragment = layout_result.PhysicalFragment();
NGFragment fragment(space.GetWritingMode(), physical_fragment);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
index 3f0f844f3a1..48ca63e28a5 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragmentation_utils.h
@@ -6,6 +6,8 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_FRAGMENTATION_UTILS_H_
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment_builder.h"
@@ -45,6 +47,14 @@ inline bool IsResumingLayout(const NGBlockBreakToken* token) {
return token && !token->IsBreakBefore();
}
+// Return true if the fragment to be generated for the specified item is going
+// to be the first fragment for the node.
+inline bool IsFirstForNode(const NGInlineItem& item,
+ const NGInlineBreakToken* token) {
+ return item.IsFirstForNode() &&
+ (!token || item.StartOffset() >= token->TextOffset());
+}
+
// Calculate the final "break-between" value at a class A or C breakpoint. This
// is the combination of all break-before and break-after values that met at the
// breakpoint.
@@ -93,15 +103,16 @@ inline void AdjustForFragmentation(const NGBlockBreakToken* break_token,
// formatting context starts in a previous fragmentainer; the offset from the
// current fragmentainer block-start.
void SetupFragmentation(const NGConstraintSpace& parent_space,
+ const NGLayoutInputNode& child,
LayoutUnit fragmentainer_offset_delta,
NGConstraintSpaceBuilder*,
bool is_new_fc);
// Write fragmentation information to the fragment builder after layout.
void FinishFragmentation(const NGConstraintSpace&,
+ const NGBlockBreakToken* previous_break_token,
LayoutUnit block_size,
LayoutUnit intrinsic_block_size,
- LayoutUnit previously_consumed_block_size,
LayoutUnit space_left,
NGBoxFragmentBuilder*);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h
index 2ef8605d97e..b04949398e8 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h
@@ -7,7 +7,7 @@
#include "base/optional.h"
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
@@ -17,7 +17,7 @@ namespace blink {
class ComputedStyle;
class NGEarlyBreak;
class NGLayoutResult;
-struct MinMaxSizeInput;
+struct MinMaxSizesInput;
// Operations provided by a layout algorithm.
class NGLayoutAlgorithmOperations {
@@ -33,8 +33,8 @@ class NGLayoutAlgorithmOperations {
// account. If the return value is empty, the caller is expected to synthesize
// this value from the overflow rect returned from Layout called with an
// available width of 0 and LayoutUnit::max(), respectively.
- virtual base::Optional<MinMaxSize> ComputeMinMaxSize(
- const MinMaxSizeInput&) const {
+ virtual base::Optional<MinMaxSizes> ComputeMinMaxSizes(
+ const MinMaxSizesInput&) const {
return base::nullopt;
}
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
index f46d17d48d1..28d5bcce744 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc
@@ -8,9 +8,8 @@
#include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
#include "third_party/blink/renderer/core/layout/layout_replaced.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
-#include "third_party/blink/renderer/core/layout/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
@@ -61,39 +60,23 @@ void AppendNodeToString(NGLayoutInputNode node,
} // namespace
-MinMaxSize NGLayoutInputNode::ComputeMinMaxSize(
+MinMaxSizes NGLayoutInputNode::ComputeMinMaxSizes(
WritingMode writing_mode,
- const MinMaxSizeInput& input,
+ const MinMaxSizesInput& input,
const NGConstraintSpace* space) {
if (auto* inline_node = DynamicTo<NGInlineNode>(this))
- return inline_node->ComputeMinMaxSize(writing_mode, input, space);
- return To<NGBlockNode>(*this).ComputeMinMaxSize(writing_mode, input, space);
+ return inline_node->ComputeMinMaxSizes(writing_mode, input, space);
+ return To<NGBlockNode>(*this).ComputeMinMaxSizes(writing_mode, input, space);
}
void NGLayoutInputNode::IntrinsicSize(
base::Optional<LayoutUnit>* computed_inline_size,
- base::Optional<LayoutUnit>* computed_block_size,
- LogicalSize* aspect_ratio) const {
+ base::Optional<LayoutUnit>* computed_block_size) const {
DCHECK(IsReplaced());
- LayoutUnit override_inline_size = OverrideIntrinsicContentInlineSize();
- if (override_inline_size != kIndefiniteSize)
- *computed_inline_size = override_inline_size;
-
- LayoutUnit override_block_size = OverrideIntrinsicContentBlockSize();
- if (override_block_size != kIndefiniteSize)
- *computed_block_size = override_block_size;
-
- if (ShouldApplySizeContainment()) {
- if (!*computed_inline_size)
- *computed_inline_size = LayoutUnit();
- if (!*computed_block_size)
- *computed_block_size = LayoutUnit();
- }
- if (*computed_inline_size && *computed_block_size) {
- *aspect_ratio = LogicalSize(**computed_inline_size, **computed_block_size);
+ GetOverrideIntrinsicSize(computed_inline_size, computed_block_size);
+ if (*computed_inline_size && *computed_block_size)
return;
- }
IntrinsicSizingInfo legacy_sizing_info;
@@ -102,9 +85,6 @@ void NGLayoutInputNode::IntrinsicSize(
*computed_inline_size = LayoutUnit(legacy_sizing_info.size.Width());
if (!*computed_block_size && legacy_sizing_info.has_height)
*computed_block_size = LayoutUnit(legacy_sizing_info.size.Height());
- *aspect_ratio =
- LogicalSize(LayoutUnit(legacy_sizing_info.aspect_ratio.Width()),
- LayoutUnit(legacy_sizing_info.aspect_ratio.Height()));
}
NGLayoutInputNode NGLayoutInputNode::NextSibling() {
@@ -134,8 +114,39 @@ void NGLayoutInputNode::ShowNodeTree() const {
StringBuilder string_builder;
string_builder.Append(".:: LayoutNG Node Tree ::.\n");
AppendNodeToString(*this, &string_builder);
- fprintf(stderr, "%s\n", string_builder.ToString().Utf8().c_str());
+ DLOG(INFO) << "\n" << string_builder.ToString().Utf8();
}
#endif
+void NGLayoutInputNode::GetOverrideIntrinsicSize(
+ base::Optional<LayoutUnit>* computed_inline_size,
+ base::Optional<LayoutUnit>* computed_block_size) const {
+ DCHECK(IsReplaced());
+
+ LayoutUnit override_inline_size = OverrideIntrinsicContentInlineSize();
+ if (override_inline_size != kIndefiniteSize) {
+ *computed_inline_size = override_inline_size;
+ } else {
+ LayoutUnit default_inline_size = DefaultIntrinsicContentInlineSize();
+ if (default_inline_size != kIndefiniteSize)
+ *computed_inline_size = default_inline_size;
+ }
+
+ LayoutUnit override_block_size = OverrideIntrinsicContentBlockSize();
+ if (override_block_size != kIndefiniteSize) {
+ *computed_block_size = override_block_size;
+ } else {
+ LayoutUnit default_block_size = DefaultIntrinsicContentBlockSize();
+ if (default_block_size != kIndefiniteSize)
+ *computed_block_size = default_block_size;
+ }
+
+ if (ShouldApplySizeContainment()) {
+ if (!*computed_inline_size)
+ *computed_inline_size = LayoutUnit();
+ if (!*computed_block_size)
+ *computed_block_size = LayoutUnit();
+ }
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
index c77e16c4310..45acfcb0f7c 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h
@@ -11,7 +11,7 @@
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/ng/layout_box_utils.h"
-#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker.h"
+#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_outside_list_marker.h"
#include "third_party/blink/renderer/platform/geometry/layout_unit.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
@@ -24,16 +24,13 @@ class LayoutObject;
class LayoutBox;
class NGConstraintSpace;
class NGPaintFragment;
-struct MinMaxSize;
-struct LogicalSize;
+struct MinMaxSizes;
struct PhysicalSize;
-enum class NGMinMaxSizeType { kContentBoxSize, kBorderBoxSize };
-
// Input to the min/max inline size calculation algorithm for child nodes. Child
// nodes within the same formatting context need to know which floats are beside
// them.
-struct MinMaxSizeInput {
+struct MinMaxSizesInput {
// The min-max size calculation (un-intuitively) requires a percentage
// resolution size!
// This occurs when a replaced element has an intrinsic size. E.g.
@@ -44,14 +41,11 @@ struct MinMaxSizeInput {
//
// As we don't perform any tree walking, we need to pass the percentage
// resolution block-size for min/max down the min/max size calculation.
- explicit MinMaxSizeInput(LayoutUnit percentage_resolution_block_size)
+ explicit MinMaxSizesInput(LayoutUnit percentage_resolution_block_size)
: percentage_resolution_block_size(percentage_resolution_block_size) {}
LayoutUnit float_left_inline_size;
LayoutUnit float_right_inline_size;
LayoutUnit percentage_resolution_block_size;
-
- // Whether to return the size as a content-box size or border-box size.
- NGMinMaxSizeType size_type = NGMinMaxSizeType::kBorderBoxSize;
};
// Represents the input to a layout algorithm for a given node. The layout
@@ -108,11 +102,11 @@ class CORE_EXPORT NGLayoutInputNode {
}
bool IsListItem() const { return IsBlock() && box_->IsLayoutNGListItem(); }
bool IsListMarker() const {
- return IsBlock() && box_->IsLayoutNGListMarker();
+ return IsBlock() && box_->IsLayoutNGOutsideListMarker();
}
bool ListMarkerOccupiesWholeLine() const {
DCHECK(IsListMarker());
- return ToLayoutNGListMarker(box_)->NeedsOccupyWholeLine();
+ return ToLayoutNGOutsideListMarker(box_)->NeedsOccupyWholeLine();
}
bool IsFieldsetContainer() const {
return IsBlock() && box_->IsLayoutNGFieldset();
@@ -123,6 +117,9 @@ class CORE_EXPORT NGLayoutInputNode {
bool IsRenderedLegend() const {
return IsBlock() && box_->IsRenderedLegend();
}
+ bool IsTable() const { return IsBlock() && box_->IsTable(); }
+
+ bool IsMathRoot() const { return box_->IsMathMLRoot(); }
bool IsAnonymousBlock() const { return box_->IsAnonymousBlock(); }
@@ -159,16 +156,16 @@ class CORE_EXPORT NGLayoutInputNode {
}
// Returns border box.
- MinMaxSize ComputeMinMaxSize(WritingMode,
- const MinMaxSizeInput&,
- const NGConstraintSpace* = nullptr);
+ MinMaxSizes ComputeMinMaxSizes(WritingMode,
+ const MinMaxSizesInput&,
+ const NGConstraintSpace* = nullptr);
// Returns intrinsic sizing information for replaced elements.
// ComputeReplacedSize can use it to compute actual replaced size.
// Corresponds to Legacy's LayoutReplaced::IntrinsicSizingInfo.
+ // Use NGBlockNode::GetAspectRatio to get the aspect ratio.
void IntrinsicSize(base::Optional<LayoutUnit>* computed_inline_size,
- base::Optional<LayoutUnit>* computed_block_size,
- LogicalSize* aspect_ratio) const;
+ base::Optional<LayoutUnit>* computed_block_size) const;
// Returns the next sibling.
NGLayoutInputNode NextSibling();
@@ -201,6 +198,13 @@ class CORE_EXPORT NGLayoutInputNode {
return kIndefiniteSize;
}
+ LayoutUnit DefaultIntrinsicContentInlineSize() const {
+ return box_->DefaultIntrinsicContentInlineSize();
+ }
+ LayoutUnit DefaultIntrinsicContentBlockSize() const {
+ return box_->DefaultIntrinsicContentBlockSize();
+ }
+
// Display locking functionality.
const DisplayLockContext& GetDisplayLockContext() const {
DCHECK(box_->GetDisplayLockContext());
@@ -240,6 +244,10 @@ class CORE_EXPORT NGLayoutInputNode {
NGLayoutInputNode(LayoutBox* box, NGLayoutInputNodeType type)
: box_(box), type_(type) {}
+ void GetOverrideIntrinsicSize(
+ base::Optional<LayoutUnit>* computed_inline_size,
+ base::Optional<LayoutUnit>* computed_block_size) const;
+
LayoutBox* box_;
unsigned type_ : 1; // NGLayoutInputNodeType
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
index fac77834d22..6dc8f994eee 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc
@@ -39,6 +39,7 @@ static_assert(sizeof(NGLayoutResult) == sizeof(SameSizeAsNGLayoutResult),
} // namespace
NGLayoutResult::NGLayoutResult(
+ NGBoxFragmentBuilderPassKey passkey,
scoped_refptr<const NGPhysicalContainerFragment> physical_fragment,
NGBoxFragmentBuilder* builder)
: NGLayoutResult(std::move(physical_fragment),
@@ -48,6 +49,10 @@ NGLayoutResult::NGLayoutResult(
bitfields_.subtree_modified_margin_strut =
builder->subtree_modified_margin_strut_;
intrinsic_block_size_ = builder->intrinsic_block_size_;
+ // We don't support fragment caching when block-fragmenting, so mark the
+ // result as non-reusable.
+ if (builder->has_block_fragmentation_)
+ EnsureRareData()->is_single_use = true;
if (builder->minimal_space_shortage_ != LayoutUnit::Max()) {
#if DCHECK_IS_ON()
DCHECK(!HasRareData() || !rare_data_->has_tallest_unbreakable_block_size);
@@ -62,10 +67,9 @@ NGLayoutResult::NGLayoutResult(
rare_data->has_tallest_unbreakable_block_size = true;
#endif
}
- if (builder->unconstrained_intrinsic_block_size_ != kIndefiniteSize &&
- builder->unconstrained_intrinsic_block_size_ != intrinsic_block_size_) {
- EnsureRareData()->unconstrained_intrinsic_block_size_ =
- builder->unconstrained_intrinsic_block_size_;
+ if (builder->overflow_block_size_ != kIndefiniteSize &&
+ builder->overflow_block_size_ != intrinsic_block_size_) {
+ EnsureRareData()->overflow_block_size_ = builder->overflow_block_size_;
}
if (builder->custom_layout_data_) {
EnsureRareData()->custom_layout_data =
@@ -73,6 +77,8 @@ NGLayoutResult::NGLayoutResult(
}
if (builder->column_spanner_)
EnsureRareData()->column_spanner = builder->column_spanner_;
+ if (builder->lines_until_clamp_)
+ EnsureRareData()->lines_until_clamp = *builder->lines_until_clamp_;
bitfields_.initial_break_before =
static_cast<unsigned>(builder->initial_break_before_);
bitfields_.final_break_after =
@@ -81,15 +87,20 @@ NGLayoutResult::NGLayoutResult(
}
NGLayoutResult::NGLayoutResult(
+ NGLineBoxFragmentBuilderPassKey passkey,
scoped_refptr<const NGPhysicalContainerFragment> physical_fragment,
NGLineBoxFragmentBuilder* builder)
: NGLayoutResult(std::move(physical_fragment),
static_cast<NGContainerFragmentBuilder*>(builder)) {}
-NGLayoutResult::NGLayoutResult(EStatus status, NGBoxFragmentBuilder* builder)
+NGLayoutResult::NGLayoutResult(NGBoxFragmentBuilderPassKey key,
+ EStatus status,
+ NGBoxFragmentBuilder* builder)
: NGLayoutResult(/* physical_fragment */ nullptr,
static_cast<NGContainerFragmentBuilder*>(builder)) {
bitfields_.status = status;
+ if (builder->lines_until_clamp_)
+ EnsureRareData()->lines_until_clamp = *builder->lines_until_clamp_;
DCHECK_NE(status, kSuccess)
<< "Use the other constructor for successful layout";
}
@@ -152,7 +163,7 @@ NGLayoutResult::NGLayoutResult(
#if DCHECK_IS_ON()
if (bitfields_.is_self_collapsing && physical_fragment_) {
// A new formatting-context shouldn't be self-collapsing.
- DCHECK(!physical_fragment_->IsBlockFormattingContextRoot());
+ DCHECK(!physical_fragment_->IsFormattingContextRoot());
// Self-collapsing children must have a block-size of zero.
NGFragment fragment(physical_fragment_->Style().GetWritingMode(),
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
index 77ff5c5b9b9..3faf3aa43aa 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h
@@ -41,6 +41,8 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
kSuccess = 0,
kBfcBlockOffsetResolved = 1,
kNeedsEarlierBreak = 2,
+ kOutOfFragmentainerSpace = 3,
+ kNeedsRelayoutWithNoForcedTruncateAtLineClamp = 4,
// When adding new values, make sure the bit size of |Bitfields::status| is
// large enough to store.
};
@@ -62,6 +64,10 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
return *physical_fragment_;
}
+ int LinesUntilClamp() const {
+ return HasRareData() ? rare_data_->lines_until_clamp : 0;
+ }
+
LogicalOffset OutOfFlowPositionedOffset() const {
DCHECK(bitfields_.has_oof_positioned_offset);
return HasRareData() ? rare_data_->oof_positioned_offset
@@ -140,16 +146,13 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
}
const LayoutUnit IntrinsicBlockSize() const {
- DCHECK(physical_fragment_->Type() == NGPhysicalFragment::kFragmentBox ||
- physical_fragment_->Type() ==
- NGPhysicalFragment::kFragmentRenderedLegend);
+ DCHECK(physical_fragment_->IsBox());
return intrinsic_block_size_;
}
- LayoutUnit UnconstrainedIntrinsicBlockSize() const {
- return HasRareData() && rare_data_->unconstrained_intrinsic_block_size_ !=
- kIndefiniteSize
- ? rare_data_->unconstrained_intrinsic_block_size_
+ LayoutUnit OverflowBlockSize() const {
+ return HasRareData() && rare_data_->overflow_block_size_ != kIndefiniteSize
+ ? rare_data_->overflow_block_size_
: intrinsic_block_size_;
}
@@ -173,6 +176,14 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
return rare_data_->tallest_unbreakable_block_size;
}
+ // Return whether this result is single-use only (true), or if it is allowed
+ // to be involved in cache hits in future layout passes (false).
+ // For example, this happens when a block is fragmented, since we don't yet
+ // support caching of block-fragmented results.
+ bool IsSingleUse() const {
+ return HasRareData() && rare_data_->is_single_use;
+ }
+
SerializedScriptValue* CustomLayoutData() const {
return HasRareData() ? rare_data_->custom_layout_data.get() : nullptr;
}
@@ -285,21 +296,24 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
bool check_same_block_size = true) const;
#endif
- private:
- friend class NGBoxFragmentBuilder;
- friend class NGLineBoxFragmentBuilder;
- friend class MutableForOutOfFlow;
-
+ using NGBoxFragmentBuilderPassKey = util::PassKey<NGBoxFragmentBuilder>;
+ // This constructor is for a non-success status.
+ NGLayoutResult(NGBoxFragmentBuilderPassKey, EStatus, NGBoxFragmentBuilder*);
// This constructor requires a non-null fragment and sets a success status.
NGLayoutResult(
+ NGBoxFragmentBuilderPassKey,
scoped_refptr<const NGPhysicalContainerFragment> physical_fragment,
NGBoxFragmentBuilder*);
+ using NGLineBoxFragmentBuilderPassKey =
+ util::PassKey<NGLineBoxFragmentBuilder>;
// This constructor requires a non-null fragment and sets a success status.
NGLayoutResult(
+ NGLineBoxFragmentBuilderPassKey,
scoped_refptr<const NGPhysicalContainerFragment> physical_fragment,
NGLineBoxFragmentBuilder*);
- // This constructor is for a non-success status.
- NGLayoutResult(EStatus, NGBoxFragmentBuilder*);
+
+ private:
+ friend class MutableForOutOfFlow;
// We don't need the copy constructor, move constructor, copy
// assigmnment-operator, or move assignment-operator today.
@@ -358,10 +372,12 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
};
NGExclusionSpace exclusion_space;
scoped_refptr<SerializedScriptValue> custom_layout_data;
- LayoutUnit unconstrained_intrinsic_block_size_ = kIndefiniteSize;
+ LayoutUnit overflow_block_size_ = kIndefiniteSize;
#if DCHECK_IS_ON()
bool has_tallest_unbreakable_block_size = false;
#endif
+ bool is_single_use = false;
+ int lines_until_clamp = 0;
};
bool HasRareData() const { return bitfields_.has_rare_data; }
@@ -421,7 +437,7 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
unsigned initial_break_before : 4; // EBreakBetween
unsigned final_break_after : 4; // EBreakBetween
- unsigned status : 2; // EStatus
+ unsigned status : 3; // EStatus
};
// The constraint space which generated this layout result, may not be valid
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc
index 107e1cc3dc8..24df10ed942 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result_caching_test.cc
@@ -19,8 +19,6 @@ namespace {
class NGLayoutResultCachingTest : public NGLayoutTest {};
TEST_F(NGLayoutResultCachingTest, HitDifferentExclusionSpace) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Same BFC offset, different exclusion space.
SetBodyInnerHTML(R"HTML(
<style>
@@ -58,8 +56,6 @@ TEST_F(NGLayoutResultCachingTest, HitDifferentExclusionSpace) {
}
TEST_F(NGLayoutResultCachingTest, HitDifferentBFCOffset) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Different BFC offset, same exclusion space.
SetBodyInnerHTML(R"HTML(
<style>
@@ -123,8 +119,6 @@ TEST_F(NGLayoutResultCachingTest, HitDifferentBFCOffset) {
}
TEST_F(NGLayoutResultCachingTest, HitDifferentBFCOffsetSameMarginStrut) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Different BFC offset, same margin-strut.
SetBodyInnerHTML(R"HTML(
<style>
@@ -155,8 +149,6 @@ TEST_F(NGLayoutResultCachingTest, HitDifferentBFCOffsetSameMarginStrut) {
}
TEST_F(NGLayoutResultCachingTest, MissDescendantAboveBlockStart1) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Same BFC offset, different exclusion space, descendant above
// block start.
SetBodyInnerHTML(R"HTML(
@@ -195,8 +187,6 @@ TEST_F(NGLayoutResultCachingTest, MissDescendantAboveBlockStart1) {
}
TEST_F(NGLayoutResultCachingTest, MissDescendantAboveBlockStart2) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Different BFC offset, same exclusion space, descendant above
// block start.
SetBodyInnerHTML(R"HTML(
@@ -235,8 +225,6 @@ TEST_F(NGLayoutResultCachingTest, MissDescendantAboveBlockStart2) {
}
TEST_F(NGLayoutResultCachingTest, HitOOFDescendantAboveBlockStart) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Different BFC offset, same exclusion space, OOF-descendant above
// block start.
SetBodyInnerHTML(R"HTML(
@@ -275,8 +263,6 @@ TEST_F(NGLayoutResultCachingTest, HitOOFDescendantAboveBlockStart) {
}
TEST_F(NGLayoutResultCachingTest, HitLineBoxDescendantAboveBlockStart) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Different BFC offset, same exclusion space, line-box descendant above
// block start.
SetBodyInnerHTML(R"HTML(
@@ -320,8 +306,6 @@ TEST_F(NGLayoutResultCachingTest, HitLineBoxDescendantAboveBlockStart) {
}
TEST_F(NGLayoutResultCachingTest, MissFloatInitiallyIntruding1) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Same BFC offset, different exclusion space, float initially
// intruding.
SetBodyInnerHTML(R"HTML(
@@ -358,8 +342,6 @@ TEST_F(NGLayoutResultCachingTest, MissFloatInitiallyIntruding1) {
}
TEST_F(NGLayoutResultCachingTest, MissFloatInitiallyIntruding2) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Different BFC offset, same exclusion space, float initially
// intruding.
SetBodyInnerHTML(R"HTML(
@@ -396,8 +378,6 @@ TEST_F(NGLayoutResultCachingTest, MissFloatInitiallyIntruding2) {
}
TEST_F(NGLayoutResultCachingTest, MissFloatWillIntrude1) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Same BFC offset, different exclusion space, float will intrude.
SetBodyInnerHTML(R"HTML(
<style>
@@ -433,8 +413,6 @@ TEST_F(NGLayoutResultCachingTest, MissFloatWillIntrude1) {
}
TEST_F(NGLayoutResultCachingTest, MissFloatWillIntrude2) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Different BFC offset, same exclusion space, float will intrude.
SetBodyInnerHTML(R"HTML(
<style>
@@ -470,8 +448,6 @@ TEST_F(NGLayoutResultCachingTest, MissFloatWillIntrude2) {
}
TEST_F(NGLayoutResultCachingTest, HitPushedByFloats1) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Same BFC offset, different exclusion space, pushed by floats.
SetBodyInnerHTML(R"HTML(
<style>
@@ -507,8 +483,6 @@ TEST_F(NGLayoutResultCachingTest, HitPushedByFloats1) {
}
TEST_F(NGLayoutResultCachingTest, HitPushedByFloats2) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Different BFC offset, same exclusion space, pushed by floats.
SetBodyInnerHTML(R"HTML(
<style>
@@ -544,8 +518,6 @@ TEST_F(NGLayoutResultCachingTest, HitPushedByFloats2) {
}
TEST_F(NGLayoutResultCachingTest, MissPushedByFloats1) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Same BFC offset, different exclusion space, pushed by floats.
// Miss due to shrinking offset.
SetBodyInnerHTML(R"HTML(
@@ -582,8 +554,6 @@ TEST_F(NGLayoutResultCachingTest, MissPushedByFloats1) {
}
TEST_F(NGLayoutResultCachingTest, MissPushedByFloats2) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Different BFC offset, same exclusion space, pushed by floats.
// Miss due to shrinking offset.
SetBodyInnerHTML(R"HTML(
@@ -620,8 +590,6 @@ TEST_F(NGLayoutResultCachingTest, MissPushedByFloats2) {
}
TEST_F(NGLayoutResultCachingTest, HitDifferentRareData) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Same absolute fixed constraints.
SetBodyInnerHTML(R"HTML(
<style>
@@ -651,8 +619,6 @@ TEST_F(NGLayoutResultCachingTest, HitDifferentRareData) {
}
TEST_F(NGLayoutResultCachingTest, HitPercentageMinWidth) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// min-width calculates to different values, but doesn't change size.
SetBodyInnerHTML(R"HTML(
<style>
@@ -682,8 +648,6 @@ TEST_F(NGLayoutResultCachingTest, HitPercentageMinWidth) {
}
TEST_F(NGLayoutResultCachingTest, HitFixedMinWidth) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// min-width is always larger than the available size.
SetBodyInnerHTML(R"HTML(
<style>
@@ -712,9 +676,151 @@ TEST_F(NGLayoutResultCachingTest, HitFixedMinWidth) {
EXPECT_NE(result.get(), nullptr);
}
-TEST_F(NGLayoutResultCachingTest, HitShrinkToFitSameIntrinsicSizes) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
+TEST_F(NGLayoutResultCachingTest, HitShrinkToFit) {
+ SetBodyInnerHTML(R"HTML(
+ <div style="display: flow-root; width: 300px; height: 100px;">
+ <div id="test1" style="float: left;">
+ <div style="display: inline-block; width: 150px;"></div>
+ <div style="display: inline-block; width: 50px;"></div>
+ </div>
+ <div id="test2" style="float: left;">
+ <div style="display: inline-block; width: 350px;"></div>
+ <div style="display: inline-block; width: 250px;"></div>
+ </div>
+ </div>
+ <div style="display: flow-root; width: 400px; height: 100px;">
+ <div id="src1" style="float: left;">
+ <div style="display: inline-block; width: 150px;"></div>
+ <div style="display: inline-block; width: 50px;"></div>
+ </div>
+ </div>
+ <div style="display: flow-root; width: 200px; height: 100px;">
+ <div id="src2" style="float: left;">
+ <div style="display: inline-block; width: 350px;"></div>
+ <div style="display: inline-block; width: 250px;"></div>
+ </div>
+ </div>
+ )HTML");
+
+ auto* test1 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("test1"));
+ auto* test2 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("test2"));
+ auto* src1 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src1"));
+ auto* src2 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src2"));
+
+ NGLayoutCacheStatus cache_status;
+ base::Optional<NGFragmentGeometry> fragment_geometry;
+ NGConstraintSpace space =
+ src1->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ scoped_refptr<const NGLayoutResult> result = test1->CachedLayoutResult(
+ space, nullptr, nullptr, &fragment_geometry, &cache_status);
+ // test1 was sized to its max-content size, passing an available size larger
+ // than the fragment should hit the cache.
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kHit);
+ EXPECT_NE(result.get(), nullptr);
+
+ fragment_geometry.reset();
+ space = src2->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ result = test2->CachedLayoutResult(space, nullptr, nullptr,
+ &fragment_geometry, &cache_status);
+ // test2 was sized to its min-content size in, passing an available size
+ // smaller than the fragment should hit the cache.
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kHit);
+ EXPECT_NE(result.get(), nullptr);
+}
+
+TEST_F(NGLayoutResultCachingTest, MissShrinkToFit) {
+ SetBodyInnerHTML(R"HTML(
+ <div style="display: flow-root; width: 300px; height: 100px;">
+ <div id="test1" style="float: left;">
+ <div style="display: inline-block; width: 150px;"></div>
+ <div style="display: inline-block; width: 50px;"></div>
+ </div>
+ <div id="test2" style="float: left;">
+ <div style="display: inline-block; width: 350px;"></div>
+ <div style="display: inline-block; width: 250px;"></div>
+ </div>
+ <div id="test3" style="float: left; min-width: 80%;">
+ <div style="display: inline-block; width: 150px;"></div>
+ <div style="display: inline-block; width: 250px;"></div>
+ </div>
+ <div id="test4" style="float: left; margin-left: 75px;">
+ <div style="display: inline-block; width: 150px;"></div>
+ <div style="display: inline-block; width: 50px;"></div>
+ </div>
+ </div>
+ <div style="display: flow-root; width: 100px; height: 100px;">
+ <div id="src1" style="float: left;">
+ <div style="display: inline-block; width: 150px;"></div>
+ <div style="display: inline-block; width: 50px;"></div>
+ </div>
+ </div>
+ <div style="display: flow-root; width: 400px; height: 100px;">
+ <div id="src2" style="float: left;">
+ <div style="display: inline-block; width: 350px;"></div>
+ <div style="display: inline-block; width: 250px;"></div>
+ </div>
+ <div id="src3" style="float: left; min-width: 80%;">
+ <div style="display: inline-block; width: 150px;"></div>
+ <div style="display: inline-block; width: 250px;"></div>
+ </div>
+ </div>
+ <div style="display: flow-root; width: 250px; height: 100px;">
+ <div id="src4" style="float: left; margin-left: 75px;">
+ <div style="display: inline-block; width: 150px;"></div>
+ <div style="display: inline-block; width: 50px;"></div>
+ </div>
+ </div>
+ )HTML");
+
+ auto* test1 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("test1"));
+ auto* test2 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("test2"));
+ auto* test3 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("test3"));
+ auto* test4 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("test4"));
+ auto* src1 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src1"));
+ auto* src2 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src2"));
+ auto* src3 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src3"));
+ auto* src4 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src4"));
+
+ NGLayoutCacheStatus cache_status;
+ base::Optional<NGFragmentGeometry> fragment_geometry;
+ NGConstraintSpace space =
+ src1->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ scoped_refptr<const NGLayoutResult> result = test1->CachedLayoutResult(
+ space, nullptr, nullptr, &fragment_geometry, &cache_status);
+ // test1 was sized to its max-content size, passing an available size smaller
+ // than the fragment should miss the cache.
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kNeedsLayout);
+ EXPECT_EQ(result.get(), nullptr);
+
+ fragment_geometry.reset();
+ space = src2->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ result = test2->CachedLayoutResult(space, nullptr, nullptr,
+ &fragment_geometry, &cache_status);
+ // test2 was sized to its min-content size, passing an available size
+ // larger than the fragment should miss the cache.
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kNeedsLayout);
+ EXPECT_EQ(result.get(), nullptr);
+
+ fragment_geometry.reset();
+ space = src3->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ result = test3->CachedLayoutResult(space, nullptr, nullptr,
+ &fragment_geometry, &cache_status);
+ // test3 was sized to its min-content size, however it should miss the cache
+ // as it has a %-min-size.
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kNeedsLayout);
+ EXPECT_EQ(result.get(), nullptr);
+
+ fragment_geometry.reset();
+ space = src4->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ result = test4->CachedLayoutResult(space, nullptr, nullptr,
+ &fragment_geometry, &cache_status);
+ // test4 was sized to its max-content size, however it should miss the cache
+ // due to its margin.
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kNeedsLayout);
+ EXPECT_EQ(result.get(), nullptr);
+}
+TEST_F(NGLayoutResultCachingTest, HitShrinkToFitSameIntrinsicSizes) {
// We have a shrink-to-fit node, with the min, and max intrinsic sizes being
// equal (the available size doesn't affect the final size).
SetBodyInnerHTML(R"HTML(
@@ -750,8 +856,6 @@ TEST_F(NGLayoutResultCachingTest, HitShrinkToFitSameIntrinsicSizes) {
}
TEST_F(NGLayoutResultCachingTest, HitShrinkToFitDifferentParent) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// The parent "bfc" node changes from shrink-to-fit, to a fixed width. But
// these calculate as the same available space to the "test" element.
SetBodyInnerHTML(R"HTML(
@@ -786,8 +890,6 @@ TEST_F(NGLayoutResultCachingTest, HitShrinkToFitDifferentParent) {
}
TEST_F(NGLayoutResultCachingTest, MissQuirksModePercentageBasedChild) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Quirks-mode %-block-size child.
GetDocument().SetCompatibilityMode(Document::kQuirksMode);
SetBodyInnerHTML(R"HTML(
@@ -822,8 +924,6 @@ TEST_F(NGLayoutResultCachingTest, MissQuirksModePercentageBasedChild) {
}
TEST_F(NGLayoutResultCachingTest, HitQuirksModePercentageBasedParentAndChild) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Quirks-mode %-block-size parent *and* child. Here we mark the parent as
// depending on %-block-size changes, however itself doesn't change in
// height.
@@ -863,8 +963,6 @@ TEST_F(NGLayoutResultCachingTest, HitQuirksModePercentageBasedParentAndChild) {
}
TEST_F(NGLayoutResultCachingTest, HitStandardsModePercentageBasedChild) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
// Standards-mode %-block-size child.
SetBodyInnerHTML(R"HTML(
<style>
@@ -898,8 +996,6 @@ TEST_F(NGLayoutResultCachingTest, HitStandardsModePercentageBasedChild) {
}
TEST_F(NGLayoutResultCachingTest, ChangeTableCellBlockSizeConstrainedness) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
SetBodyInnerHTML(R"HTML(
<style>
.table { display: table; width: 300px; }
@@ -964,12 +1060,9 @@ TEST_F(NGLayoutResultCachingTest, ChangeTableCellBlockSizeConstrainedness) {
// height or not. We're only going to need simplified layout, though, since no
// children will be affected by its height change.
EXPECT_EQ(cache_status, NGLayoutCacheStatus::kNeedsSimplifiedLayout);
- EXPECT_EQ(result.get(), nullptr);
}
TEST_F(NGLayoutResultCachingTest, OptimisticFloatPlacementNoRelayout) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
SetBodyInnerHTML(R"HTML(
<style>
.root { display: flow-root; width: 300px; }
@@ -994,8 +1087,6 @@ TEST_F(NGLayoutResultCachingTest, OptimisticFloatPlacementNoRelayout) {
}
TEST_F(NGLayoutResultCachingTest, SelfCollapsingShifting) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
SetBodyInnerHTML(R"HTML(
<style>
.bfc { display: flow-root; width: 300px; height: 300px; }
@@ -1080,8 +1171,6 @@ TEST_F(NGLayoutResultCachingTest, SelfCollapsingShifting) {
}
TEST_F(NGLayoutResultCachingTest, ClearancePastAdjoiningFloatsMovement) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
SetBodyInnerHTML(R"HTML(
<style>
.bfc { display: flow-root; width: 300px; height: 300px; }
@@ -1146,8 +1235,6 @@ TEST_F(NGLayoutResultCachingTest, ClearancePastAdjoiningFloatsMovement) {
}
TEST_F(NGLayoutResultCachingTest, MarginStrutMovementSelfCollapsing) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
SetBodyInnerHTML(R"HTML(
<style>
.bfc { display: flow-root; width: 300px; height: 300px; }
@@ -1217,8 +1304,6 @@ TEST_F(NGLayoutResultCachingTest, MarginStrutMovementSelfCollapsing) {
}
TEST_F(NGLayoutResultCachingTest, MarginStrutMovementInFlow) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
SetBodyInnerHTML(R"HTML(
<style>
.bfc { display: flow-root; width: 300px; height: 300px; }
@@ -1315,8 +1400,6 @@ TEST_F(NGLayoutResultCachingTest, MarginStrutMovementInFlow) {
}
TEST_F(NGLayoutResultCachingTest, MarginStrutMovementPercentage) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
SetBodyInnerHTML(R"HTML(
<style>
.bfc { display: flow-root; width: 300px; height: 300px; }
@@ -1354,53 +1437,55 @@ TEST_F(NGLayoutResultCachingTest, MarginStrutMovementPercentage) {
EXPECT_EQ(result.get(), nullptr);
}
-TEST_F(NGLayoutResultCachingTest, MarginStrutMovementDiscard) {
- ScopedLayoutNGFragmentCachingForTest layout_ng_fragment_caching(true);
-
+TEST_F(NGLayoutResultCachingTest, HitIsFixedBlockSizeIndefinite) {
SetBodyInnerHTML(R"HTML(
- <style>
- .bfc { display: flow-root; width: 300px; height: 300px; }
- </style>
- <div class="bfc">
- <div style="margin-top: 10px;">
- <div id="test1">
- <div style="-webkit-margin-top-collapse: discard;">text</div>
- </div>
+ <div style="display: flex; width: 100px; height: 100px;">
+ <div id="test1" style="flex-grow: 1; min-height: 100px;">
+ <div style="height: 50px;">text</div>
</div>
</div>
- <div class="bfc">
- <div style="margin-top: 5px;">
- <div id="src1">
- <div style="-webkit-margin-top-collapse: discard;">text</div>
- </div>
+ <div style="display: flex; width: 100px; height: 100px; align-items: stretch;">
+ <div id="src1" style="flex-grow: 1; min-height: 100px;">
+ <div style="height: 50px;">text</div>
</div>
</div>
- <div class="bfc">
- <div style="margin-top: 10px;">
- <div id="test2">
- <div>
- <div style="-webkit-margin-bottom-collapse: discard;"></div>
- </div>
- <div>text</div>
- </div>
+ )HTML");
+
+ auto* test1 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("test1"));
+ auto* src1 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src1"));
+
+ NGLayoutCacheStatus cache_status;
+ base::Optional<NGFragmentGeometry> fragment_geometry;
+
+ NGConstraintSpace space =
+ src1->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ scoped_refptr<const NGLayoutResult> result = test1->CachedLayoutResult(
+ space, nullptr, nullptr, &fragment_geometry, &cache_status);
+
+ // Even though the "align-items: stretch" will make the final fixed
+ // block-size indefinite, we don't have any %-block-size children, so we can
+ // hit the cache.
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kHit);
+ EXPECT_NE(result.get(), nullptr);
+}
+
+TEST_F(NGLayoutResultCachingTest, MissIsFixedBlockSizeIndefinite) {
+ SetBodyInnerHTML(R"HTML(
+ <!DOCTYPE html>
+ <div style="display: flex; width: 100px; height: 100px; align-items: start;">
+ <div id="src1" style="flex-grow: 1; min-height: 100px;">
+ <div style="height: 50%;">text</div>
</div>
</div>
- <div class="bfc">
- <div style="margin-top: 5px;">
- <div id="src2">
- <div>
- <div style="-webkit-margin-bottom-collapse: discard;"></div>
- </div>
- <div>text</div>
- </div>
+ <div style="display: flex; width: 100px; height: 100px; align-items: stretch;">
+ <div id="test1" style="flex-grow: 1; min-height: 100px;">
+ <div style="height: 50%;">text</div>
</div>
</div>
)HTML");
auto* test1 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("test1"));
- auto* test2 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("test2"));
auto* src1 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src1"));
- auto* src2 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src2"));
NGLayoutCacheStatus cache_status;
base::Optional<NGFragmentGeometry> fragment_geometry;
@@ -1410,18 +1495,62 @@ TEST_F(NGLayoutResultCachingTest, MarginStrutMovementDiscard) {
scoped_refptr<const NGLayoutResult> result = test1->CachedLayoutResult(
space, nullptr, nullptr, &fragment_geometry, &cache_status);
- // Case 1: We can't re-use this fragment as the sub-tree discards margins.
+ // The "align-items: stretch" will make the final fixed block-size
+ // indefinite, and we have a %-block-size child, so we need to miss the
+ // cache.
EXPECT_EQ(cache_status, NGLayoutCacheStatus::kNeedsLayout);
EXPECT_EQ(result.get(), nullptr);
+}
- fragment_geometry.reset();
+TEST_F(NGLayoutResultCachingTest, HitFlexBoxMeasureAndLayout) {
+ ScopedLayoutNGFlexBoxForTest layout_ng_flex_box(true);
+
+ SetBodyInnerHTML(R"HTML(
+ <!DOCTYPE html>
+ <div style="display: flex; flex-direction: column; width: 100px; height: 100px;">
+ <div id="src1" style="flex-grow: 0;">
+ <div style="height: 50px;"></div>
+ </div>
+ </div>
+ <div style="display: flex; flex-direction: column; width: 100px; height: 100px;">
+ <div id="src2" style="flex-grow: 1;">
+ <div style="height: 50px;"></div>
+ </div>
+ </div>
+ <div style="display: flex; flex-direction: column; width: 100px; height: 100px;">
+ <div id="test1" style="flex-grow: 2;">
+ <div style="height: 50px;"></div>
+ </div>
+ </div>
+ )HTML");
+
+ auto* test1 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("test1"));
+ auto* src1 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src1"));
+ auto* src2 = To<LayoutBlockFlow>(GetLayoutObjectByElementId("src2"));
+
+ NGLayoutCacheStatus cache_status;
+ base::Optional<NGFragmentGeometry> fragment_geometry;
+
+ // "src1" only had one "measure" pass performed, and should hit the "measure"
+ // cache-slot for "test1".
+ NGConstraintSpace space =
+ src1->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
+ scoped_refptr<const NGLayoutResult> result = test1->CachedLayoutResult(
+ space, nullptr, nullptr, &fragment_geometry, &cache_status);
+
+ EXPECT_EQ(space.CacheSlot(), NGCacheSlot::kMeasure);
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kHit);
+ EXPECT_NE(result.get(), nullptr);
+
+ // "src2" had both a "measure" and "layout" pass performed, and should hit
+ // the "layout" cache-slot for "test1".
space = src2->GetCachedLayoutResult()->GetConstraintSpaceForCaching();
- result = test2->CachedLayoutResult(space, nullptr, nullptr,
+ result = test1->CachedLayoutResult(space, nullptr, nullptr,
&fragment_geometry, &cache_status);
- // Case 2: Also check a self-collapsing block with a block-end discard.
- EXPECT_EQ(cache_status, NGLayoutCacheStatus::kNeedsLayout);
- EXPECT_EQ(result.get(), nullptr);
+ EXPECT_EQ(space.CacheSlot(), NGCacheSlot::kLayout);
+ EXPECT_EQ(cache_status, NGLayoutCacheStatus::kHit);
+ EXPECT_NE(result.get(), nullptr);
}
} // namespace
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
index 229af34617d..3802930ac23 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
@@ -84,6 +84,8 @@ bool SizeMayChange(const NGBlockNode& node,
DCHECK_EQ(new_space.IsFixedInlineSize(), old_space.IsFixedInlineSize());
DCHECK_EQ(new_space.IsFixedBlockSize(), old_space.IsFixedBlockSize());
+ DCHECK_EQ(new_space.IsFixedBlockSizeIndefinite(),
+ old_space.IsFixedBlockSizeIndefinite());
DCHECK_EQ(new_space.IsShrinkToFit(), old_space.IsShrinkToFit());
DCHECK_EQ(new_space.TableCellChildLayoutMode(),
old_space.TableCellChildLayoutMode());
@@ -180,17 +182,48 @@ NGLayoutCacheStatus CalculateSizeBasedLayoutCacheStatusWithGeometry(
LayoutUnit block_size = fragment_geometry.border_box_size.block_size;
bool is_initial_block_size_indefinite = block_size == kIndefiniteSize;
if (is_initial_block_size_indefinite) {
- // The intrinsic size of column flex-boxes can depend on the
- // %-resolution-block-size. This occurs when a flex-box has "max-height:
- // 100%" or similar on itself.
- //
- // Due to this we can't use cached |NGLayoutResult::IntrinsicBlockSize|
- // value, as the following |block_size| calculation would be incorrect.
- if (node.IsFlexibleBox() && style.ResolvedIsColumnFlexDirection() &&
- layout_result.PhysicalFragment().DependsOnPercentageBlockSize()) {
- if (new_space.PercentageResolutionBlockSize() !=
- old_space.PercentageResolutionBlockSize())
+ if (node.IsFlexibleBox()) {
+ // Flex-boxes can have their children calculate their size based in their
+ // parent's final block-size. E.g.
+ // <div style="display: flex;">
+ // <div style="display: flex;">
+ // <!-- Child will stretch to the parent's fixed block-size -->
+ // <div></div>
+ // </div>
+ // </div>
+ // <div style="display: flex;">
+ // <div style="display: flex; flex-direction: column;">
+ // <!-- Child will grow to the parent's fixed block-size -->
+ // <div style="flex: 1;"></div>
+ // </div>
+ // </div>
+ //
+ // If the previous |layout_result| was produced by a space which had a
+ // fixed block-size we can't use |NGLayoutResult::IntrinsicBlockSize()|,
+ // and need to layout.
+ //
+ // TODO(ikilpatrick): Similar to %-block-size descendants we could store
+ // a bit on the |NGLayoutResult| which indicates if it had a child which
+ // sized itself based on the parent's block-size.
+ // We should consider this optimization if we are missing this cache
+ // often within this branch (and could have re-used the result).
+ // TODO(ikilaptrick): This may occur for other layout modes, e.g.
+ // grid/custom-layout/etc.
+ if (old_space.IsFixedBlockSize())
return NGLayoutCacheStatus::kNeedsLayout;
+
+ // The intrinsic size of column flex-boxes can depend on the
+ // %-resolution-block-size. This occurs when a flex-box has "max-height:
+ // 100%" or similar on itself.
+ //
+ // Due to this we can't use cached |NGLayoutResult::IntrinsicBlockSize|
+ // value, as the following |block_size| calculation would be incorrect.
+ if (style.ResolvedIsColumnFlexDirection() &&
+ layout_result.PhysicalFragment().DependsOnPercentageBlockSize()) {
+ if (new_space.PercentageResolutionBlockSize() !=
+ old_space.PercentageResolutionBlockSize())
+ return NGLayoutCacheStatus::kNeedsLayout;
+ }
}
block_size = ComputeBlockSizeForFragment(
@@ -209,7 +242,7 @@ NGLayoutCacheStatus CalculateSizeBasedLayoutCacheStatusWithGeometry(
// If a block (within a formatting-context) changes to/from an empty-block,
// margins may collapse through this node, requiring full layout. We
// approximate this check by checking if the block-size is/was zero.
- if (!physical_fragment.IsBlockFormattingContextRoot() &&
+ if (!physical_fragment.IsFormattingContextRoot() &&
!block_size != !fragment.BlockSize())
return NGLayoutCacheStatus::kNeedsLayout;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
index 53a8071828b..e07c07e0d08 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc
@@ -90,7 +90,7 @@ bool BlockLengthUnresolvable(
LengthResolvePhase phase,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max) {
if (length.IsAuto() || length.IsMinContent() || length.IsMaxContent() ||
- length.IsFitContent() || length.IsMaxSizeNone())
+ length.IsFitContent() || length.IsNone())
return true;
if (length.IsPercentOrCalc()) {
if (phase == LengthResolvePhase::kIntrinsic)
@@ -115,7 +115,7 @@ LayoutUnit ResolveInlineLengthInternal(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
- const base::Optional<MinMaxSize>& min_and_max,
+ const base::Optional<MinMaxSizes>& min_max_sizes,
const Length& length) {
DCHECK_GE(constraint_space.AvailableSize().inline_size, LayoutUnit());
DCHECK_GE(constraint_space.PercentageResolutionInlineSize(), LayoutUnit());
@@ -146,20 +146,20 @@ LayoutUnit ResolveInlineLengthInternal(
case Length::kMinContent:
case Length::kMaxContent:
case Length::kFitContent: {
- DCHECK(min_and_max.has_value());
+ DCHECK(min_max_sizes.has_value());
LayoutUnit available_size = constraint_space.AvailableSize().inline_size;
LayoutUnit value;
if (length.IsMinContent()) {
- value = min_and_max->min_size;
+ value = min_max_sizes->min_size;
} else if (length.IsMaxContent() || available_size == LayoutUnit::Max()) {
// If the available space is infinite, fit-content resolves to
// max-content. See css-sizing section 2.1.
- value = min_and_max->max_size;
+ value = min_max_sizes->max_size;
} else {
NGBoxStrut margins = ComputeMarginsForSelf(constraint_space, style);
LayoutUnit fill_available =
std::max(LayoutUnit(), available_size - margins.InlineSum());
- value = min_and_max->ShrinkToFit(fill_available);
+ value = min_max_sizes->ShrinkToFit(fill_available);
}
return value;
}
@@ -168,7 +168,7 @@ LayoutUnit ResolveInlineLengthInternal(
case Length::kExtendToZoom:
NOTREACHED() << "These should only be used for viewport definitions";
FALLTHROUGH;
- case Length::kMaxSizeNone:
+ case Length::kNone:
default:
NOTREACHED();
return border_padding.InlineSum();
@@ -235,18 +235,18 @@ LayoutUnit ResolveBlockLengthInternal(
case Length::kExtendToZoom:
NOTREACHED() << "These should only be used for viewport definitions";
FALLTHROUGH;
- case Length::kMaxSizeNone:
+ case Length::kNone:
default:
NOTREACHED();
return border_padding.BlockSum();
}
}
-MinMaxSize ComputeMinAndMaxContentContribution(
+MinMaxSizes ComputeMinAndMaxContentContribution(
WritingMode parent_writing_mode,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
- const base::Optional<MinMaxSize>& min_and_max) {
+ const base::Optional<MinMaxSizes>& min_max_sizes) {
WritingMode child_writing_mode = style.GetWritingMode();
// Synthesize a zero-sized constraint space for resolving sizes against.
@@ -256,20 +256,20 @@ MinMaxSize ComputeMinAndMaxContentContribution(
.ToConstraintSpace();
LayoutUnit content_size =
- min_and_max ? min_and_max->max_size : kIndefiniteSize;
+ min_max_sizes ? min_max_sizes->max_size : kIndefiniteSize;
- MinMaxSize computed_sizes;
+ MinMaxSizes computed_sizes;
const Length& inline_size = parent_writing_mode == WritingMode::kHorizontalTb
? style.Width()
: style.Height();
if (inline_size.IsAuto() || inline_size.IsPercentOrCalc() ||
inline_size.IsFillAvailable() || inline_size.IsFitContent()) {
- CHECK(min_and_max.has_value());
- computed_sizes = *min_and_max;
+ CHECK(min_max_sizes.has_value());
+ computed_sizes = *min_max_sizes;
} else {
if (IsParallelWritingMode(parent_writing_mode, child_writing_mode)) {
computed_sizes = ResolveMainInlineLength(space, style, border_padding,
- min_and_max, inline_size);
+ min_max_sizes, inline_size);
} else {
computed_sizes =
ResolveMainBlockLength(space, style, border_padding, inline_size,
@@ -282,11 +282,11 @@ MinMaxSize ComputeMinAndMaxContentContribution(
: style.MaxHeight();
LayoutUnit max;
if (IsParallelWritingMode(parent_writing_mode, child_writing_mode)) {
- max = ResolveMaxInlineLength(space, style, border_padding, min_and_max,
+ max = ResolveMaxInlineLength(space, style, border_padding, min_max_sizes,
max_length, LengthResolvePhase::kIntrinsic);
} else {
max = ResolveMaxBlockLength(space, style, border_padding, max_length,
- content_size, LengthResolvePhase::kIntrinsic);
+ LengthResolvePhase::kIntrinsic);
}
computed_sizes.Constrain(max);
@@ -295,59 +295,51 @@ MinMaxSize ComputeMinAndMaxContentContribution(
: style.MinHeight();
LayoutUnit min;
if (IsParallelWritingMode(parent_writing_mode, child_writing_mode)) {
- min = ResolveMinInlineLength(space, style, border_padding, min_and_max,
+ min = ResolveMinInlineLength(space, style, border_padding, min_max_sizes,
min_length, LengthResolvePhase::kIntrinsic);
} else {
min = ResolveMinBlockLength(space, style, border_padding, min_length,
- content_size, LengthResolvePhase::kIntrinsic);
+ LengthResolvePhase::kIntrinsic);
}
computed_sizes.Encompass(min);
return computed_sizes;
}
-MinMaxSize ComputeMinAndMaxContentContribution(
+MinMaxSizes ComputeMinAndMaxContentContribution(
const ComputedStyle& parent_style,
NGLayoutInputNode child,
- const MinMaxSizeInput& input) {
+ const MinMaxSizesInput& input) {
const ComputedStyle& child_style = child.Style();
WritingMode parent_writing_mode = parent_style.GetWritingMode();
WritingMode child_writing_mode = child_style.GetWritingMode();
- LayoutBox* box = child.GetLayoutBox();
-
- if (box->NeedsPreferredWidthsRecalculation()) {
- // Some objects (when there's an intrinsic ratio) have their min/max inline
- // size affected by the block size of their container. We don't really know
- // whether the containing block of this child did change or is going to
- // change size. However, this is our only opportunity to make sure that it
- // gets its min/max widths calculated.
- box->SetPreferredLogicalWidthsDirty();
- }
if (IsParallelWritingMode(parent_writing_mode, child_writing_mode)) {
- if (!box->PreferredLogicalWidthsDirty()) {
- return {box->MinPreferredLogicalWidth(), box->MaxPreferredLogicalWidth()};
- }
// Tables are special; even if a width is specified, they may end up being
// sized different. So we just always let the table code handle this.
+ if (child.IsTable())
+ return child.ComputeMinMaxSizes(parent_writing_mode, input, nullptr);
+
// Replaced elements may size themselves using aspect ratios and block
// sizes, so we pass that on as well.
- if (box->IsTable() || box->IsTablePart() || box->IsLayoutReplaced()) {
+ if (child.IsReplaced()) {
+ LayoutBox* box = child.GetLayoutBox();
bool needs_size_reset = false;
if (!box->HasOverrideContainingBlockContentLogicalHeight()) {
box->SetOverrideContainingBlockContentLogicalHeight(
input.percentage_resolution_block_size);
needs_size_reset = true;
}
- MinMaxSize result{box->MinPreferredLogicalWidth(),
- box->MaxPreferredLogicalWidth()};
+
+ MinMaxSizes result = box->PreferredLogicalWidths();
+
if (needs_size_reset)
box->ClearOverrideContainingBlockContentSize();
return result;
}
}
- base::Optional<MinMaxSize> minmax;
+ base::Optional<MinMaxSizes> min_max_sizes;
if (NeedMinMaxSizeForContentContribution(parent_writing_mode, child_style)) {
// We need to set up a constraint space with correct fallback available
// inline size in case of orthogonal children.
@@ -358,8 +350,8 @@ MinMaxSize ComputeMinAndMaxContentContribution(
CreateIndefiniteConstraintSpaceForChild(parent_style, child);
child_constraint_space = &indefinite_constraint_space;
}
- minmax = child.ComputeMinMaxSize(parent_writing_mode, input,
- child_constraint_space);
+ min_max_sizes = child.ComputeMinMaxSizes(parent_writing_mode, input,
+ child_constraint_space);
}
// Synthesize a zero-sized constraint space for determining the borders, and
// padding.
@@ -368,50 +360,17 @@ MinMaxSize ComputeMinAndMaxContentContribution(
/* is_new_fc */ false)
.ToConstraintSpace();
NGBoxStrut border_padding =
- ComputeBorders(space, child) + ComputePadding(space, child_style);
-
- MinMaxSize sizes = ComputeMinAndMaxContentContribution(
- parent_writing_mode, child_style, border_padding, minmax);
- if (IsParallelWritingMode(parent_writing_mode, child_writing_mode))
- box->SetPreferredLogicalWidthsFromNG(sizes);
- return sizes;
-}
-
-MinMaxSize ComputeMinAndMaxContentSizeForOutOfFlow(
- const NGConstraintSpace& constraint_space,
- NGLayoutInputNode node,
- const NGBoxStrut& border_padding,
- const MinMaxSizeInput& input) {
- LayoutBox* box = node.GetLayoutBox();
- // If we've already populated the legacy preferred logical widths cache for
- // this node at the bottom of this function, use those cached results here.
- // Or, if we're working on a table, use the legacy preferred widths code
- // instead of ComputeMinAndMaxContentContribution below because
- // ComputeMinAndMaxContentContribution assumes that if an element has a
- // specified size, that's its final size, which tables don't follow.
- if ((!box->PreferredLogicalWidthsDirty() &&
- !box->NeedsPreferredWidthsRecalculation()) ||
- box->IsTable()) {
- return MinMaxSize{box->MinPreferredLogicalWidth(),
- box->MaxPreferredLogicalWidth()};
- }
+ ComputeBorders(space, child_style) + ComputePadding(space, child_style);
- // Compute the intrinsic sizes without regard to the specified sizes.
- MinMaxSize result = node.ComputeMinMaxSize(node.Style().GetWritingMode(),
- input, &constraint_space);
- // Apply the specified min, main, max sizes.
- MinMaxSize contribution = ComputeMinAndMaxContentContribution(
- node.Style().GetWritingMode(), node.Style(), border_padding, result);
- // Cache these computed values.
- box->SetPreferredLogicalWidthsFromNG(contribution);
- return result;
+ return ComputeMinAndMaxContentContribution(parent_writing_mode, child_style,
+ border_padding, min_max_sizes);
}
LayoutUnit ComputeInlineSizeForFragment(
const NGConstraintSpace& space,
NGLayoutInputNode node,
const NGBoxStrut& border_padding,
- const MinMaxSize* override_minmax_for_test) {
+ const MinMaxSizes* override_min_max_sizes_for_test) {
if (space.IsFixedInlineSize() || space.IsAnonymous())
return space.AvailableSize().inline_size;
@@ -420,57 +379,24 @@ LayoutUnit ComputeInlineSizeForFragment(
if (logical_width.IsAuto() && space.IsShrinkToFit())
logical_width = Length::FitContent();
- LayoutBox* box = node.GetLayoutBox();
- // If we have usable cached min/max intrinsic sizes, use those if we can. They
- // will normally also be constrained to {min,max}-inline-size, but not if
- // percentages are involved. In such cases we'll have to calculate and apply
- // the constraints on our own. We also need to discard the cached values if
- // the box has certain properties (e.g. percentage padding) that cause the
- // cached values to be affected by extrinsic sizing.
- if (!box->PreferredLogicalWidthsDirty() && !override_minmax_for_test &&
- !style.LogicalMinWidth().IsPercentOrCalc() &&
- !style.LogicalMaxWidth().IsPercentOrCalc() &&
- !box->NeedsPreferredWidthsRecalculation()) {
- if (logical_width.IsFitContent()) {
- // This is not as easy as {min, max}.ShrinkToFit() because we also need
- // to subtract inline margins from the available size. The code in
- // ResolveMainInlineLength knows how to handle that, just call that.
-
- MinMaxSize min_and_max = {box->MinPreferredLogicalWidth(),
- box->MaxPreferredLogicalWidth()};
- return ResolveMainInlineLength(space, style, border_padding, min_and_max,
- logical_width);
- }
- if (logical_width.IsMinContent())
- return box->MinPreferredLogicalWidth();
- if (logical_width.IsMaxContent())
- return box->MaxPreferredLogicalWidth();
- }
+ auto MinMaxSizesFunc = [&]() -> MinMaxSizes {
+ if (override_min_max_sizes_for_test)
+ return *override_min_max_sizes_for_test;
- base::Optional<MinMaxSize> min_and_max;
- if (NeedMinMaxSize(space, style)) {
- if (override_minmax_for_test) {
- min_and_max = *override_minmax_for_test;
- } else {
- min_and_max = node.ComputeMinMaxSize(
- space.GetWritingMode(),
- MinMaxSizeInput(space.PercentageResolutionBlockSize()), &space);
- // Cache these computed values
- MinMaxSize contribution = ComputeMinAndMaxContentContribution(
- style.GetWritingMode(), style, border_padding, min_and_max);
- box->SetPreferredLogicalWidthsFromNG(contribution);
- }
- }
+ return node.ComputeMinMaxSizes(
+ space.GetWritingMode(),
+ MinMaxSizesInput(space.PercentageResolutionBlockSize()), &space);
+ };
LayoutUnit extent = ResolveMainInlineLength(space, style, border_padding,
- min_and_max, logical_width);
-
- LayoutUnit max = ResolveMaxInlineLength(space, style, border_padding,
- min_and_max, style.LogicalMaxWidth(),
- LengthResolvePhase::kLayout);
- LayoutUnit min = ResolveMinInlineLength(space, style, border_padding,
- min_and_max, style.LogicalMinWidth(),
- LengthResolvePhase::kLayout);
+ MinMaxSizesFunc, logical_width);
+
+ LayoutUnit max = ResolveMaxInlineLength(
+ space, style, border_padding, MinMaxSizesFunc, style.LogicalMaxWidth(),
+ LengthResolvePhase::kLayout);
+ LayoutUnit min = ResolveMinInlineLength(
+ space, style, border_padding, MinMaxSizesFunc, style.LogicalMinWidth(),
+ LengthResolvePhase::kLayout);
return ConstrainByMinMax(extent, min, max);
}
@@ -486,7 +412,7 @@ LayoutUnit ComputeBlockSizeForFragmentInternal(
nullptr) {
LayoutUnit min = ResolveMinBlockLength(
constraint_space, style, border_padding, style.LogicalMinHeight(),
- content_size, LengthResolvePhase::kLayout,
+ LengthResolvePhase::kLayout,
opt_percentage_resolution_block_size_for_min_max);
const Length& logical_height = style.LogicalHeight();
// Scrollable percentage-sized children of table cells, in the table
@@ -518,7 +444,7 @@ LayoutUnit ComputeBlockSizeForFragmentInternal(
LayoutUnit max = ResolveMaxBlockLength(
constraint_space, style, border_padding, style.LogicalMaxHeight(),
- content_size, LengthResolvePhase::kLayout,
+ LengthResolvePhase::kLayout,
opt_percentage_resolution_block_size_for_min_max);
return ConstrainByMinMax(extent, min, max);
@@ -546,9 +472,9 @@ LayoutUnit ComputeBlockSizeForFragment(
}
// Computes size for a replaced element.
-void ComputeReplacedSize(const NGLayoutInputNode& node,
+void ComputeReplacedSize(const NGBlockNode& node,
const NGConstraintSpace& space,
- const base::Optional<MinMaxSize>& child_minmax,
+ const base::Optional<MinMaxSizes>& child_min_max_sizes,
base::Optional<LogicalSize>* out_replaced_size,
base::Optional<LogicalSize>* out_aspect_ratio) {
DCHECK(node.IsReplaced());
@@ -558,26 +484,26 @@ void ComputeReplacedSize(const NGLayoutInputNode& node,
const ComputedStyle& style = node.Style();
NGBoxStrut border_padding =
- ComputeBorders(space, node) + ComputePadding(space, style);
+ ComputeBorders(space, style) + ComputePadding(space, style);
LayoutUnit inline_min = ResolveMinInlineLength(
- space, style, border_padding, child_minmax, style.LogicalMinWidth(),
- LengthResolvePhase::kLayout);
+ space, style, border_padding, child_min_max_sizes,
+ style.LogicalMinWidth(), LengthResolvePhase::kLayout);
LayoutUnit inline_max = ResolveMaxInlineLength(
- space, style, border_padding, child_minmax, style.LogicalMaxWidth(),
- LengthResolvePhase::kLayout);
- LayoutUnit block_min = ResolveMinBlockLength(
- space, style, border_padding, style.LogicalMinHeight(),
- border_padding.BlockSum(), LengthResolvePhase::kLayout);
- LayoutUnit block_max = ResolveMaxBlockLength(
- space, style, border_padding, style.LogicalMaxHeight(), LayoutUnit::Max(),
- LengthResolvePhase::kLayout);
+ space, style, border_padding, child_min_max_sizes,
+ style.LogicalMaxWidth(), LengthResolvePhase::kLayout);
+ LayoutUnit block_min = ResolveMinBlockLength(space, style, border_padding,
+ style.LogicalMinHeight(),
+ LengthResolvePhase::kLayout);
+ LayoutUnit block_max = ResolveMaxBlockLength(space, style, border_padding,
+ style.LogicalMaxHeight(),
+ LengthResolvePhase::kLayout);
const Length& inline_length = style.LogicalWidth();
const Length& block_length = style.LogicalHeight();
base::Optional<LayoutUnit> replaced_inline;
if (!inline_length.IsAuto()) {
- replaced_inline = ResolveMainInlineLength(space, style, border_padding,
- child_minmax, inline_length);
+ replaced_inline = ResolveMainInlineLength(
+ space, style, border_padding, child_min_max_sizes, inline_length);
replaced_inline =
ConstrainByMinMax(*replaced_inline, inline_min, inline_max);
}
@@ -595,9 +521,10 @@ void ComputeReplacedSize(const NGLayoutInputNode& node,
base::Optional<LayoutUnit> intrinsic_inline;
base::Optional<LayoutUnit> intrinsic_block;
- LogicalSize aspect_ratio;
+ node.IntrinsicSize(&intrinsic_inline, &intrinsic_block);
+
+ LogicalSize aspect_ratio = node.GetAspectRatio();
- node.IntrinsicSize(&intrinsic_inline, &intrinsic_block, &aspect_ratio);
// Computing intrinsic size is complicated by the fact that
// intrinsic_inline, intrinsic_block, and aspect_ratio can all
// be empty independent of each other.
@@ -850,7 +777,7 @@ NGBoxStrut ComputeBordersInternal(const ComputedStyle& style) {
} // namespace
NGBoxStrut ComputeBorders(const NGConstraintSpace& constraint_space,
- const NGLayoutInputNode node) {
+ const ComputedStyle& style) {
// If we are producing an anonymous fragment (e.g. a column), it has no
// borders, padding or scrollbars. Using the ones from the container can only
// cause trouble.
@@ -862,7 +789,7 @@ NGBoxStrut ComputeBorders(const NGConstraintSpace& constraint_space,
if (constraint_space.IsTableCell())
return constraint_space.TableCellBorders();
- return ComputeBordersInternal(node.Style());
+ return ComputeBordersInternal(style);
}
NGBoxStrut ComputeBordersForInline(const ComputedStyle& style) {
@@ -1058,7 +985,7 @@ NGFragmentGeometry CalculateInitialFragmentGeometry(
const NGBlockNode& node) {
const ComputedStyle& style = node.Style();
- NGBoxStrut border = ComputeBorders(constraint_space, node);
+ NGBoxStrut border = ComputeBorders(constraint_space, style);
NGBoxStrut padding = ComputePadding(constraint_space, style);
NGBoxStrut scrollbar = ComputeScrollbars(constraint_space, node);
NGBoxStrut border_padding = border + padding;
@@ -1096,8 +1023,9 @@ NGFragmentGeometry CalculateInitialFragmentGeometry(
NGFragmentGeometry CalculateInitialMinMaxFragmentGeometry(
const NGConstraintSpace& constraint_space,
const NGBlockNode& node) {
- NGBoxStrut border = ComputeBorders(constraint_space, node);
- NGBoxStrut padding = ComputePadding(constraint_space, node.Style());
+ const ComputedStyle& style = node.Style();
+ NGBoxStrut border = ComputeBorders(constraint_space, style);
+ NGBoxStrut padding = ComputePadding(constraint_space, style);
NGBoxStrut scrollbar = ComputeScrollbars(constraint_space, node);
return {/* border_box_size */ LogicalSize(), border, scrollbar, padding};
@@ -1210,7 +1138,10 @@ LayoutUnit CalculateChildPercentageBlockSizeForMinMax(
const NGBoxStrut& border_padding,
LayoutUnit parent_percentage_block_size) {
// Anonymous block or spaces should pass the percent size straight through.
- if (space.IsAnonymous() || node.IsAnonymousBlock())
+ // If this node is OOF-positioned, our size was pre-calculated and we should
+ // pass this through to our children.
+ if (space.IsAnonymous() || node.IsAnonymousBlock() ||
+ node.IsOutOfFlowPositioned())
return parent_percentage_block_size;
LayoutUnit block_size = ComputeBlockSizeForFragmentInternal(
@@ -1225,8 +1156,7 @@ LayoutUnit CalculateChildPercentageBlockSizeForMinMax(
// For OOF-positioned nodes, use the parent (containing-block) size.
if (child_percentage_block_size == kIndefiniteSize &&
- (node.UseParentPercentageResolutionBlockSizeForChildren() ||
- node.IsOutOfFlowPositioned()))
+ node.UseParentPercentageResolutionBlockSizeForChildren())
child_percentage_block_size = parent_percentage_block_size;
return child_percentage_block_size;
@@ -1255,8 +1185,13 @@ LayoutUnit ClampIntrinsicBlockSize(
// If the intrinsic size was overridden, then use that.
LayoutUnit intrinsic_size_override = node.OverrideIntrinsicContentBlockSize();
- if (intrinsic_size_override != kIndefiniteSize)
+ if (intrinsic_size_override != kIndefiniteSize) {
return intrinsic_size_override + border_scrollbar_padding.BlockSum();
+ } else {
+ LayoutUnit default_intrinsic_size = node.DefaultIntrinsicContentBlockSize();
+ if (default_intrinsic_size != kIndefiniteSize)
+ return default_intrinsic_size + border_scrollbar_padding.BlockSum();
+ }
// If we have size containment, we ignore child contributions to intrinsic
// sizing.
@@ -1265,13 +1200,11 @@ LayoutUnit ClampIntrinsicBlockSize(
return current_intrinsic_block_size;
}
-base::Optional<MinMaxSize> CalculateMinMaxSizesIgnoringChildren(
+base::Optional<MinMaxSizes> CalculateMinMaxSizesIgnoringChildren(
const NGBlockNode& node,
- const NGBoxStrut& border_scrollbar_padding,
- NGMinMaxSizeType type) {
- MinMaxSize sizes;
- if (type == NGMinMaxSizeType::kBorderBoxSize)
- sizes += border_scrollbar_padding.InlineSum();
+ const NGBoxStrut& border_scrollbar_padding) {
+ MinMaxSizes sizes;
+ sizes += border_scrollbar_padding.InlineSum();
// If intrinsic size was overridden, then use that.
const LayoutUnit intrinsic_size_override =
@@ -1279,6 +1212,12 @@ base::Optional<MinMaxSize> CalculateMinMaxSizesIgnoringChildren(
if (intrinsic_size_override != kIndefiniteSize) {
sizes += intrinsic_size_override;
return sizes;
+ } else {
+ LayoutUnit default_inline_size = node.DefaultIntrinsicContentInlineSize();
+ if (default_inline_size != kIndefiniteSize) {
+ sizes += default_inline_size;
+ return sizes;
+ }
}
// Size contained elements don't consider children for intrinsic sizing.
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
index 525a28b6cec..2a618216acc 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h
@@ -9,7 +9,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/geometry/logical_size.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
-#include "third_party/blink/renderer/core/layout/min_max_size.h"
+#include "third_party/blink/renderer/core/layout/min_max_sizes.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_fragment_geometry.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
@@ -22,7 +22,7 @@
namespace blink {
class ComputedStyle;
class Length;
-struct MinMaxSizeInput;
+struct MinMaxSizesInput;
class NGConstraintSpace;
class NGBlockNode;
class NGLayoutInputNode;
@@ -41,15 +41,6 @@ inline bool NeedMinMaxSize(const ComputedStyle& style) {
style.LogicalMaxWidth().IsIntrinsic();
}
-// Whether the caller needs to compute min-content and max-content sizes to
-// pass them to ResolveMainInlineLength / ComputeInlineSizeForFragment.
-// If this function returns false, it is safe to pass an empty
-// MinMaxSize struct to those functions.
-inline bool NeedMinMaxSize(const NGConstraintSpace& constraint_space,
- const ComputedStyle& style) {
- return constraint_space.IsShrinkToFit() || NeedMinMaxSize(style);
-}
-
// Like NeedMinMaxSize, but for use when calling
// ComputeMinAndMaxContentContribution.
// Because content contributions are commonly needed by a block's parent,
@@ -75,17 +66,17 @@ CORE_EXPORT bool BlockLengthUnresolvable(
// available-size.
// - |ComputedStyle| the style of the node.
// - |border_padding| the resolved border, and padding of the node.
-// - |MinMaxSize| is only used when the length is intrinsic (fit-content).
+// - |MinMaxSizes| is only used when the length is intrinsic (fit-content).
// - |Length| is the length to resolve.
CORE_EXPORT LayoutUnit
ResolveInlineLengthInternal(const NGConstraintSpace&,
const ComputedStyle&,
const NGBoxStrut& border_padding,
- const base::Optional<MinMaxSize>&,
+ const base::Optional<MinMaxSizes>&,
const Length&);
// Same as ResolveInlineLengthInternal, except here |content_size| roughly plays
-// the part of |MinMaxSize|.
+// the part of |MinMaxSizes|.
CORE_EXPORT LayoutUnit ResolveBlockLengthInternal(
const NGConstraintSpace&,
const ComputedStyle&,
@@ -97,44 +88,100 @@ CORE_EXPORT LayoutUnit ResolveBlockLengthInternal(
nullptr);
// Used for resolving min inline lengths, (|ComputedStyle::MinLogicalWidth|).
+template <typename MinMaxSizesFunc>
inline LayoutUnit ResolveMinInlineLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
- const base::Optional<MinMaxSize>& min_and_max,
+ const MinMaxSizesFunc& min_max_sizes_func,
+ const Length& length,
+ LengthResolvePhase phase) {
+ if (LIKELY(length.IsAuto() || InlineLengthUnresolvable(length, phase)))
+ return border_padding.InlineSum();
+
+ base::Optional<MinMaxSizes> min_max_sizes;
+ if (length.IsIntrinsic())
+ min_max_sizes = min_max_sizes_func();
+
+ return ResolveInlineLengthInternal(constraint_space, style, border_padding,
+ min_max_sizes, length);
+}
+
+template <>
+inline LayoutUnit ResolveMinInlineLength<base::Optional<MinMaxSizes>>(
+ const NGConstraintSpace& constraint_space,
+ const ComputedStyle& style,
+ const NGBoxStrut& border_padding,
+ const base::Optional<MinMaxSizes>& min_max_sizes,
const Length& length,
LengthResolvePhase phase) {
if (LIKELY(length.IsAuto() || InlineLengthUnresolvable(length, phase)))
return border_padding.InlineSum();
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
- min_and_max, length);
+ min_max_sizes, length);
}
// Used for resolving max inline lengths, (|ComputedStyle::MaxLogicalWidth|).
+template <typename MinMaxSizesFunc>
inline LayoutUnit ResolveMaxInlineLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
- const base::Optional<MinMaxSize>& min_and_max,
+ const MinMaxSizesFunc& min_max_sizes_func,
const Length& length,
LengthResolvePhase phase) {
- if (LIKELY(length.IsMaxSizeNone() || InlineLengthUnresolvable(length, phase)))
+ if (LIKELY(length.IsNone() || InlineLengthUnresolvable(length, phase)))
return LayoutUnit::Max();
+ base::Optional<MinMaxSizes> min_max_sizes;
+ if (length.IsIntrinsic())
+ min_max_sizes = min_max_sizes_func();
+
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
- min_and_max, length);
+ min_max_sizes, length);
+}
+
+template <>
+inline LayoutUnit ResolveMaxInlineLength<base::Optional<MinMaxSizes>>(
+ const NGConstraintSpace& constraint_space,
+ const ComputedStyle& style,
+ const NGBoxStrut& border_padding,
+ const base::Optional<MinMaxSizes>& min_max_sizes,
+ const Length& length,
+ LengthResolvePhase phase) {
+ if (LIKELY(length.IsNone() || InlineLengthUnresolvable(length, phase)))
+ return LayoutUnit::Max();
+
+ return ResolveInlineLengthInternal(constraint_space, style, border_padding,
+ min_max_sizes, length);
}
// Used for resolving main inline lengths, (|ComputedStyle::LogicalWidth|).
+template <typename MinMaxSizesFunc>
inline LayoutUnit ResolveMainInlineLength(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const NGBoxStrut& border_padding,
- const base::Optional<MinMaxSize>& min_and_max,
+ const MinMaxSizesFunc& min_max_sizes_func,
+ const Length& length) {
+ base::Optional<MinMaxSizes> min_max_sizes;
+ if (length.IsIntrinsic())
+ min_max_sizes = min_max_sizes_func();
+
+ return ResolveInlineLengthInternal(constraint_space, style, border_padding,
+ min_max_sizes, length);
+}
+
+template <>
+inline LayoutUnit ResolveMainInlineLength<base::Optional<MinMaxSizes>>(
+ const NGConstraintSpace& constraint_space,
+ const ComputedStyle& style,
+ const NGBoxStrut& border_padding,
+ const base::Optional<MinMaxSizes>& min_max_sizes,
const Length& length) {
return ResolveInlineLengthInternal(constraint_space, style, border_padding,
- min_and_max, length);
+ min_max_sizes, length);
}
// Used for resolving min block lengths, (|ComputedStyle::MinLogicalHeight|).
@@ -143,7 +190,6 @@ inline LayoutUnit ResolveMinBlockLength(
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const Length& length,
- LayoutUnit content_size,
LengthResolvePhase phase,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr) {
@@ -153,7 +199,7 @@ inline LayoutUnit ResolveMinBlockLength(
return border_padding.BlockSum();
return ResolveBlockLengthInternal(
- constraint_space, style, border_padding, length, content_size, phase,
+ constraint_space, style, border_padding, length, kIndefiniteSize, phase,
opt_percentage_resolution_block_size_for_min_max);
}
@@ -163,7 +209,6 @@ inline LayoutUnit ResolveMaxBlockLength(
const ComputedStyle& style,
const NGBoxStrut& border_padding,
const Length& length,
- LayoutUnit content_size,
LengthResolvePhase phase,
const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
nullptr) {
@@ -173,7 +218,7 @@ inline LayoutUnit ResolveMaxBlockLength(
return LayoutUnit::Max();
return ResolveBlockLengthInternal(
- constraint_space, style, border_padding, length, content_size, phase,
+ constraint_space, style, border_padding, length, kIndefiniteSize, phase,
opt_percentage_resolution_block_size_for_min_max);
}
@@ -198,6 +243,31 @@ inline LayoutUnit ResolveMainBlockLength(
opt_percentage_resolution_block_size_for_min_max);
}
+template <typename IntrinsicBlockSizeFunc>
+inline LayoutUnit ResolveMainBlockLength(
+ const NGConstraintSpace& constraint_space,
+ const ComputedStyle& style,
+ const NGBoxStrut& border_padding,
+ const Length& length,
+ const IntrinsicBlockSizeFunc& intrinsic_block_size_func,
+ LengthResolvePhase phase,
+ const LayoutUnit* opt_percentage_resolution_block_size_for_min_max =
+ nullptr) {
+ if (UNLIKELY((length.IsPercentOrCalc() || length.IsFillAvailable()) &&
+ BlockLengthUnresolvable(
+ constraint_space, length, phase,
+ opt_percentage_resolution_block_size_for_min_max)))
+ return intrinsic_block_size_func();
+
+ LayoutUnit intrinsic_block_size = kIndefiniteSize;
+ if (length.IsIntrinsicOrAuto())
+ intrinsic_block_size = intrinsic_block_size_func();
+
+ return ResolveBlockLengthInternal(
+ constraint_space, style, border_padding, length, intrinsic_block_size,
+ phase, opt_percentage_resolution_block_size_for_min_max);
+}
+
// For the given style and min/max content sizes, computes the min and max
// content contribution (https://drafts.csswg.org/css-sizing/#contributions).
// This is similar to ComputeInlineSizeForFragment except that it does not
@@ -208,11 +278,11 @@ inline LayoutUnit ResolveMainBlockLength(
// Because content contributions are commonly needed by a block's parent,
// we also take a writing mode here so we can compute this in the parent's
// coordinate system.
-CORE_EXPORT MinMaxSize
+CORE_EXPORT MinMaxSizes
ComputeMinAndMaxContentContribution(WritingMode writing_mode,
const ComputedStyle&,
const NGBoxStrut& border_padding,
- const base::Optional<MinMaxSize>&);
+ const base::Optional<MinMaxSizes>&);
// A version of ComputeMinAndMaxContentContribution that does not require you
// to compute the min/max content size of the child. Instead, this function
@@ -222,31 +292,22 @@ ComputeMinAndMaxContentContribution(WritingMode writing_mode,
// parent, we'll still return the inline min/max contribution in the writing
// mode of the parent (i.e. typically something based on the preferred *block*
// size of the child).
-MinMaxSize ComputeMinAndMaxContentContribution(
+MinMaxSizes ComputeMinAndMaxContentContribution(
const ComputedStyle& parent_style,
NGLayoutInputNode child,
- const MinMaxSizeInput&);
-
-// Computes the min/max-content size for an out-of-flow positioned node and
-// returns it, using the cache where possible. ALways computes it in the writing
-// mode of the node itself.
-MinMaxSize ComputeMinAndMaxContentSizeForOutOfFlow(
- const NGConstraintSpace&,
- NGLayoutInputNode,
- const NGBoxStrut& border_padding,
- const MinMaxSizeInput&);
+ const MinMaxSizesInput&);
// Returns inline size of the node's border box by resolving the computed value
// in style.logicalWidth (Length) to a layout unit, adding border and padding,
// then constraining the result by the resolved min logical width and max
// logical width from the ComputedStyle object. Calls Node::ComputeMinMaxSize
// if needed.
-// |override_minmax_for_test| is provided *solely* for use by unit tests.
+// |override_min_max_sizes_for_test| is provided *solely* for use by unit tests.
CORE_EXPORT LayoutUnit ComputeInlineSizeForFragment(
const NGConstraintSpace&,
NGLayoutInputNode,
const NGBoxStrut& border_padding,
- const MinMaxSize* override_minmax_for_test = nullptr);
+ const MinMaxSizes* override_min_max_sizes_for_test = nullptr);
// Same as ComputeInlineSizeForFragment, but uses height instead of width.
CORE_EXPORT LayoutUnit
@@ -265,9 +326,9 @@ ComputeBlockSizeForFragment(const NGConstraintSpace&,
// - neither out_aspect_ratio, nor out_replaced_size
// SVG elements can return any of the three options above.
CORE_EXPORT void ComputeReplacedSize(
- const NGLayoutInputNode&,
+ const NGBlockNode&,
const NGConstraintSpace&,
- const base::Optional<MinMaxSize>&,
+ const base::Optional<MinMaxSizes>&,
base::Optional<LogicalSize>* out_replaced_size,
base::Optional<LogicalSize>* out_aspect_ratio);
@@ -364,7 +425,7 @@ CORE_EXPORT NGBoxStrut ComputeMinMaxMargins(const ComputedStyle& parent_style,
NGLayoutInputNode child);
CORE_EXPORT NGBoxStrut ComputeBorders(const NGConstraintSpace&,
- const NGLayoutInputNode);
+ const ComputedStyle&);
CORE_EXPORT NGBoxStrut ComputeBordersForInline(const ComputedStyle& style);
@@ -480,11 +541,9 @@ LayoutUnit ClampIntrinsicBlockSize(
// without considering children. If so, it returns the calculated size.
// Otherwise, it returns base::nullopt and the caller has to compute the size
// itself.
-base::Optional<MinMaxSize> CalculateMinMaxSizesIgnoringChildren(
+base::Optional<MinMaxSizes> CalculateMinMaxSizesIgnoringChildren(
const NGBlockNode&,
- const NGBoxStrut& border_scrollbar_padding,
- NGMinMaxSizeType);
-
+ const NGBoxStrut& border_scrollbar_padding);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
index 6b63229023f..f374f55a0cb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc
@@ -41,7 +41,7 @@ class NGLengthUtilsTest : public testing::Test {
LayoutUnit ResolveMainInlineLength(
const Length& length,
- const base::Optional<MinMaxSize>& sizes = base::nullopt) {
+ const base::Optional<MinMaxSizes>& sizes = base::nullopt) {
NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300);
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
@@ -53,7 +53,7 @@ class NGLengthUtilsTest : public testing::Test {
LayoutUnit ResolveMinInlineLength(
const Length& length,
LengthResolvePhase phase = LengthResolvePhase::kLayout,
- const base::Optional<MinMaxSize>& sizes = base::nullopt) {
+ const base::Optional<MinMaxSizes>& sizes = base::nullopt) {
NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300);
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
@@ -65,7 +65,7 @@ class NGLengthUtilsTest : public testing::Test {
LayoutUnit ResolveMaxInlineLength(
const Length& length,
LengthResolvePhase phase = LengthResolvePhase::kLayout,
- const base::Optional<MinMaxSize>& sizes = base::nullopt) {
+ const base::Optional<MinMaxSizes>& sizes = base::nullopt) {
NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300);
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
@@ -97,10 +97,10 @@ class NGLengthUtilsTestWithNode : public NGLayoutTest {
LayoutUnit ComputeInlineSizeForFragment(
NGConstraintSpace constraint_space = ConstructConstraintSpace(200, 300),
- const MinMaxSize& sizes = MinMaxSize()) {
+ const MinMaxSizes& sizes = MinMaxSizes()) {
LayoutBox* body = ToLayoutBox(GetDocument().body()->GetLayoutObject());
body->SetStyle(style_);
- body->SetPreferredLogicalWidthsDirty();
+ body->SetIntrinsicLogicalWidthsDirty();
NGBlockNode node(body);
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
@@ -114,7 +114,7 @@ class NGLengthUtilsTestWithNode : public NGLayoutTest {
LayoutUnit content_size = LayoutUnit()) {
LayoutBox* body = ToLayoutBox(GetDocument().body()->GetLayoutObject());
body->SetStyle(style_);
- body->SetPreferredLogicalWidthsDirty();
+ body->SetIntrinsicLogicalWidthsDirty();
NGBoxStrut border_padding = ComputeBordersForTest(*style_) +
ComputePadding(constraint_space, *style_);
@@ -139,7 +139,7 @@ TEST_F(NGLengthUtilsTest, testResolveInlineLength) {
EXPECT_EQ(LayoutUnit::Max(),
ResolveMaxInlineLength(Length::FillAvailable(),
LengthResolvePhase::kIntrinsic));
- MinMaxSize sizes;
+ MinMaxSizes sizes;
sizes.min_size = LayoutUnit(30);
sizes.max_size = LayoutUnit(40);
EXPECT_EQ(LayoutUnit(30),
@@ -168,13 +168,13 @@ TEST_F(NGLengthUtilsTest, testResolveBlockLength) {
}
TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
- MinMaxSize sizes;
+ MinMaxSizes sizes;
sizes.min_size = LayoutUnit(30);
sizes.max_size = LayoutUnit(40);
NGBoxStrut border_padding;
- MinMaxSize expected = sizes;
+ MinMaxSizes expected = sizes;
style_->SetLogicalWidth(Length::Percent(30));
EXPECT_EQ(expected,
ComputeMinAndMaxContentContribution(
@@ -185,7 +185,7 @@ TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
ComputeMinAndMaxContentContribution(
style_->GetWritingMode(), *style_, border_padding, sizes));
- expected = MinMaxSize{LayoutUnit(150), LayoutUnit(150)};
+ expected = MinMaxSizes{LayoutUnit(150), LayoutUnit(150)};
style_->SetLogicalWidth(Length::Fixed(150));
EXPECT_EQ(expected,
ComputeMinAndMaxContentContribution(
@@ -197,7 +197,7 @@ TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
ComputeMinAndMaxContentContribution(
style_->GetWritingMode(), *style_, border_padding, sizes));
- expected = MinMaxSize{LayoutUnit(430), LayoutUnit(440)};
+ expected = MinMaxSizes{LayoutUnit(430), LayoutUnit(440)};
style_->SetPaddingLeft(Length::Fixed(400));
auto sizes_padding400 = sizes;
sizes_padding400 += LayoutUnit(400);
@@ -207,7 +207,7 @@ TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
style_->GetWritingMode(), *style_, border_padding400,
sizes_padding400));
- expected = MinMaxSize{LayoutUnit(30), LayoutUnit(40)};
+ expected = MinMaxSizes{LayoutUnit(30), LayoutUnit(40)};
style_->SetPaddingLeft(Length::Fixed(0));
style_->SetLogicalWidth(Length(CalculationValue::Create(
PixelsAndPercent(100, -10), kValueRangeNonNegative)));
@@ -215,21 +215,21 @@ TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
ComputeMinAndMaxContentContribution(
style_->GetWritingMode(), *style_, border_padding, sizes));
- expected = MinMaxSize{LayoutUnit(30), LayoutUnit(35)};
+ expected = MinMaxSizes{LayoutUnit(30), LayoutUnit(35)};
style_->SetLogicalWidth(Length::Auto());
style_->SetMaxWidth(Length::Fixed(35));
EXPECT_EQ(expected,
ComputeMinAndMaxContentContribution(
style_->GetWritingMode(), *style_, border_padding, sizes));
- expected = MinMaxSize{LayoutUnit(80), LayoutUnit(80)};
+ expected = MinMaxSizes{LayoutUnit(80), LayoutUnit(80)};
style_->SetLogicalWidth(Length::Fixed(50));
style_->SetMinWidth(Length::Fixed(80));
EXPECT_EQ(expected,
ComputeMinAndMaxContentContribution(
style_->GetWritingMode(), *style_, border_padding, sizes));
- expected = MinMaxSize{LayoutUnit(150), LayoutUnit(150)};
+ expected = MinMaxSizes{LayoutUnit(150), LayoutUnit(150)};
style_ = ComputedStyle::Create();
style_->SetLogicalWidth(Length::Fixed(100));
style_->SetPaddingLeft(Length::Fixed(50));
@@ -241,7 +241,7 @@ TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
style_->GetWritingMode(), *style_, border_padding50,
sizes_padding50));
- expected = MinMaxSize{LayoutUnit(100), LayoutUnit(100)};
+ expected = MinMaxSizes{LayoutUnit(100), LayoutUnit(100)};
style_->SetBoxSizing(EBoxSizing::kBorderBox);
EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
style_->GetWritingMode(), *style_, border_padding50,
@@ -249,7 +249,7 @@ TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
// Content size should never be below zero, even with box-sizing: border-box
// and a large padding...
- expected = MinMaxSize{LayoutUnit(400), LayoutUnit(400)};
+ expected = MinMaxSizes{LayoutUnit(400), LayoutUnit(400)};
style_->SetPaddingLeft(Length::Fixed(400));
EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
style_->GetWritingMode(), *style_, border_padding400,
@@ -264,11 +264,11 @@ TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
style_->SetMaxWidth(Length::MaxContent());
// Due to padding and box-sizing, width computes to 400px and max-width to
// 440px, so the result is 400.
- expected = MinMaxSize{LayoutUnit(400), LayoutUnit(400)};
+ expected = MinMaxSizes{LayoutUnit(400), LayoutUnit(400)};
EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
style_->GetWritingMode(), *style_, border_padding400,
sizes_padding400));
- expected = MinMaxSize{LayoutUnit(40), LayoutUnit(40)};
+ expected = MinMaxSizes{LayoutUnit(40), LayoutUnit(40)};
style_->SetPaddingLeft(Length::Fixed(0));
EXPECT_EQ(expected,
ComputeMinAndMaxContentContribution(
@@ -276,7 +276,7 @@ TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
}
TEST_F(NGLengthUtilsTestWithNode, testComputeInlineSizeForFragment) {
- MinMaxSize sizes;
+ MinMaxSizes sizes;
sizes.min_size = LayoutUnit(30);
sizes.max_size = LayoutUnit(40);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
index df903e64148..0df01829351 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc
@@ -237,10 +237,8 @@ bool NGOutOfFlowLayoutPart::SweepLegacyCandidates(
// size first.
// We perform a pre-layout to correctly determine the static position.
// Copied from LayoutBlock::LayoutPositionedObject
+ // TODO(layout-dev): Remove this once LayoutFlexibleBox is removed.
LayoutBox* layout_box = ToLayoutBox(legacy_object);
- // TODO(dgrogan): The NG flexbox implementation doesn't have an
- // analogous method yet, so abspos children of NG flexboxes that have a
- // legacy containing block will not be positioned correctly.
if (layout_box->Parent()->IsFlexibleBox()) {
LayoutFlexibleBox* parent = ToLayoutFlexibleBox(layout_box->Parent());
if (parent->SetStaticPositionForPositionedLayout(*layout_box)) {
@@ -293,22 +291,22 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
inline_geometry);
}
}
- // Fetch start/end fragment info.
- container_builder_->ComputeInlineContainerFragments(
- &inline_container_fragments);
+
+ // Fetch the inline start/end fragment geometry.
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ container_builder_->ComputeInlineContainerGeometry(
+ &inline_container_fragments);
+ } else {
+ container_builder_->ComputeInlineContainerGeometryFromFragmentTree(
+ &inline_container_fragments);
+ }
+
LogicalSize container_builder_size = container_builder_->Size();
PhysicalSize container_builder_physical_size =
ToPhysicalSize(container_builder_size, writing_mode_);
- // Translate start/end fragments into ContainingBlockInfo.
+ // Transform the start/end fragments into a ContainingBlockInfo.
for (auto& block_info : inline_container_fragments) {
- // Variables needed to describe ContainingBlockInfo
- const ComputedStyle* inline_cb_style = block_info.key->Style();
- LogicalSize inline_cb_size;
- LogicalOffset container_offset;
-
DCHECK(block_info.value.has_value());
- DCHECK(inline_cb_style);
- NGBoxStrut inline_cb_borders = ComputeBordersForInline(*inline_cb_style);
// The calculation below determines the size of the inline containing block
// rect.
@@ -362,7 +360,11 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
//
// Note in cases [2a, 2b] we don't allow a "negative" containing block size,
// we clamp negative sizes to zero.
+ const ComputedStyle* inline_cb_style = block_info.key->Style();
+ DCHECK(inline_cb_style);
+
TextDirection container_direction = default_containing_block_.direction;
+ NGBoxStrut inline_cb_borders = ComputeBordersForInline(*inline_cb_style);
bool is_same_direction =
container_direction == inline_cb_style->Direction();
@@ -403,13 +405,14 @@ void NGOutOfFlowLayoutPart::ComputeInlineContainingBlocks(
// Step 3 - determine the logical rectangle.
// Determine the logical size of the containing block.
- inline_cb_size = {end_offset.inline_offset - start_offset.inline_offset,
- end_offset.block_offset - start_offset.block_offset};
+ LogicalSize inline_cb_size = {
+ end_offset.inline_offset - start_offset.inline_offset,
+ end_offset.block_offset - start_offset.block_offset};
DCHECK_GE(inline_cb_size.inline_size, LayoutUnit());
DCHECK_GE(inline_cb_size.block_size, LayoutUnit());
// Set the container padding-box offset.
- container_offset = start_offset;
+ LogicalOffset container_offset = start_offset;
containing_blocks_map_.insert(
block_info.key,
@@ -525,12 +528,12 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::LayoutCandidate(
// Since out-of-flow positioning sets up a constraint space with fixed
// inline-size, the regular layout code (|NGBlockNode::Layout()|) cannot
// re-layout if it discovers that a scrollbar was added or removed. Handle
- // that situation here. The assumption is that if preferred logical widths
- // are dirty after layout, AND its inline-size depends on preferred
+ // that situation here. The assumption is that if intrinsic logical widths
+ // are dirty after layout, AND its inline-size depends on the intrinsic
// logical widths, it means that scrollbars appeared or disappeared. We
// have the same logic in legacy layout in
// |LayoutBlockFlow::UpdateBlockLayout()|.
- if (node.GetLayoutBox()->PreferredLogicalWidthsDirty() &&
+ if (node.GetLayoutBox()->IntrinsicLogicalWidthsDirty() &&
AbsoluteNeedsChildInlineSize(candidate_style)) {
// Freeze the scrollbars for this layout pass. We don't want them to
// change *again*.
@@ -561,12 +564,12 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
LogicalSize container_content_size_in_candidate_writing_mode =
container_physical_content_size.ConvertToLogical(candidate_writing_mode);
NGBoxStrut border_padding =
- ComputeBorders(candidate_constraint_space, node) +
+ ComputeBorders(candidate_constraint_space, candidate_style) +
ComputePadding(candidate_constraint_space, candidate_style);
// The |block_estimate| is wrt. the candidate's writing mode.
base::Optional<LayoutUnit> block_estimate;
- base::Optional<MinMaxSize> min_max_size;
+ base::Optional<MinMaxSizes> min_max_sizes;
scoped_refptr<const NGLayoutResult> layout_result = nullptr;
// In order to calculate the offsets, we may need to know the size.
@@ -577,45 +580,61 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
// words, in that case, we may have to lay out, calculate the offset, and
// then lay out again at the correct block-offset.
+ NGLogicalOutOfFlowDimensions node_dimensions;
+ bool has_computed_block_dimensions = false;
bool is_replaced = node.IsReplaced();
bool should_be_considered_as_replaced = node.ShouldBeConsideredAsReplaced();
+ bool absolute_needs_child_block_size =
+ AbsoluteNeedsChildBlockSize(candidate_style);
if (AbsoluteNeedsChildInlineSize(candidate_style) ||
NeedMinMaxSize(candidate_style) || should_be_considered_as_replaced) {
- // This is a new formatting context, so whatever happened on the outside
- // doesn't concern us.
- MinMaxSizeInput input(container_content_size.block_size);
- min_max_size = ComputeMinAndMaxContentSizeForOutOfFlow(
- candidate_constraint_space, node, border_padding, input);
+ MinMaxSizesInput input(kIndefiniteSize);
+ if (is_replaced) {
+ input.percentage_resolution_block_size =
+ container_content_size_in_candidate_writing_mode.block_size;
+ } else if (!absolute_needs_child_block_size) {
+ // If we can determine our block-size ahead of time (it doesn't depend on
+ // our content), we use this for our %-block-size.
+ ComputeOutOfFlowBlockDimensions(
+ candidate_constraint_space, candidate_style, border_padding,
+ candidate_static_position, base::nullopt, base::nullopt,
+ writing_mode_, container_direction, &node_dimensions);
+ has_computed_block_dimensions = true;
+ input.percentage_resolution_block_size = node_dimensions.size.block_size;
+ }
+
+ min_max_sizes = node.ComputeMinMaxSizes(candidate_writing_mode, input,
+ &candidate_constraint_space);
}
base::Optional<LogicalSize> replaced_size;
base::Optional<LogicalSize> replaced_aspect_ratio;
bool is_replaced_with_only_aspect_ratio = false;
if (is_replaced) {
- ComputeReplacedSize(node, candidate_constraint_space, min_max_size,
+ ComputeReplacedSize(node, candidate_constraint_space, min_max_sizes,
&replaced_size, &replaced_aspect_ratio);
is_replaced_with_only_aspect_ratio = !replaced_size &&
replaced_aspect_ratio &&
!replaced_aspect_ratio->IsEmpty();
// If we only have aspect ratio, and no replaced size, intrinsic size
- // defaults to 300x150. min_max_size gets computed from the intrinsic size.
- // We reset the min_max_size because spec says that OOF-positioned size
+ // defaults to 300x150. min_max_sizes gets computed from the intrinsic size.
+ // We reset the min_max_sizes because spec says that OOF-positioned size
// should not be constrained by intrinsic size in this case.
// https://www.w3.org/TR/CSS22/visudet.html#inline-replaced-width
if (is_replaced_with_only_aspect_ratio)
- min_max_size = MinMaxSize{LayoutUnit(), LayoutUnit::NearlyMax()};
+ min_max_sizes = MinMaxSizes{LayoutUnit(), LayoutUnit::NearlyMax()};
} else if (should_be_considered_as_replaced) {
replaced_size =
- LogicalSize{min_max_size->ShrinkToFit(
+ LogicalSize{min_max_sizes->ShrinkToFit(
candidate_constraint_space.AvailableSize().inline_size),
kIndefiniteSize};
}
- NGLogicalOutOfFlowPosition node_position =
- ComputePartialAbsoluteWithChildInlineSize(
- candidate_constraint_space, candidate_style, border_padding,
- candidate_static_position, min_max_size, replaced_size, writing_mode_,
- container_direction);
+
+ ComputeOutOfFlowInlineDimensions(candidate_constraint_space, candidate_style,
+ border_padding, candidate_static_position,
+ min_max_sizes, replaced_size, writing_mode_,
+ container_direction, &node_dimensions);
// |should_be_considered_as_replaced| sets the inline-size.
// It does not set the block-size. This is a compatibility quirk.
@@ -627,16 +646,20 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
// https://www.w3.org/TR/css-sizing-3/#intrinsic-sizes
if (is_replaced_with_only_aspect_ratio) {
replaced_size = LogicalSize(
- node_position.size.inline_size,
+ node_dimensions.size.inline_size,
(replaced_aspect_ratio->block_size *
- ((node_position.size.inline_size - border_padding.InlineSum()) /
+ ((node_dimensions.size.inline_size - border_padding.InlineSum()) /
replaced_aspect_ratio->inline_size)) +
border_padding.BlockSum());
}
- if (AbsoluteNeedsChildBlockSize(candidate_style)) {
+ if (absolute_needs_child_block_size) {
+ DCHECK(!has_computed_block_dimensions);
layout_result =
GenerateFragment(node, container_content_size_in_candidate_writing_mode,
- block_estimate, node_position);
+ block_estimate, node_dimensions);
+
+ // TODO(layout-dev): Handle abortions caused by block fragmentation.
+ DCHECK(layout_result->Status() != NGLayoutResult::kOutOfFragmentainerSpace);
NGFragment fragment(candidate_writing_mode,
layout_result->PhysicalFragment());
@@ -644,15 +667,18 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
block_estimate = fragment.BlockSize();
}
- // Calculate the offsets.
-
- ComputeFullAbsoluteWithChildBlockSize(
- candidate_constraint_space, candidate_style, border_padding,
- candidate_static_position, block_estimate, replaced_size, writing_mode_,
- container_direction, &node_position);
+ // We may have already pre-computed our block-dimensions when determining our
+ // |min_max_sizes|, only run if needed.
+ if (!has_computed_block_dimensions) {
+ ComputeOutOfFlowBlockDimensions(
+ candidate_constraint_space, candidate_style, border_padding,
+ candidate_static_position, block_estimate, replaced_size, writing_mode_,
+ container_direction, &node_dimensions);
+ }
+ // Calculate the offsets.
NGBoxStrut inset =
- node_position.inset
+ node_dimensions.inset
.ConvertToPhysical(candidate_writing_mode, candidate_direction)
.ConvertToLogical(writing_mode_, default_direction);
@@ -719,12 +745,15 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
// Skip this step if we produced a fragment when estimating the block-size.
if (!layout_result) {
- block_estimate = node_position.size.block_size;
+ block_estimate = node_dimensions.size.block_size;
layout_result =
GenerateFragment(node, container_content_size_in_candidate_writing_mode,
- block_estimate, node_position);
+ block_estimate, node_dimensions);
}
+ // TODO(layout-dev): Handle abortions caused by block fragmentation.
+ DCHECK_EQ(layout_result->Status(), NGLayoutResult::kSuccess);
+
// TODO(mstensho): Move the rest of this method back into LayoutCandidate().
if (node.GetLayoutBox()->IsLayoutNGObject()) {
@@ -736,7 +765,7 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::Layout(
if (!container_builder_->GetLayoutObject()
->Style()
->IsDisplayFlexibleOrGridBox()) {
- node.GetLayoutBox()->SetMargin(node_position.margins.ConvertToPhysical(
+ node.GetLayoutBox()->SetMargin(node_dimensions.margins.ConvertToPhysical(
candidate_writing_mode, candidate_direction));
}
@@ -785,12 +814,12 @@ scoped_refptr<const NGLayoutResult> NGOutOfFlowLayoutPart::GenerateFragment(
NGBlockNode node,
const LogicalSize& container_content_size_in_candidate_writing_mode,
const base::Optional<LayoutUnit>& block_estimate,
- const NGLogicalOutOfFlowPosition& node_position) {
+ const NGLogicalOutOfFlowDimensions& node_dimensions) {
// As the |block_estimate| is always in the node's writing mode, we build the
// constraint space in the node's writing mode.
WritingMode writing_mode = node.Style().GetWritingMode();
- LayoutUnit inline_size = node_position.size.inline_size;
+ LayoutUnit inline_size = node_dimensions.size.inline_size;
LayoutUnit block_size = block_estimate.value_or(
container_content_size_in_candidate_writing_mode.block_size);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
index e8d9ad81dbd..777309f62ef 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h
@@ -122,7 +122,7 @@ class CORE_EXPORT NGOutOfFlowLayoutPart {
NGBlockNode node,
const LogicalSize& container_content_size_in_child_writing_mode,
const base::Optional<LayoutUnit>& block_estimate,
- const NGLogicalOutOfFlowPosition& node_position);
+ const NGLogicalOutOfFlowDimensions& node_dimensions);
const NGConstraintSpace& container_space_;
NGBoxFragmentBuilder* container_builder_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h
index 1037e23bca2..3f9a5127140 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_node.h
@@ -54,14 +54,17 @@ struct NGLogicalOutOfFlowPositionedNode {
NGLogicalStaticPosition static_position;
// Continuation root of the optional inline container.
const LayoutInline* inline_container;
+ bool needs_block_offset_adjustment;
NGLogicalOutOfFlowPositionedNode(
NGBlockNode node,
NGLogicalStaticPosition static_position,
- const LayoutInline* inline_container = nullptr)
+ const LayoutInline* inline_container = nullptr,
+ bool needs_block_offset_adjustment = false)
: node(node),
static_position(static_position),
- inline_container(inline_container) {
+ inline_container(inline_container),
+ needs_block_offset_adjustment(needs_block_offset_adjustment) {
DCHECK(!inline_container ||
inline_container == inline_container->ContinuationRoot());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.cc
index dece4940984..805794074b6 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.cc
@@ -46,7 +46,7 @@ bool NGOutlineUtils::ShouldPaintOutline(
NGInlineCursor cursor;
cursor.MoveTo(*layout_object);
DCHECK(cursor);
- return cursor.CurrentBoxFragment() == &physical_fragment;
+ return cursor.Current().BoxFragment() == &physical_fragment;
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc
index 21ab11cf7b5..5328304e619 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc
@@ -5,7 +5,6 @@
#include "third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.h"
#include <algorithm>
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h"
#include "third_party/blink/renderer/core/layout/ng/ng_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
@@ -81,13 +80,13 @@ scoped_refptr<const NGLayoutResult> NGPageLayoutAlgorithm::Layout() {
return container_builder_.ToBoxFragment();
}
-base::Optional<MinMaxSize> NGPageLayoutAlgorithm::ComputeMinMaxSize(
- const MinMaxSizeInput& input) const {
+base::Optional<MinMaxSizes> NGPageLayoutAlgorithm::ComputeMinMaxSizes(
+ const MinMaxSizesInput& input) const {
NGFragmentGeometry fragment_geometry =
CalculateInitialMinMaxFragmentGeometry(ConstraintSpace(), Node());
NGBlockLayoutAlgorithm algorithm(
{Node(), fragment_geometry, ConstraintSpace()});
- return algorithm.ComputeMinMaxSize(input);
+ return algorithm.ComputeMinMaxSizes(input);
}
NGConstraintSpace NGPageLayoutAlgorithm::CreateConstraintSpaceForPages(
@@ -97,9 +96,6 @@ NGConstraintSpace NGPageLayoutAlgorithm::CreateConstraintSpaceForPages(
space_builder.SetAvailableSize(page_size);
space_builder.SetPercentageResolutionSize(page_size);
- if (NGBaseline::ShouldPropagateBaselines(Node()))
- space_builder.AddBaselineRequests(ConstraintSpace().BaselineRequests());
-
// TODO(mstensho): Handle auto block size.
space_builder.SetFragmentationType(kFragmentPage);
space_builder.SetFragmentainerBlockSize(page_size.block_size);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.h
index f05b8a8d717..8797b3ba1ac 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.h
@@ -25,8 +25,8 @@ class CORE_EXPORT NGPageLayoutAlgorithm
scoped_refptr<const NGLayoutResult> Layout() override;
- base::Optional<MinMaxSize> ComputeMinMaxSize(
- const MinMaxSizeInput&) const override;
+ base::Optional<MinMaxSizes> ComputeMinMaxSizes(
+ const MinMaxSizesInput&) const override;
private:
NGConstraintSpace CreateConstraintSpaceForPages(
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
index d550eea7cd0..2092c9bbe84 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_object_inlines.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
@@ -22,7 +23,8 @@ namespace blink {
namespace {
struct SameSizeAsNGPhysicalBoxFragment : NGPhysicalContainerFragment {
- NGBaselineList baselines;
+ LayoutUnit baseline;
+ LayoutUnit last_baseline;
NGLink children[];
};
@@ -63,25 +65,23 @@ scoped_refptr<const NGPhysicalBoxFragment> NGPhysicalBoxFragment::Create(
// we pass the buffer as a constructor argument.
void* data = ::WTF::Partitions::FastMalloc(
byte_size, ::WTF::GetStringWithTypeName<NGPhysicalBoxFragment>());
- new (data) NGPhysicalBoxFragment(builder, borders, padding,
+ new (data) NGPhysicalBoxFragment(PassKey(), builder, borders, padding,
block_or_line_writing_mode);
return base::AdoptRef(static_cast<NGPhysicalBoxFragment*>(data));
}
NGPhysicalBoxFragment::NGPhysicalBoxFragment(
+ PassKey key,
NGBoxFragmentBuilder* builder,
const NGPhysicalBoxStrut& borders,
const NGPhysicalBoxStrut& padding,
WritingMode block_or_line_writing_mode)
- : NGPhysicalContainerFragment(
- builder,
- block_or_line_writing_mode,
- children_,
- (builder->node_ && builder->node_.IsRenderedLegend())
- ? kFragmentRenderedLegend
- : kFragmentBox,
- builder->BoxType()),
- baselines_(builder->baselines_) {
+ : NGPhysicalContainerFragment(builder,
+ block_or_line_writing_mode,
+ children_,
+ kFragmentBox,
+ builder->BoxType()) {
+ DCHECK(layout_object_);
DCHECK(layout_object_->IsBoxModelObject());
if (NGFragmentItemsBuilder* items_builder = builder->ItemsBuilder()) {
has_fragment_items_ = true;
@@ -98,15 +98,34 @@ NGPhysicalBoxFragment::NGPhysicalBoxFragment(
has_padding_ = !padding.IsZero();
if (has_padding_)
*const_cast<NGPhysicalBoxStrut*>(ComputePaddingAddress()) = padding;
- // consumed_block_size_ is only updated if we're in block
- // fragmentation. Otherwise it will always be 0.
- is_first_for_node_ =
- builder->consumed_block_size_ <= builder->size_.block_size;
+ is_first_for_node_ = builder->is_first_for_node_;
is_fieldset_container_ = builder->is_fieldset_container_;
is_legacy_layout_root_ = builder->is_legacy_layout_root_;
+ is_painted_atomically_ =
+ builder->space_ && builder->space_->IsPaintedAtomically();
border_edge_ = builder->border_edges_.ToPhysical(builder->GetWritingMode());
- children_inline_ =
- builder->layout_object_ && builder->layout_object_->ChildrenInline();
+ is_inline_formatting_context_ = builder->is_inline_formatting_context_;
+ is_generated_text_or_math_fraction_ = builder->is_math_fraction_;
+
+ bool has_layout_containment = layout_object_->ShouldApplyLayoutContainment();
+ if (builder->baseline_.has_value() && !has_layout_containment) {
+ has_baseline_ = true;
+ baseline_ = *builder->baseline_;
+ } else {
+ has_baseline_ = false;
+ baseline_ = LayoutUnit::Min();
+ }
+ if (builder->last_baseline_.has_value() && !has_layout_containment) {
+ has_last_baseline_ = true;
+ last_baseline_ = *builder->last_baseline_;
+ } else {
+ has_last_baseline_ = false;
+ last_baseline_ = LayoutUnit::Min();
+ }
+
+#if DCHECK_IS_ON()
+ CheckIntegrity();
+#endif
}
scoped_refptr<const NGLayoutResult>
@@ -153,7 +172,7 @@ PhysicalRect NGPhysicalBoxFragment::ScrollableOverflow() const {
TextDirection container_direction = Style().Direction();
for (const auto& child_fragment : Children()) {
PhysicalRect child_overflow =
- child_fragment->ScrollableOverflowForPropagation(layout_object);
+ child_fragment->ScrollableOverflowForPropagation(*this);
if (child_fragment->Style() != Style()) {
PhysicalOffset relative_offset = ComputeRelativeOffset(
child_fragment->Style(), container_writing_mode,
@@ -170,6 +189,157 @@ PhysicalRect NGPhysicalBoxFragment::ScrollableOverflow() const {
return PhysicalRect({}, Size());
}
+PhysicalRect NGPhysicalBoxFragment::ScrollableOverflowFromChildren() const {
+ const NGFragmentItems* items = Items();
+ if (Children().empty() && !items)
+ return PhysicalRect();
+
+ // Internal struct to share logic between child fragments and child items.
+ // - Inline children's overflow expands by padding end/after.
+ // - Float / OOF overflow is added as is.
+ // - Children not reachable by scroll overflow do not contribute to it.
+ struct ComputeOverflowContext {
+ ComputeOverflowContext(const NGPhysicalBoxFragment& container)
+ : container(container),
+ style(container.Style()),
+ writing_mode(style.GetWritingMode()),
+ direction(style.Direction()),
+ border_inline_start(LayoutUnit(style.BorderStartWidth())),
+ border_block_start(LayoutUnit(style.BorderBeforeWidth())) {
+ DCHECK_EQ(&style, container.GetLayoutObject()->Style(
+ container.UsesFirstLineStyle()));
+
+ // End and under padding are added to scroll overflow of inline children.
+ // https://github.com/w3c/csswg-drafts/issues/129
+ DCHECK_EQ(container.HasOverflowClip(),
+ container.GetLayoutObject()->HasOverflowClip());
+ if (container.HasOverflowClip()) {
+ const LayoutBox* layout_object =
+ ToLayoutBox(container.GetLayoutObject());
+ padding_strut = NGBoxStrut(LayoutUnit(), layout_object->PaddingEnd(),
+ LayoutUnit(), layout_object->PaddingAfter())
+ .ConvertToPhysical(writing_mode, direction);
+ }
+ }
+
+ // Rectangles not reachable by scroll should not be added to overflow.
+ bool IsRectReachableByScroll(const PhysicalRect& rect) {
+ LogicalOffset rect_logical_end =
+ rect.offset.ConvertToLogical(writing_mode, direction,
+ container.Size(), rect.size) +
+ rect.size.ConvertToLogical(writing_mode);
+ return rect_logical_end.inline_offset > border_inline_start &&
+ rect_logical_end.block_offset > border_block_start;
+ }
+
+ void AddChild(const PhysicalRect& child_scrollable_overflow) {
+ // Do not add overflow if fragment is not reachable by scrolling.
+ if (IsRectReachableByScroll(child_scrollable_overflow))
+ children_overflow.Unite(child_scrollable_overflow);
+ }
+
+ void AddFloatingOrOutOfFlowPositionedChild(
+ const NGPhysicalFragment& child,
+ const PhysicalOffset& child_offset) {
+ DCHECK(child.IsFloatingOrOutOfFlowPositioned());
+ PhysicalRect child_scrollable_overflow =
+ child.ScrollableOverflowForPropagation(container);
+ child_scrollable_overflow.offset += ComputeRelativeOffset(
+ child.Style(), writing_mode, direction, container.Size());
+ child_scrollable_overflow.offset += child_offset;
+ AddChild(child_scrollable_overflow);
+ }
+
+ void AddLineBoxChild(const NGPhysicalLineBoxFragment& child,
+ const PhysicalOffset& child_offset) {
+ if (padding_strut)
+ AddLineBoxRect({child_offset, child.Size()});
+ PhysicalRect child_scrollable_overflow =
+ child.ScrollableOverflow(container, style);
+ child_scrollable_overflow.offset += child_offset;
+ AddChild(child_scrollable_overflow);
+ }
+
+ void AddLineBoxChild(const NGFragmentItem& child,
+ const NGInlineCursor& cursor) {
+ DCHECK_EQ(&child, cursor.CurrentItem());
+ DCHECK_EQ(child.Type(), NGFragmentItem::kLine);
+ if (padding_strut)
+ AddLineBoxRect(child.RectInContainerBlock());
+ const NGPhysicalLineBoxFragment* line_box = child.LineBoxFragment();
+ DCHECK(line_box);
+ PhysicalRect child_scrollable_overflow =
+ line_box->ScrollableOverflowForLine(container, style, child, cursor);
+ AddChild(child_scrollable_overflow);
+ }
+
+ void AddLineBoxRect(const PhysicalRect& linebox_rect) {
+ DCHECK(padding_strut);
+ if (lineboxes_enclosing_rect)
+ lineboxes_enclosing_rect->Unite(linebox_rect);
+ else
+ lineboxes_enclosing_rect = linebox_rect;
+ }
+
+ void AddPaddingToLineBoxChildren() {
+ if (lineboxes_enclosing_rect) {
+ DCHECK(padding_strut);
+ lineboxes_enclosing_rect->Expand(*padding_strut);
+ AddChild(*lineboxes_enclosing_rect);
+ }
+ }
+
+ const NGPhysicalBoxFragment& container;
+ const ComputedStyle& style;
+ const WritingMode writing_mode;
+ const TextDirection direction;
+ const LayoutUnit border_inline_start;
+ const LayoutUnit border_block_start;
+ base::Optional<NGPhysicalBoxStrut> padding_strut;
+ base::Optional<PhysicalRect> lineboxes_enclosing_rect;
+ PhysicalRect children_overflow;
+ } context(*this);
+
+ // Traverse child items.
+ if (items) {
+ for (NGInlineCursor cursor(*items); cursor; cursor.MoveToNextSibling()) {
+ const NGFragmentItem* item = cursor.CurrentItem();
+ if (item->Type() == NGFragmentItem::kLine) {
+ context.AddLineBoxChild(*item, cursor);
+ continue;
+ }
+
+ if (const NGPhysicalBoxFragment* child_box = item->BoxFragment()) {
+ if (child_box->IsFloatingOrOutOfFlowPositioned()) {
+ context.AddFloatingOrOutOfFlowPositionedChild(
+ *child_box, item->OffsetInContainerBlock());
+ }
+ }
+ }
+ }
+
+ // Traverse child fragments.
+ const bool children_inline = IsInlineFormattingContext();
+ // Only add overflow for fragments NG has not reflected into Legacy.
+ // These fragments are:
+ // - inline fragments,
+ // - out of flow fragments whose css container is inline box.
+ // TODO(layout-dev) Transforms also need to be applied to compute overflow
+ // correctly. NG is not yet transform-aware. crbug.com/855965
+ for (const auto& child : Children()) {
+ if (child->IsFloatingOrOutOfFlowPositioned()) {
+ context.AddFloatingOrOutOfFlowPositionedChild(*child, child.Offset());
+ } else if (children_inline && child->IsLineBox()) {
+ context.AddLineBoxChild(To<NGPhysicalLineBoxFragment>(*child),
+ child.Offset());
+ }
+ }
+
+ context.AddPaddingToLineBoxChildren();
+
+ return context.children_overflow;
+}
+
LayoutSize NGPhysicalBoxFragment::PixelSnappedScrolledContentOffset() const {
DCHECK(GetLayoutObject() && GetLayoutObject()->IsBox());
const LayoutBox* box = ToLayoutBox(GetLayoutObject());
@@ -318,9 +488,10 @@ void NGPhysicalBoxFragment::CheckSameForSimplifiedLayout(
DCHECK_EQ(depends_on_percentage_block_size_,
other.depends_on_percentage_block_size_);
- DCHECK_EQ(children_inline_, other.children_inline_);
+ DCHECK_EQ(is_inline_formatting_context_, other.is_inline_formatting_context_);
DCHECK_EQ(is_fieldset_container_, other.is_fieldset_container_);
DCHECK_EQ(is_legacy_layout_root_, other.is_legacy_layout_root_);
+ DCHECK_EQ(is_painted_atomically_, other.is_painted_atomically_);
DCHECK_EQ(border_edge_, other.border_edge_);
// The oof_positioned_descendants_ vector can change during "simplified"
@@ -329,10 +500,63 @@ void NGPhysicalBoxFragment::CheckSameForSimplifiedLayout(
// Legacy layout can (incorrectly) shift baseline position(s) during
// "simplified" layout.
- DCHECK(IsLegacyLayoutRoot() || baselines_ == other.baselines_);
+ DCHECK(IsLegacyLayoutRoot() || Baseline() == other.Baseline());
+ DCHECK(IsLegacyLayoutRoot() || LastBaseline() == other.LastBaseline());
DCHECK(Borders() == other.Borders());
DCHECK(Padding() == other.Padding());
}
+
+// Check our flags represent the actual children correctly.
+void NGPhysicalBoxFragment::CheckIntegrity() const {
+ bool has_inflow_blocks = false;
+ bool has_inlines = false;
+ bool has_line_boxes = false;
+ bool has_floats = false;
+ bool has_list_markers = false;
+
+ for (const NGLink& child : Children()) {
+ if (child->IsFloating())
+ has_floats = true;
+ else if (child->IsOutOfFlowPositioned())
+ ; // OOF can be in the fragment tree regardless of |HasItems|.
+ else if (child->IsLineBox())
+ has_line_boxes = true;
+ else if (child->IsListMarker())
+ has_list_markers = true;
+ else if (child->IsInline())
+ has_inlines = true;
+ else
+ has_inflow_blocks = true;
+ }
+
+ // If we have line boxes, |IsInlineFormattingContext()| is true, but the
+ // reverse is not always true.
+ if (has_line_boxes || has_inlines)
+ DCHECK(IsInlineFormattingContext());
+
+ // If display-locked, we may not have any children.
+ DCHECK(layout_object_);
+ if (layout_object_ && layout_object_->PaintBlockedByDisplayLock(
+ DisplayLockLifecycleTarget::kChildren))
+ return;
+
+ if (RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled()) {
+ if (RuntimeEnabledFeatures::LayoutNGBlockFragmentationEnabled()) {
+ if (has_line_boxes)
+ DCHECK(HasItems());
+ } else {
+ DCHECK_EQ(HasItems(), has_line_boxes);
+ }
+
+ if (has_line_boxes) {
+ DCHECK(!has_inlines);
+ DCHECK(!has_inflow_blocks);
+ // Following objects should be in the items, not in the tree.
+ DCHECK(!has_floats);
+ DCHECK(!has_list_markers);
+ }
+ }
+}
#endif
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
index 5fdc31c023e..21527728c01 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h
@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_items.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h"
#include "third_party/blink/renderer/platform/graphics/scroll_types.h"
@@ -25,6 +24,13 @@ class CORE_EXPORT NGPhysicalBoxFragment final
NGBoxFragmentBuilder* builder,
WritingMode block_or_line_writing_mode);
+ using PassKey = util::PassKey<NGPhysicalBoxFragment>;
+ NGPhysicalBoxFragment(PassKey,
+ NGBoxFragmentBuilder* builder,
+ const NGPhysicalBoxStrut& borders,
+ const NGPhysicalBoxStrut& padding,
+ WritingMode block_or_line_writing_mode);
+
scoped_refptr<const NGLayoutResult> CloneAsHiddenForPaint() const;
~NGPhysicalBoxFragment() {
@@ -40,8 +46,16 @@ class CORE_EXPORT NGPhysicalBoxFragment final
return has_fragment_items_ ? ComputeItemsAddress() : nullptr;
}
- base::Optional<LayoutUnit> Baseline(const NGBaselineRequest& request) const {
- return baselines_.Offset(request);
+ base::Optional<LayoutUnit> Baseline() const {
+ if (has_baseline_)
+ return baseline_;
+ return base::nullopt;
+ }
+
+ base::Optional<LayoutUnit> LastBaseline() const {
+ if (has_last_baseline_)
+ return last_baseline_;
+ return base::nullopt;
}
const NGPhysicalBoxStrut Borders() const {
@@ -63,9 +77,40 @@ class CORE_EXPORT NGPhysicalBoxFragment final
}
bool HasSelfPaintingLayer() const;
- bool ChildrenInline() const { return children_inline_; }
+
+ // Return true if this is either a container that establishes an inline
+ // formatting context, or if it's non-atomic inline content participating in
+ // one. Empty blocks don't establish an inline formatting context.
+ //
+ // The return value from this method is undefined and irrelevant if the object
+ // establishes a different type of formatting context than block/inline, such
+ // as table or flexbox.
+ //
+ // Example:
+ // <div> <!-- false -->
+ // <div> <!-- true -->
+ // <div style="float:left;"></div> <!-- false -->
+ // <div style="float:left;"> <!-- true -->
+ // xxx <!-- true -->
+ // </div>
+ // <div style="float:left;"> <!-- false -->
+ // <div style="float:left;"></div> <!-- false -->
+ // </div>
+ // <span> <!-- true -->
+ // xxx <!-- true -->
+ // <span style="display:inline-block;"> <!-- false -->
+ // <div></div> <!-- false -->
+ // </span>
+ // <span style="display:inline-block;"> <!-- true -->
+ // xxx <!-- true -->
+ // </span>
+ // <span style="display:inline-flex;"> <!-- N/A -->
+ bool IsInlineFormattingContext() const {
+ return is_inline_formatting_context_;
+ }
PhysicalRect ScrollableOverflow() const;
+ PhysicalRect ScrollableOverflowFromChildren() const;
// TODO(layout-dev): These three methods delegate to legacy layout for now,
// update them to use LayoutNG based overflow information from the fragment
@@ -79,6 +124,14 @@ class CORE_EXPORT NGPhysicalBoxFragment final
// Compute visual overflow of this box in the local coordinate.
PhysicalRect ComputeSelfInkOverflow() const;
+ // Contents ink overflow includes anything that would bleed out of the box and
+ // would be clipped by the overflow clip ('overflow' != visible). This
+ // corresponds to children that overflows their parent.
+ PhysicalRect ContentsInkOverflow() const {
+ // TODO(layout-dev): Implement box fragment overflow.
+ return LocalRect();
+ }
+
// Fragment offset is this fragment's offset from parent.
// Needed to compensate for LayoutInline Legacy code offsets.
void AddSelfOutlineRects(const PhysicalOffset& additional_offset,
@@ -91,20 +144,12 @@ class CORE_EXPORT NGPhysicalBoxFragment final
unsigned BorderEdges() const { return border_edge_; }
NGPixelSnappedPhysicalBoxStrut BorderWidths() const;
- // Return true if this is the first fragment generated from a node.
- bool IsFirstForNode() const { return is_first_for_node_; }
-
#if DCHECK_IS_ON()
void CheckSameForSimplifiedLayout(const NGPhysicalBoxFragment&,
bool check_same_block_size) const;
#endif
private:
- NGPhysicalBoxFragment(NGBoxFragmentBuilder* builder,
- const NGPhysicalBoxStrut& borders,
- const NGPhysicalBoxStrut& padding,
- WritingMode block_or_line_writing_mode);
-
const NGFragmentItems* ComputeItemsAddress() const {
DCHECK(has_fragment_items_ || has_borders_ || has_padding_);
const NGLink* children_end = children_ + Children().size();
@@ -125,7 +170,12 @@ class CORE_EXPORT NGPhysicalBoxFragment final
return has_borders_ ? address + 1 : address;
}
- NGBaselineList baselines_;
+#if DCHECK_IS_ON()
+ void CheckIntegrity() const;
+#endif
+
+ LayoutUnit baseline_;
+ LayoutUnit last_baseline_;
NGLink children_[];
// borders and padding come from after |children_| if they are not zero.
};
@@ -133,8 +183,7 @@ class CORE_EXPORT NGPhysicalBoxFragment final
template <>
struct DowncastTraits<NGPhysicalBoxFragment> {
static bool AllowFrom(const NGPhysicalFragment& fragment) {
- return fragment.Type() == NGPhysicalFragment::kFragmentBox ||
- fragment.Type() == NGPhysicalFragment::kFragmentRenderedLegend;
+ return fragment.Type() == NGPhysicalFragment::kFragmentBox;
}
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment_test.cc
index 327d158404a..78373f21bb6 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment_test.cc
@@ -122,7 +122,7 @@ TEST_F(NGPhysicalBoxFragmentTest, DISABLED_NormalLegacyLayoutRoot) {
EXPECT_TRUE(fragment->IsBox());
EXPECT_EQ(NGPhysicalFragment::kNormalBox, fragment->BoxType());
EXPECT_TRUE(fragment->IsLegacyLayoutRoot());
- EXPECT_TRUE(fragment->IsBlockFormattingContextRoot());
+ EXPECT_TRUE(fragment->IsFormattingContextRoot());
}
// TODO(editing-dev): Once LayoutNG supports editing, we should change this
@@ -136,7 +136,7 @@ TEST_F(NGPhysicalBoxFragmentTest, DISABLED_FloatLegacyLayoutRoot) {
EXPECT_TRUE(fragment->IsBox());
EXPECT_EQ(NGPhysicalFragment::kFloating, fragment->BoxType());
EXPECT_TRUE(fragment->IsLegacyLayoutRoot());
- EXPECT_TRUE(fragment->IsBlockFormattingContextRoot());
+ EXPECT_TRUE(fragment->IsFormattingContextRoot());
}
// TODO(editing-dev): Once LayoutNG supports editing, we should change this
@@ -152,7 +152,7 @@ TEST_F(NGPhysicalBoxFragmentTest, DISABLED_InlineBlockLegacyLayoutRoot) {
EXPECT_TRUE(fragment->IsBox());
EXPECT_EQ(NGPhysicalFragment::kAtomicInline, fragment->BoxType());
EXPECT_TRUE(fragment->IsLegacyLayoutRoot());
- EXPECT_TRUE(fragment->IsBlockFormattingContextRoot());
+ EXPECT_TRUE(fragment->IsFormattingContextRoot());
}
// TODO(editing-dev): Once LayoutNG supports editing, we should change this
@@ -170,7 +170,7 @@ TEST_F(NGPhysicalBoxFragmentTest,
EXPECT_TRUE(fragment->IsBox());
EXPECT_EQ(NGPhysicalFragment::kOutOfFlowPositioned, fragment->BoxType());
EXPECT_TRUE(fragment->IsLegacyLayoutRoot());
- EXPECT_TRUE(fragment->IsBlockFormattingContextRoot());
+ EXPECT_TRUE(fragment->IsFormattingContextRoot());
}
TEST_F(NGPhysicalBoxFragmentTest, ReplacedBlock) {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
index 6e7ac12f47b..82f57612ce4 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc
@@ -6,10 +6,12 @@
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_cursor.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
namespace blink {
@@ -88,6 +90,40 @@ void NGPhysicalContainerFragment::AddOutlineRectsForNormalChildren(
const PhysicalOffset& additional_offset,
NGOutlineType outline_type,
const LayoutBoxModelObject* containing_block) const {
+ if (const auto* box = DynamicTo<NGPhysicalBoxFragment>(this)) {
+ if (const NGFragmentItems* items = box->Items()) {
+ for (NGInlineCursor cursor(*items); cursor; cursor.MoveToNext()) {
+ DCHECK(cursor.Current().Item());
+ const NGFragmentItem& item = *cursor.Current().Item();
+ if (item.Type() == NGFragmentItem::kLine) {
+ AddOutlineRectsForDescendant(
+ {item.LineBoxFragment(), item.OffsetInContainerBlock()},
+ outline_rects, additional_offset, outline_type, containing_block);
+ continue;
+ }
+ if (item.Type() == NGFragmentItem::kBox) {
+ if (const NGPhysicalBoxFragment* child_box = item.BoxFragment()) {
+ DCHECK(!child_box->IsOutOfFlowPositioned());
+ AddOutlineRectsForDescendant(
+ {child_box, item.OffsetInContainerBlock()}, outline_rects,
+ additional_offset, outline_type, containing_block);
+ }
+ continue;
+ }
+ DCHECK(item.IsText());
+ }
+ // Don't add |Children()|. If |this| has |NGFragmentItems|, children are
+ // either line box, which we already handled in items, or OOF, which we
+ // should ignore.
+ DCHECK(std::all_of(PostLayoutChildren().begin(),
+ PostLayoutChildren().end(), [](const NGLink& child) {
+ return child->IsLineBox() ||
+ child->IsOutOfFlowPositioned();
+ }));
+ return;
+ }
+ }
+
for (const auto& child : PostLayoutChildren()) {
// Outlines of out-of-flow positioned descendants are handled in
// NGPhysicalBoxFragment::AddSelfOutlineRects().
@@ -111,6 +147,84 @@ void NGPhysicalContainerFragment::AddOutlineRectsForNormalChildren(
}
}
+void NGPhysicalContainerFragment::AddScrollableOverflowForInlineChild(
+ const NGPhysicalBoxFragment& container,
+ const ComputedStyle& container_style,
+ const NGFragmentItem& line,
+ bool has_hanging,
+ const NGInlineCursor& cursor,
+ PhysicalRect* overflow) const {
+ DCHECK(RuntimeEnabledFeatures::LayoutNGFragmentItemEnabled());
+ DCHECK(IsLineBox() || IsInlineBox());
+ DCHECK(cursor.Current().Item() &&
+ (cursor.Current().Item()->BoxFragment() == this ||
+ cursor.Current().Item()->LineBoxFragment() == this));
+ const WritingMode container_writing_mode = container_style.GetWritingMode();
+ const TextDirection container_direction = container_style.Direction();
+ for (NGInlineCursor descendants = cursor.CursorForDescendants();
+ descendants;) {
+ const NGFragmentItem* item = descendants.CurrentItem();
+ DCHECK(item);
+ if (item->IsText()) {
+ PhysicalRect child_scroll_overflow = item->RectInContainerBlock();
+ if (UNLIKELY(has_hanging)) {
+ AdjustScrollableOverflowForHanging(line.RectInContainerBlock(),
+ container_writing_mode,
+ &child_scroll_overflow);
+ }
+ overflow->Unite(child_scroll_overflow);
+ descendants.MoveToNextSkippingChildren();
+ continue;
+ }
+
+ if (const NGPhysicalBoxFragment* child_box = item->BoxFragment()) {
+ PhysicalRect child_scroll_overflow = item->RectInContainerBlock();
+ if (child_box->IsInlineBox()) {
+ child_box->AddScrollableOverflowForInlineChild(
+ container, container_style, line, has_hanging, descendants,
+ &child_scroll_overflow);
+ child_box->AdjustScrollableOverflowForPropagation(
+ container, &child_scroll_overflow);
+ } else {
+ child_scroll_overflow =
+ child_box->ScrollableOverflowForPropagation(container);
+ child_scroll_overflow.offset += item->OffsetInContainerBlock();
+ }
+ child_scroll_overflow.offset +=
+ ComputeRelativeOffset(child_box->Style(), container_writing_mode,
+ container_direction, container.Size());
+ overflow->Unite(child_scroll_overflow);
+ descendants.MoveToNextSkippingChildren();
+ continue;
+ }
+
+ // Add all children of a culled inline box; i.e., an inline box without
+ // margin/border/padding etc.
+ DCHECK_EQ(item->Type(), NGFragmentItem::kBox);
+ descendants.MoveToNext();
+ }
+}
+
+// Chop the hanging part from scrollable overflow. Children overflow in inline
+// direction should hang, which should not cause scroll.
+// TODO(kojii): Should move to text fragment to make this more accurate.
+void NGPhysicalContainerFragment::AdjustScrollableOverflowForHanging(
+ const PhysicalRect& rect,
+ const WritingMode container_writing_mode,
+ PhysicalRect* overflow) {
+ if (IsHorizontalWritingMode(container_writing_mode)) {
+ if (overflow->offset.left < rect.offset.left)
+ overflow->offset.left = rect.offset.left;
+ if (overflow->Right() > rect.Right())
+ overflow->ShiftRightEdgeTo(rect.Right());
+ } else {
+ if (overflow->offset.top < rect.offset.top)
+ overflow->offset.top = rect.offset.top;
+ if (overflow->Bottom() > rect.Bottom())
+ overflow->ShiftBottomEdgeTo(rect.Bottom());
+ }
+}
+
// additional_offset must be offset from the containing_block because
// LocalToAncestorRect returns rects wrt containing_block.
void NGPhysicalContainerFragment::AddOutlineRectsForDescendant(
@@ -212,16 +326,23 @@ bool NGPhysicalContainerFragment::DependsOnPercentageBlockSize(
// element if it has a percentage block-size however, but this will return
// the correct result from below.
+ // There are two conditions where we need to know about an (arbitrary)
+ // descendant which depends on a %-block-size.
+ // - In quirks mode, the arbitrary descendant may depend the percentage
+ // resolution block-size given (to this node), and need to relayout if
+ // this size changes.
+ // - A flex-item may have its "definiteness" change, (e.g. if itself is a
+ // flex item which is being stretched). This definiteness change will
+ // affect any %-block-size children.
+ //
+ // NOTE(ikilpatrick): For the flex-item case this is potentially too general.
+ // We only need to know about if this flex-item has a %-block-size child if
+ // the "definiteness" changes, not if the percentage resolution size changes.
if ((builder.has_descendant_that_depends_on_percentage_block_size_ ||
builder.is_legacy_layout_root_) &&
- node.UseParentPercentageResolutionBlockSizeForChildren()) {
- // Quirks mode has different %-block-size behaviour, than standards mode.
- // An arbitrary descendant may depend on the percentage resolution
- // block-size given.
- // If this is also an anonymous block we need to mark ourselves dependent
- // if we have a dependent child.
+ (node.UseParentPercentageResolutionBlockSizeForChildren() ||
+ node.IsFlexItem()))
return true;
- }
const ComputedStyle& style = builder.Style();
if (style.LogicalHeight().IsPercentOrCalc() ||
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
index 4cf2b93116b..b3c7624f494 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h
@@ -17,6 +17,7 @@
namespace blink {
class NGContainerFragmentBuilder;
+class NGFragmentItem;
struct NGPhysicalOutOfFlowPositionedNode;
enum class NGOutlineType;
@@ -149,6 +150,19 @@ class CORE_EXPORT NGPhysicalContainerFragment : public NGPhysicalFragment {
NGFragmentType,
unsigned sub_type);
+ void AddScrollableOverflowForInlineChild(
+ const NGPhysicalBoxFragment& container,
+ const ComputedStyle& container_style,
+ const NGFragmentItem& line,
+ bool has_hanging,
+ const NGInlineCursor& cursor,
+ PhysicalRect* overflow) const;
+
+ static void AdjustScrollableOverflowForHanging(
+ const PhysicalRect& rect,
+ const WritingMode container_writing_mode,
+ PhysicalRect* overflow);
+
void AddOutlineRectsForNormalChildren(
Vector<PhysicalRect>* outline_rects,
const PhysicalOffset& additional_offset,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
index 02c51c05535..d5f70584bc9 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc
@@ -80,6 +80,9 @@ String StringForBoxType(const NGPhysicalFragment& fragment) {
case NGPhysicalFragment::NGBoxType::kBlockFlowRoot:
result.Append("block-flow-root");
break;
+ case NGPhysicalFragment::NGBoxType::kRenderedLegend:
+ result.Append("rendered-legend");
+ break;
}
if (fragment.IsLegacyLayoutRoot()) {
if (result.length())
@@ -91,18 +94,13 @@ String StringForBoxType(const NGPhysicalFragment& fragment) {
result.Append(" ");
result.Append("block-flow");
}
- if (fragment.IsRenderedLegend()) {
- if (result.length())
- result.Append(" ");
- result.Append("rendered-legend");
- }
if (fragment.IsFieldsetContainer()) {
if (result.length())
result.Append(" ");
result.Append("fieldset-container");
}
if (fragment.IsBox() &&
- static_cast<const NGPhysicalBoxFragment&>(fragment).ChildrenInline()) {
+ To<NGPhysicalBoxFragment>(fragment).IsInlineFormattingContext()) {
if (result.length())
result.Append(" ");
result.Append("children-inline");
@@ -124,10 +122,7 @@ void AppendFragmentToString(const NGPhysicalFragment* fragment,
bool has_content = false;
if (const auto* box = DynamicTo<NGPhysicalBoxFragment>(fragment)) {
if (flags & NGPhysicalFragment::DumpType) {
- if (fragment->IsRenderedLegend())
- builder->Append("RenderedLegend");
- else
- builder->Append("Box");
+ builder->Append("Box");
String box_type = StringForBoxType(*fragment);
has_content = true;
if (!box_type.IsEmpty()) {
@@ -224,9 +219,12 @@ NGPhysicalFragment::NGPhysicalFragment(NGFragmentBuilder* builder,
sub_type_(sub_type),
style_variant_((unsigned)builder->style_variant_),
is_hidden_for_paint_(builder->is_hidden_for_paint_),
+ is_first_for_node_(true),
has_floating_descendants_for_paint_(false),
is_fieldset_container_(false),
- is_legacy_layout_root_(false) {
+ is_legacy_layout_root_(false),
+ is_painted_atomically_(false),
+ has_baseline_(false) {
DCHECK(builder->layout_object_);
}
@@ -243,7 +241,9 @@ NGPhysicalFragment::NGPhysicalFragment(LayoutObject* layout_object,
is_hidden_for_paint_(false),
has_floating_descendants_for_paint_(false),
is_fieldset_container_(false),
- is_legacy_layout_root_(false) {
+ is_legacy_layout_root_(false),
+ is_painted_atomically_(false),
+ has_baseline_(false) {
DCHECK(layout_object);
}
@@ -254,7 +254,6 @@ NGPhysicalFragment::~NGPhysicalFragment() = default;
void NGPhysicalFragment::Destroy() const {
switch (Type()) {
case kFragmentBox:
- case kFragmentRenderedLegend:
delete static_cast<const NGPhysicalBoxFragment*>(this);
break;
case kFragmentText:
@@ -305,6 +304,19 @@ bool NGPhysicalFragment::IsPlacedByLayoutNG() const {
return container->IsLayoutNGMixin();
}
+const FragmentData* NGPhysicalFragment::GetFragmentData() const {
+ DCHECK(CanTraverse());
+ const LayoutObject* layout_object = GetLayoutObject();
+ if (!layout_object)
+ return nullptr;
+ // TODO(mstensho): Actually return the correct FragmentData. For now this
+ // method only behaves if there's just one FragmentData associated with the
+ // LayoutObject.
+ const FragmentData& first_fragment_data = layout_object->FirstFragment();
+ DCHECK(!first_fragment_data.NextFragment());
+ return &first_fragment_data;
+}
+
const NGPhysicalFragment* NGPhysicalFragment::PostLayout() const {
if (IsBox() && !IsInlineBox()) {
if (const auto* block = DynamicTo<LayoutBlockFlow>(GetLayoutObject())) {
@@ -322,7 +334,6 @@ const NGPhysicalFragment* NGPhysicalFragment::PostLayout() const {
void NGPhysicalFragment::CheckType() const {
switch (Type()) {
case kFragmentBox:
- case kFragmentRenderedLegend:
if (IsInlineBox()) {
DCHECK(layout_object_->IsLayoutInline());
} else {
@@ -337,10 +348,10 @@ void NGPhysicalFragment::CheckType() const {
DCHECK(!IsFloating());
DCHECK(!IsOutOfFlowPositioned());
DCHECK(!IsAtomicInline());
- DCHECK(!IsBlockFormattingContextRoot());
+ DCHECK(!IsFormattingContextRoot());
break;
}
- if (layout_object_->IsLayoutNGListMarker()) {
+ if (layout_object_->IsLayoutNGOutsideListMarker()) {
// List marker is an atomic inline if it appears in a line box, or a
// block box.
DCHECK(!IsFloating());
@@ -392,7 +403,6 @@ void NGPhysicalFragment::CheckCanUpdateInkOverflow() const {
PhysicalRect NGPhysicalFragment::ScrollableOverflow() const {
switch (Type()) {
case kFragmentBox:
- case kFragmentRenderedLegend:
return To<NGPhysicalBoxFragment>(*this).ScrollableOverflow();
case kFragmentText:
return {{}, Size()};
@@ -406,18 +416,30 @@ PhysicalRect NGPhysicalFragment::ScrollableOverflow() const {
}
PhysicalRect NGPhysicalFragment::ScrollableOverflowForPropagation(
- const LayoutObject* container) const {
- DCHECK(container);
+ const NGPhysicalBoxFragment& container) const {
PhysicalRect overflow = ScrollableOverflow();
- if (GetLayoutObject() &&
- GetLayoutObject()->ShouldUseTransformFromContainer(container)) {
+ AdjustScrollableOverflowForPropagation(container, &overflow);
+ return overflow;
+}
+
+void NGPhysicalFragment::AdjustScrollableOverflowForPropagation(
+ const NGPhysicalBoxFragment& container,
+ PhysicalRect* overflow) const {
+ DCHECK(!IsLineBox());
+ if (!IsCSSBox())
+ return;
+
+ const LayoutObject* layout_object = GetLayoutObject();
+ DCHECK(layout_object);
+ const LayoutObject* container_layout_object = container.GetLayoutObject();
+ DCHECK(container_layout_object);
+ if (layout_object->ShouldUseTransformFromContainer(container_layout_object)) {
TransformationMatrix transform;
- GetLayoutObject()->GetTransformFromContainer(container, PhysicalOffset(),
- transform);
- overflow =
- PhysicalRect::EnclosingRect(transform.MapRect(FloatRect(overflow)));
+ layout_object->GetTransformFromContainer(container_layout_object,
+ PhysicalOffset(), transform);
+ *overflow =
+ PhysicalRect::EnclosingRect(transform.MapRect(FloatRect(*overflow)));
}
- return overflow;
}
const Vector<NGInlineItem>& NGPhysicalFragment::InlineItemsOfContainingBlock()
@@ -430,6 +452,7 @@ const Vector<NGInlineItem>& NGPhysicalFragment::InlineItemsOfContainingBlock()
// modification. Unify them.
DCHECK(block_flow);
NGBlockNode block_node = NGBlockNode(block_flow);
+ DCHECK(block_node.IsInlineFormattingContextRoot());
DCHECK(block_node.CanUseNewLayout());
NGLayoutInputNode node = block_node.FirstChild();
@@ -447,7 +470,6 @@ UBiDiLevel NGPhysicalFragment::BidiLevel() const {
case kFragmentText:
return To<NGPhysicalTextFragment>(*this).BidiLevel();
case kFragmentBox:
- case kFragmentRenderedLegend:
return To<NGPhysicalBoxFragment>(*this).BidiLevel();
case kFragmentLineBox:
break;
@@ -461,7 +483,6 @@ TextDirection NGPhysicalFragment::ResolvedDirection() const {
case kFragmentText:
return To<NGPhysicalTextFragment>(*this).ResolvedDirection();
case kFragmentBox:
- case kFragmentRenderedLegend:
DCHECK(IsInline() && IsAtomicInline());
// TODO(xiaochengh): Store direction in |base_direction_| flag.
return DirectionFromLevel(BidiLevel());
@@ -494,7 +515,6 @@ String NGPhysicalFragment::ToString() const {
Size().ToString().Ascii().c_str());
switch (Type()) {
case kFragmentBox:
- case kFragmentRenderedLegend:
output.AppendFormat(", BoxType: '%s'",
StringForBoxType(*this).Ascii().c_str());
break;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
index e3b64e26d96..2fcd7049c96 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h
@@ -11,7 +11,7 @@
#include "third_party/blink/renderer/core/layout/geometry/physical_offset.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_rect.h"
#include "third_party/blink/renderer/core/layout/geometry/physical_size.h"
-#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
#include "third_party/blink/renderer/platform/graphics/touch_action.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
@@ -21,6 +21,7 @@
namespace blink {
class ComputedStyle;
+class FragmentData;
class Node;
class NGFragmentBuilder;
class NGInlineItem;
@@ -50,7 +51,6 @@ class CORE_EXPORT NGPhysicalFragment
kFragmentBox = 0,
kFragmentText = 1,
kFragmentLineBox = 2,
- kFragmentRenderedLegend = 3,
// When adding new values, make sure the bit size of |type_| is large
// enough to store.
};
@@ -64,13 +64,14 @@ class CORE_EXPORT NGPhysicalFragment
kFloating,
kOutOfFlowPositioned,
kBlockFlowRoot,
+ kRenderedLegend,
// When adding new values, make sure the bit size of |sub_type_| is large
// enough to store.
- // Also, add after kMinimumBlockFormattingContextRoot if the box type is a
- // block formatting context root, or before otherwise. See
- // IsBlockFormattingContextRoot().
- kMinimumBlockFormattingContextRoot = kAtomicInline
+ // Also, add after kMinimumFormattingContextRoot if the box type is a
+ // formatting context root, or before otherwise. See
+ // IsFormattingContextRoot().
+ kMinimumFormattingContextRoot = kAtomicInline
};
~NGPhysicalFragment();
@@ -78,19 +79,12 @@ class CORE_EXPORT NGPhysicalFragment
NGFragmentType Type() const { return static_cast<NGFragmentType>(type_); }
bool IsContainer() const {
return Type() == NGFragmentType::kFragmentBox ||
- Type() == NGFragmentType::kFragmentLineBox ||
- Type() == NGFragmentType::kFragmentRenderedLegend;
+ Type() == NGFragmentType::kFragmentLineBox;
}
bool IsBox() const { return Type() == NGFragmentType::kFragmentBox; }
bool IsText() const { return Type() == NGFragmentType::kFragmentText; }
bool IsLineBox() const { return Type() == NGFragmentType::kFragmentLineBox; }
- // Return true if this is the legend child of a fieldset that gets special
- // treatment (i.e. placed over the block-start border).
- bool IsRenderedLegend() const {
- return Type() == NGFragmentType::kFragmentRenderedLegend;
- }
-
// Returns the box type of this fragment.
NGBoxType BoxType() const {
DCHECK(IsBox());
@@ -122,6 +116,14 @@ class CORE_EXPORT NGPhysicalFragment
bool IsFloatingOrOutOfFlowPositioned() const {
return IsFloating() || IsOutOfFlowPositioned();
}
+ // Return true if this is the legend child of a fieldset that gets special
+ // treatment (i.e. placed over the block-start border).
+ bool IsRenderedLegend() const {
+ return IsBox() && BoxType() == NGBoxType::kRenderedLegend;
+ }
+ bool IsMathMLFraction() const {
+ return IsBox() && is_generated_text_or_math_fraction_;
+ }
// Return true if this fragment corresponds directly to an entry in the CSS
// box tree [1]. Note that anonymous blocks also exist in the CSS box
@@ -140,7 +142,7 @@ class CORE_EXPORT NGPhysicalFragment
return IsCSSBox() && layout_object_->IsAnonymousBlock();
}
bool IsListMarker() const {
- return IsCSSBox() && layout_object_->IsLayoutNGListMarker();
+ return IsCSSBox() && layout_object_->IsLayoutNGOutsideListMarker();
}
// Return true if this fragment is a container established by a fieldset
@@ -152,9 +154,11 @@ class CORE_EXPORT NGPhysicalFragment
// Returns whether the fragment is legacy layout root.
bool IsLegacyLayoutRoot() const { return is_legacy_layout_root_; }
- bool IsBlockFormattingContextRoot() const {
- return (IsBox() &&
- BoxType() >= NGBoxType::kMinimumBlockFormattingContextRoot) ||
+ // Returns whether the fragment should be atomically painted.
+ bool IsPaintedAtomically() const { return is_painted_atomically_; }
+
+ bool IsFormattingContextRoot() const {
+ return (IsBox() && BoxType() >= NGBoxType::kMinimumFormattingContextRoot) ||
IsLegacyLayoutRoot();
}
@@ -164,6 +168,9 @@ class CORE_EXPORT NGPhysicalFragment
// |LayoutNGBlockFlow::UpdateBlockLayout()| and crbug.com/788590
bool IsPlacedByLayoutNG() const;
+ // Return true if this is the first fragment generated from a node.
+ bool IsFirstForNode() const { return is_first_for_node_; }
+
// The accessors in this class shouldn't be used by layout code directly,
// instead should be accessed by the NGFragmentBase classes. These accessors
// exist for paint, hit-testing, etc.
@@ -206,6 +213,17 @@ class CORE_EXPORT NGPhysicalFragment
// from GetNode() when this fragment is content of a pseudo node.
Node* NodeForHitTest() const { return layout_object_->NodeForHitTest(); }
+ bool IsInSelfHitTestingPhase(HitTestAction action) const {
+ if (const auto* box = ToLayoutBoxOrNull(GetLayoutObject()))
+ return box->IsInSelfHitTestingPhase(action);
+ if (IsInlineBox())
+ return action == kHitTestForeground;
+ // Assuming this is some sort of container, e.g. a fragmentainer (they don't
+ // have a LayoutObject associated).
+ return action == kHitTestBlockBackground ||
+ action == kHitTestChildBlockBackground;
+ }
+
// Whether there is a PaintLayer associated with the fragment.
bool HasLayer() const { return IsCSSBox() && layout_object_->HasLayer(); }
@@ -225,10 +243,31 @@ class CORE_EXPORT NGPhysicalFragment
return IsCSSBox() && layout_object_->ShouldClipOverflow();
}
+ bool IsFragmentationContextRoot() const {
+ return !IsColumnBox() && IsBlockFlow() && Style().SpecifiesColumns();
+ }
+
+ // Return whether we can traverse this fragment and its children directly, for
+ // painting, hit-testing and other layout read operations. If false is
+ // returned, we need to traverse the layout object tree instead.
+ bool CanTraverse() const {
+ return layout_object_->CanTraversePhysicalFragments();
+ }
+
// This fragment is hidden for paint purpose, but exists for querying layout
// information. Used for `text-overflow: ellipsis`.
bool IsHiddenForPaint() const { return is_hidden_for_paint_; }
+ // Return true if this fragment is monolithic, as far as block fragmentation
+ // is concerned.
+ bool IsMonolithic() const {
+ const LayoutObject* layout_object = GetLayoutObject();
+ if (!layout_object || !IsBox() || !layout_object->IsBox())
+ return false;
+ return ToLayoutBox(layout_object)->GetPaginationBreakability() ==
+ LayoutBox::kForbidBreaks;
+ }
+
// GetLayoutObject should only be used when necessary for compatibility
// with LegacyLayout.
//
@@ -244,6 +283,8 @@ class CORE_EXPORT NGPhysicalFragment
return IsCSSBox() ? layout_object_ : nullptr;
}
+ const FragmentData* GetFragmentData() const;
+
// |NGPhysicalFragment| may live longer than the corresponding |LayoutObject|.
// Though |NGPhysicalFragment| is immutable, |layout_object_| is cleared to
// |nullptr| when it was destroyed to avoid reading destroyed objects.
@@ -260,13 +301,21 @@ class CORE_EXPORT NGPhysicalFragment
// check if there were newer generations.
const NGPhysicalFragment* PostLayout() const;
+ PhysicalRect InkOverflow() const {
+ // TODO(layout-dev): Implement box fragment overflow.
+ return LocalRect();
+ }
+
// Scrollable overflow. including contents, in the local coordinate.
PhysicalRect ScrollableOverflow() const;
// ScrollableOverflow(), with transforms applied wrt container if needed.
// This does not include any offsets from the parent (including relpos).
PhysicalRect ScrollableOverflowForPropagation(
- const LayoutObject* container) const;
+ const NGPhysicalBoxFragment& container) const;
+ void AdjustScrollableOverflowForPropagation(
+ const NGPhysicalBoxFragment& container,
+ PhysicalRect* overflow) const;
// The allowed touch action is the union of the effective touch action
// (from style) and blocking touch event handlers.
@@ -336,6 +385,7 @@ class CORE_EXPORT NGPhysicalFragment
const unsigned sub_type_ : 3; // NGBoxType, NGTextType, or NGLineBoxType
const unsigned style_variant_ : 2; // NGStyleVariant
const unsigned is_hidden_for_paint_ : 1;
+ unsigned is_first_for_node_ : 1;
// The following bitfields are only to be used by NGPhysicalContainerFragment
// (it's defined here to save memory, since that class has no bitfields).
@@ -348,28 +398,37 @@ class CORE_EXPORT NGPhysicalFragment
// The following bitfields are only to be used by NGPhysicalLineBoxFragment
// (it's defined here to save memory, since that class has no bitfields).
unsigned has_propagated_descendants_ : 1;
- unsigned base_direction_ : 1; // TextDirection
+ // base (line box) or resolve (text) direction
+ unsigned base_or_resolved_direction_ : 1; // TextDirection
unsigned has_hanging_ : 1;
// The following bitfields are only to be used by NGPhysicalBoxFragment
// (it's defined here to save memory, since that class has no bitfields).
- unsigned children_inline_ : 1;
+ unsigned is_inline_formatting_context_ : 1;
unsigned has_fragment_items_ : 1;
unsigned border_edge_ : 4; // NGBorderEdges::Physical
unsigned has_borders_ : 1;
unsigned has_padding_ : 1;
- unsigned is_first_for_node_ : 1;
// The following are only used by NGPhysicalBoxFragment but are initialized
// for all types to allow methods using them to be inlined.
unsigned is_fieldset_container_ : 1;
unsigned is_legacy_layout_root_ : 1;
+ unsigned is_painted_atomically_ : 1;
+ unsigned has_baseline_ : 1;
+ unsigned has_last_baseline_ : 1;
+
+ // The following bitfield is shared between NGPhysicalTextFragment and
+ // NGPhysicalBoxFragment.
+ unsigned is_generated_text_or_math_fraction_ : 1;
// The following bitfields are only to be used by NGPhysicalTextFragment
// (it's defined here to save memory, since that class has no bitfields).
- unsigned is_generated_text_ : 1;
mutable unsigned ink_overflow_computed_ : 1;
+ // Note: We've used 32-bit bit field. If you need more bits, please think to
+ // share bit fields.
+
private:
friend struct NGPhysicalFragmentTraits;
void Destroy() const;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
index 448c3e00d89..a2bec293a78 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_simplified_layout_algorithm.cc
@@ -36,9 +36,11 @@ NGSimplifiedLayoutAlgorithm::NGSimplifiedLayoutAlgorithm(
const NGPhysicalBoxFragment& physical_fragment =
To<NGPhysicalBoxFragment>(result.PhysicalFragment());
+ container_builder_.SetIsInlineFormattingContext(
+ Node().IsInlineFormattingContextRoot());
container_builder_.SetStyleVariant(physical_fragment.StyleVariant());
container_builder_.SetIsNewFormattingContext(
- physical_fragment.IsBlockFormattingContextRoot());
+ physical_fragment.IsFormattingContextRoot());
container_builder_.SetInitialFragmentGeometry(params.fragment_geometry);
NGExclusionSpace exclusion_space = result.ExclusionSpace();
@@ -65,11 +67,10 @@ NGSimplifiedLayoutAlgorithm::NGSimplifiedLayoutAlgorithm(
container_builder_.SetIsPushedByFloats();
container_builder_.SetAdjoiningObjectTypes(result.AdjoiningObjectTypes());
- for (const auto& request : ConstraintSpace().BaselineRequests()) {
- base::Optional<LayoutUnit> baseline = physical_fragment.Baseline(request);
- if (baseline)
- container_builder_.AddBaseline(request, *baseline);
- }
+ if (physical_fragment.Baseline())
+ container_builder_.SetBaseline(*physical_fragment.Baseline());
+ if (physical_fragment.LastBaseline())
+ container_builder_.SetLastBaseline(*physical_fragment.LastBaseline());
container_builder_.SetBlockSize(ComputeBlockSizeForFragment(
ConstraintSpace(), Style(),
@@ -171,7 +172,7 @@ scoped_refptr<const NGLayoutResult> NGSimplifiedLayoutAlgorithm::Layout() {
// Only take exclusion spaces from children which don't establish their own
// formatting context.
- if (!fragment.IsBlockFormattingContextRoot())
+ if (!fragment.IsFormattingContextRoot())
exclusion_space_ = result->ExclusionSpace();
++it;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc
index 3ae73180868..11eec2a89c9 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc
@@ -38,6 +38,7 @@ NGConstraintSpace CreateIndefiniteConstraintSpaceForChild(
builder.SetAvailableSize(indefinite_size);
builder.SetPercentageResolutionSize(indefinite_size);
builder.SetReplacedPercentageResolutionSize(indefinite_size);
+ builder.SetIsShrinkToFit(child.Style().LogicalWidth().IsAuto());
return builder.ToConstraintSpace();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.cc
index 13a027e0b88..b67b5756cc9 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.cc
@@ -4,7 +4,6 @@
#include "third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_fragment_item.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
@@ -19,15 +18,8 @@ int NGTextDecorationOffset::ComputeUnderlineOffsetForUnder(
const ComputedStyle& style = text_style_;
FontBaseline baseline_type = style.GetFontBaseline();
- if (decorating_box_) {
- NGBaselineRequest baseline_request = {
- NGBaselineAlgorithmType::kAtomicInline,
- FontBaseline::kIdeographicBaseline};
-
- if (base::Optional<LayoutUnit> baseline =
- decorating_box_->Baseline(baseline_request))
- offset = *baseline;
- }
+ if (decorating_box_)
+ offset = decorating_box_->Baseline().value_or(offset);
if (offset == LayoutUnit::Max()) {
// TODO(layout-dev): How do we compute the baseline offset with a
diff --git a/chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc b/chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc
index 0d86a6fc07c..d796a7f10bb 100644
--- a/chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc
+++ b/chromium/third_party/blink/renderer/core/layout/scroll_anchor.cc
@@ -463,7 +463,8 @@ void ScrollAnchor::Adjust() {
}
scroller_->SetScrollOffset(
- scroller_->GetScrollOffset() + FloatSize(adjustment), kAnchoringScroll);
+ scroller_->GetScrollOffset() + FloatSize(adjustment),
+ mojom::blink::ScrollType::kAnchoring);
// Update UMA metric.
DEFINE_STATIC_LOCAL(EnumerationHistogram, adjusted_offset_histogram,
@@ -538,13 +539,15 @@ bool ScrollAnchor::RestoreAnchor(const SerializedAnchor& serialized_anchor) {
ScrollOffset delta =
ScrollOffset(RoundedIntSize(serialized_anchor.relative_offset));
desired_offset -= delta;
- scroller_->SetScrollOffset(desired_offset, kAnchoringScroll);
+ scroller_->SetScrollOffset(desired_offset,
+ mojom::blink::ScrollType::kAnchoring);
FindAnchor();
// If the above FindAnchor call failed, reset the scroll position and try
// again with the next found element.
if (!anchor_object_) {
- scroller_->SetScrollOffset(current_offset, kAnchoringScroll);
+ scroller_->SetScrollOffset(current_offset,
+ mojom::blink::ScrollType::kAnchoring);
continue;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/scroll_anchor.h b/chromium/third_party/blink/renderer/core/layout/scroll_anchor.h
index 56ebdf6a503..c637c9c9e20 100644
--- a/chromium/third_party/blink/renderer/core/layout/scroll_anchor.h
+++ b/chromium/third_party/blink/renderer/core/layout/scroll_anchor.h
@@ -108,7 +108,7 @@ class CORE_EXPORT ScrollAnchor final {
// Notifies us that an object will be removed from the layout tree.
void NotifyRemoved(LayoutObject*);
- void Trace(blink::Visitor* visitor) { visitor->Trace(scroller_); }
+ void Trace(Visitor* visitor) { visitor->Trace(scroller_); }
private:
void FindAnchor();
diff --git a/chromium/third_party/blink/renderer/core/layout/scroll_anchor_test.cc b/chromium/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
index ae0ac5b2816..e14100e6593 100644
--- a/chromium/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/scroll_anchor_test.cc
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/layout/scroll_anchor.h"
#include "build/build_config.h"
+#include "third_party/blink/public/common/input/web_mouse_event.h"
#include "third_party/blink/renderer/core/dom/static_node_list.h"
#include "third_party/blink/renderer/core/frame/root_frame_viewport.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
@@ -28,6 +29,11 @@ class ScrollAnchorTest : public testing::WithParamInterface<bool>,
ScrollAnchorTest() : ScopedLayoutNGForTest(GetParam()) {}
protected:
+ void SetUp() override {
+ EnableCompositing();
+ RenderingTest::SetUp();
+ }
+
void Update() {
// TODO(skobes): Use SimTest instead of RenderingTest and move into
// Source/web?
@@ -79,6 +85,52 @@ class ScrollAnchorTest : public testing::WithParamInterface<bool>,
GetDocument().QuerySelectorAll(AtomicString(serialized.selector));
EXPECT_EQ(ele_list->length(), 1u);
}
+
+ Scrollbar* VerticalScrollbarForElement(Element* element) {
+ return ToLayoutBox(element->GetLayoutObject())
+ ->GetScrollableArea()
+ ->VerticalScrollbar();
+ }
+
+ void MouseDownOnVerticalScrollbar(Scrollbar* scrollbar) {
+ DCHECK_EQ(true, scrollbar->GetTheme().AllowsHitTest());
+ int thumb_center = scrollbar->GetTheme().ThumbPosition(*scrollbar) +
+ scrollbar->GetTheme().ThumbLength(*scrollbar) / 2;
+ scrollbar_drag_point_ =
+ gfx::PointF(scrollbar->GetScrollableArea()
+ ->ConvertFromScrollbarToContainingEmbeddedContentView(
+ *scrollbar, IntPoint(0, thumb_center)));
+ scrollbar->MouseDown(blink::WebMouseEvent(
+ blink::WebInputEvent::kMouseDown, *scrollbar_drag_point_,
+ *scrollbar_drag_point_, blink::WebPointerProperties::Button::kLeft, 0,
+ blink::WebInputEvent::kNoModifiers, base::TimeTicks::Now()));
+ }
+
+ void MouseDragVerticalScrollbar(Scrollbar* scrollbar, float scroll_delta_y) {
+ DCHECK(scrollbar_drag_point_);
+ ScrollableArea* scroller = scrollbar->GetScrollableArea();
+ scrollbar_drag_point_->Offset(
+ 0, scroll_delta_y *
+ (scrollbar->GetTheme().TrackLength(*scrollbar) -
+ scrollbar->GetTheme().ThumbLength(*scrollbar)) /
+ (scroller->MaximumScrollOffset().Height() -
+ scroller->MinimumScrollOffset().Height()));
+ scrollbar->MouseMoved(blink::WebMouseEvent(
+ blink::WebInputEvent::kMouseMove, *scrollbar_drag_point_,
+ *scrollbar_drag_point_, blink::WebPointerProperties::Button::kLeft, 0,
+ blink::WebInputEvent::kNoModifiers, base::TimeTicks::Now()));
+ }
+
+ void MouseUpOnVerticalScrollbar(Scrollbar* scrollbar) {
+ DCHECK(scrollbar_drag_point_);
+ scrollbar->MouseDown(blink::WebMouseEvent(
+ blink::WebInputEvent::kMouseUp, *scrollbar_drag_point_,
+ *scrollbar_drag_point_, blink::WebPointerProperties::Button::kLeft, 0,
+ blink::WebInputEvent::kNoModifiers, base::TimeTicks::Now()));
+ scrollbar_drag_point_.reset();
+ }
+
+ base::Optional<gfx::PointF> scrollbar_drag_point_;
};
INSTANTIATE_TEST_SUITE_P(All, ScrollAnchorTest, testing::Bool());
@@ -213,7 +265,7 @@ TEST_P(ScrollAnchorTest, ClearScrollAnchorsOnAncestors) {
// Scrolling the nested scroller should clear the anchor on the main frame.
ScrollableArea* scroller =
ScrollerForElement(GetDocument().getElementById("scroller"));
- scroller->ScrollBy(ScrollOffset(0, 100), kUserScroll);
+ scroller->ScrollBy(ScrollOffset(0, 100), mojom::blink::ScrollType::kUser);
EXPECT_EQ(nullptr, GetScrollAnchor(viewport).AnchorObject());
}
@@ -313,7 +365,7 @@ TEST_P(ScrollAnchorTest, AnchorWithLayerInScrollingDiv) {
Element* block1 = GetDocument().getElementById("block1");
Element* block2 = GetDocument().getElementById("block2");
- scroller->ScrollBy(ScrollOffset(0, 150), kUserScroll);
+ scroller->ScrollBy(ScrollOffset(0, 150), mojom::blink::ScrollType::kUser);
// In this layout pass we will anchor to #block2 which has its own PaintLayer.
SetHeight(block1, 200);
@@ -328,6 +380,51 @@ TEST_P(ScrollAnchorTest, AnchorWithLayerInScrollingDiv) {
EXPECT_EQ(250, scroller->ScrollOffsetInt().Height());
}
+TEST_P(ScrollAnchorTest, AnchorWhileDraggingScrollbar) {
+ // Dragging the scrollbar is inherently inaccurate. Allow many pixels slop in
+ // the scroll position.
+ const int kScrollbarDragAccuracy = 10;
+ USE_NON_OVERLAY_SCROLLBARS();
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #scroller { overflow: scroll; width: 500px; height: 400px; }
+ div { height: 100px }
+ #block2 { overflow: hidden }
+ #space { height: 1000px; }
+ </style>
+ <div id='scroller'><div id='space'>
+ <div id='block1'>abc</div>
+ <div id='block2'>def</div>
+ </div></div>
+ )HTML");
+ Element* scroller_element = GetDocument().getElementById("scroller");
+ ScrollableArea* scroller = ScrollerForElement(scroller_element);
+
+ Element* block1 = GetDocument().getElementById("block1");
+ Element* block2 = GetDocument().getElementById("block2");
+
+ Scrollbar* scrollbar = VerticalScrollbarForElement(scroller_element);
+ scroller->MouseEnteredScrollbar(*scrollbar);
+ MouseDownOnVerticalScrollbar(scrollbar);
+ MouseDragVerticalScrollbar(scrollbar, 150);
+ EXPECT_NEAR(150, scroller->GetScrollOffset().Height(),
+ kScrollbarDragAccuracy);
+
+ // In this layout pass we will anchor to #block2 which has its own PaintLayer.
+ SetHeight(block1, 200);
+ EXPECT_NEAR(250, scroller->ScrollOffsetInt().Height(),
+ kScrollbarDragAccuracy);
+ EXPECT_EQ(block2->GetLayoutObject(),
+ GetScrollAnchor(scroller).AnchorObject());
+
+ // If we continue dragging the scroller should scroll from the newly anchored
+ // position.
+ MouseDragVerticalScrollbar(scrollbar, 10);
+ EXPECT_NEAR(260, scroller->ScrollOffsetInt().Height(),
+ kScrollbarDragAccuracy);
+ MouseUpOnVerticalScrollbar(scrollbar);
+}
+
// Verify that a nested scroller with a div that has its own PaintLayer can be
// removed without causing a crash. This test passes if it doesn't crash.
TEST_P(ScrollAnchorTest, RemoveScrollerWithLayerInScrollingDiv) {
@@ -353,7 +450,7 @@ TEST_P(ScrollAnchorTest, RemoveScrollerWithLayerInScrollingDiv) {
Element* changer2 = GetDocument().getElementById("changer2");
Element* anchor = GetDocument().getElementById("anchor");
- scroller->ScrollBy(ScrollOffset(0, 150), kUserScroll);
+ scroller->ScrollBy(ScrollOffset(0, 150), mojom::blink::ScrollType::kUser);
ScrollLayoutViewport(ScrollOffset(0, 50));
// In this layout pass both the inner and outer scroller will anchor to
@@ -949,11 +1046,12 @@ TEST_P(ScrollAnchorTest, ClampAdjustsAnchorAnimation) {
<div class="content" id=three></div>
<div class="content" id=four></div>
)HTML");
- LayoutViewport()->SetScrollOffset(ScrollOffset(0, 2000), kUserScroll);
+ LayoutViewport()->SetScrollOffset(ScrollOffset(0, 2000),
+ mojom::blink::ScrollType::kUser);
Update();
GetDocument().getElementById("hidden")->setAttribute(html_names::kStyleAttr,
"display:block");
- GetDocument().UpdateStyleAndLayout();
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
#if !defined(OS_MACOSX)
EXPECT_EQ(IntSize(0, 200), LayoutViewport()
->GetScrollAnimator()
@@ -961,7 +1059,7 @@ TEST_P(ScrollAnchorTest, ClampAdjustsAnchorAnimation) {
#endif
GetDocument().getElementById("hidden")->setAttribute(html_names::kStyleAttr,
"");
- GetDocument().UpdateStyleAndLayout();
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
// The clamping scroll after resizing layout overflow to be smaller
// should adjust the animation back to 0.
EXPECT_EQ(IntSize(0, 0), LayoutViewport()
diff --git a/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc b/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc
index 174a0472eec..5ffb764ec5e 100644
--- a/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc
@@ -30,6 +30,8 @@
#include "third_party/blink/renderer/platform/testing/testing_platform_support.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
+#include "ui/base/cursor/cursor.h"
+#include "ui/base/mojom/cursor_type.mojom-blink.h"
namespace blink {
@@ -74,19 +76,8 @@ class StubWebThemeEngine : public WebThemeEngine {
return painted_color_scheme_[part];
}
- blink::PreferredColorScheme PreferredColorScheme() const override {
- return preferred_color_scheme_;
- }
-
- void SetPreferredColorScheme(
- const blink::PreferredColorScheme preferred_color_scheme) override {
- preferred_color_scheme_ = preferred_color_scheme;
- }
-
private:
std::array<WebColorScheme, kPartProgressBar + 1> painted_color_scheme_;
- blink::PreferredColorScheme preferred_color_scheme_ =
- blink::PreferredColorScheme::kNoPreference;
};
constexpr int StubWebThemeEngine::kMinimumHorizontalLength;
@@ -136,8 +127,8 @@ class ScrollbarsTest : public SimTest {
}
void HandleMouseMoveEvent(int x, int y) {
- WebMouseEvent event(WebInputEvent::kMouseMove, WebFloatPoint(x, y),
- WebFloatPoint(x, y),
+ WebMouseEvent event(WebInputEvent::kMouseMove, gfx::PointF(x, y),
+ gfx::PointF(x, y),
WebPointerProperties::Button::kNoButton, 0,
WebInputEvent::kNoModifiers, base::TimeTicks::Now());
event.SetFrameScale(1);
@@ -146,17 +137,17 @@ class ScrollbarsTest : public SimTest {
}
void HandleMousePressEvent(int x, int y) {
- WebMouseEvent event(
- WebInputEvent::kMouseDown, WebFloatPoint(x, y), WebFloatPoint(x, y),
- WebPointerProperties::Button::kLeft, 0,
- WebInputEvent::Modifiers::kLeftButtonDown, base::TimeTicks::Now());
+ WebMouseEvent event(WebInputEvent::kMouseDown, gfx::PointF(x, y),
+ gfx::PointF(x, y), WebPointerProperties::Button::kLeft,
+ 0, WebInputEvent::Modifiers::kLeftButtonDown,
+ base::TimeTicks::Now());
event.SetFrameScale(1);
GetEventHandler().HandleMousePressEvent(event);
}
void HandleContextMenuEvent(int x, int y) {
WebMouseEvent event(
- WebInputEvent::kMouseDown, WebFloatPoint(x, y), WebFloatPoint(x, y),
+ WebInputEvent::kMouseDown, gfx::PointF(x, y), gfx::PointF(x, y),
WebPointerProperties::Button::kNoButton, 0,
WebInputEvent::Modifiers::kNoModifiers, base::TimeTicks::Now());
event.SetFrameScale(1);
@@ -164,17 +155,17 @@ class ScrollbarsTest : public SimTest {
}
void HandleMouseReleaseEvent(int x, int y) {
- WebMouseEvent event(
- WebInputEvent::kMouseUp, WebFloatPoint(x, y), WebFloatPoint(x, y),
- WebPointerProperties::Button::kLeft, 0,
- WebInputEvent::Modifiers::kNoModifiers, base::TimeTicks::Now());
+ WebMouseEvent event(WebInputEvent::kMouseUp, gfx::PointF(x, y),
+ gfx::PointF(x, y), WebPointerProperties::Button::kLeft,
+ 0, WebInputEvent::Modifiers::kNoModifiers,
+ base::TimeTicks::Now());
event.SetFrameScale(1);
GetEventHandler().HandleMouseReleaseEvent(event);
}
void HandleMouseMiddlePressEvent(int x, int y) {
WebMouseEvent event(
- WebInputEvent::kMouseDown, WebFloatPoint(x, y), WebFloatPoint(x, y),
+ WebInputEvent::kMouseDown, gfx::PointF(x, y), gfx::PointF(x, y),
WebPointerProperties::Button::kMiddle, 0,
WebInputEvent::Modifiers::kMiddleButtonDown, base::TimeTicks::Now());
event.SetFrameScale(1);
@@ -183,7 +174,7 @@ class ScrollbarsTest : public SimTest {
void HandleMouseMiddleReleaseEvent(int x, int y) {
WebMouseEvent event(
- WebInputEvent::kMouseUp, WebFloatPoint(x, y), WebFloatPoint(x, y),
+ WebInputEvent::kMouseUp, gfx::PointF(x, y), gfx::PointF(x, y),
WebPointerProperties::Button::kMiddle, 0,
WebInputEvent::Modifiers::kMiddleButtonDown, base::TimeTicks::Now());
event.SetFrameScale(1);
@@ -191,10 +182,10 @@ class ScrollbarsTest : public SimTest {
}
void HandleMouseLeaveEvent() {
- WebMouseEvent event(
- WebInputEvent::kMouseMove, WebFloatPoint(1, 1), WebFloatPoint(1, 1),
- WebPointerProperties::Button::kLeft, 0,
- WebInputEvent::Modifiers::kLeftButtonDown, base::TimeTicks::Now());
+ WebMouseEvent event(WebInputEvent::kMouseLeave, gfx::PointF(1, 1),
+ gfx::PointF(1, 1), WebPointerProperties::Button::kLeft,
+ 0, WebInputEvent::Modifiers::kLeftButtonDown,
+ base::TimeTicks::Now());
event.SetFrameScale(1);
GetEventHandler().HandleMouseLeaveEvent(event);
}
@@ -215,12 +206,12 @@ class ScrollbarsTest : public SimTest {
offset);
}
- ui::CursorType CursorType() {
+ ui::mojom::blink::CursorType CursorType() {
return GetDocument()
.GetFrame()
->GetChromeClient()
.LastSetCursorForTesting()
- .GetType();
+ .type();
}
ScrollbarTheme& GetScrollbarTheme() {
@@ -235,7 +226,7 @@ class ScrollbarsTest : public SimTest {
WebGestureEvent event(type, WebInputEvent::kNoModifiers,
base::TimeTicks::Now(), device);
- event.SetPositionInWidget(WebFloatPoint(position.X(), position.Y()));
+ event.SetPositionInWidget(gfx::PointF(position.X(), position.Y()));
if (type == WebInputEvent::kGestureScrollUpdate) {
event.data.scroll_update.delta_x = offset.Width();
@@ -370,7 +361,7 @@ TEST(ScrollbarsTestWithOwnWebViewHelper, ScrollbarSizeForUseZoomDSF) {
"</body>",
base_url);
web_view_impl->MainFrameWidget()->UpdateAllLifecyclePhases(
- WebWidget::LifecycleUpdateReason::kTest);
+ DocumentUpdateReason::kTest);
Document* document =
To<LocalFrame>(web_view_impl->GetPage()->MainFrame())->GetDocument();
@@ -577,6 +568,45 @@ TEST_F(ScrollbarsTest, OverlayScrollbarChangeToDisplayNoneDynamically) {
EXPECT_TRUE(scrollable_root->HorizontalScrollbar()->FrameRect().IsEmpty());
}
+// Ensure that overlay scrollbars are not created, even in overflow:scroll,
+// situations when there's no overflow. Specifically, after style-only changes.
+TEST_F(ScrollbarsTest, OverlayScrolblarNotCreatedInUnscrollableAxis) {
+ // This test is specifically checking the behavior when overlay scrollbars
+ // are enabled.
+ ENABLE_OVERLAY_SCROLLBARS(true);
+
+ WebView().MainFrameWidget()->Resize(WebSize(800, 600));
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ #target {
+ width: 100px;
+ height: 100px;
+ overflow-y: scroll;
+ opacity: 0.5;
+ }
+ </style>
+ <div id="target"></div>
+ )HTML");
+
+ Compositor().BeginFrame();
+
+ auto* target = GetDocument().getElementById("target");
+ auto* scrollable_area = target->GetLayoutBox()->GetScrollableArea();
+
+ ASSERT_FALSE(scrollable_area->VerticalScrollbar());
+ ASSERT_FALSE(scrollable_area->HorizontalScrollbar());
+
+ // Mutate the opacity so that we cause a style-only change.
+ target->setAttribute(html_names::kStyleAttr, "opacity: 0.9");
+ Compositor().BeginFrame();
+
+ ASSERT_FALSE(scrollable_area->VerticalScrollbar());
+ ASSERT_FALSE(scrollable_area->HorizontalScrollbar());
+}
+
TEST_F(ScrollbarsTest, scrollbarIsNotHandlingTouchpadScroll) {
WebView().MainFrameWidget()->Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
@@ -603,11 +633,11 @@ TEST_F(ScrollbarsTest, scrollbarIsNotHandlingTouchpadScroll) {
WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers,
base::TimeTicks::Now(), WebGestureDevice::kTouchpad);
scroll_begin.SetPositionInWidget(
- WebFloatPoint(scrollable->OffsetLeft() + scrollable->OffsetWidth() - 2,
- scrollable->OffsetTop()));
+ gfx::PointF(scrollable->OffsetLeft() + scrollable->OffsetWidth() - 2,
+ scrollable->OffsetTop()));
scroll_begin.SetPositionInScreen(
- WebFloatPoint(scrollable->OffsetLeft() + scrollable->OffsetWidth() - 2,
- scrollable->OffsetTop()));
+ gfx::PointF(scrollable->OffsetLeft() + scrollable->OffsetWidth() - 2,
+ scrollable->OffsetTop()));
scroll_begin.data.scroll_begin.delta_x_hint = 0;
scroll_begin.data.scroll_begin.delta_y_hint = 10;
scroll_begin.SetFrameScale(1);
@@ -647,8 +677,8 @@ TEST_F(ScrollbarsTest, HidingScrollbarsOnScrollableAreaDisablesScrollbars) {
ScrollableArea* frame_scroller_area = frame_view->LayoutViewport();
// Scrollbars are hidden at start.
- scroller_area->SetScrollbarsHiddenIfOverlay(true);
- frame_scroller_area->SetScrollbarsHiddenIfOverlay(true);
+ scroller_area->SetScrollbarsHiddenForTesting(true);
+ frame_scroller_area->SetScrollbarsHiddenForTesting(true);
ASSERT_TRUE(scroller_area->HorizontalScrollbar());
ASSERT_TRUE(scroller_area->VerticalScrollbar());
ASSERT_TRUE(frame_scroller_area->HorizontalScrollbar());
@@ -666,23 +696,23 @@ TEST_F(ScrollbarsTest, HidingScrollbarsOnScrollableAreaDisablesScrollbars) {
EXPECT_FALSE(
scroller_area->VerticalScrollbar()->ShouldParticipateInHitTesting());
- frame_scroller_area->SetScrollbarsHiddenIfOverlay(false);
+ frame_scroller_area->SetScrollbarsHiddenForTesting(false);
EXPECT_TRUE(frame_scroller_area->HorizontalScrollbar()
->ShouldParticipateInHitTesting());
EXPECT_TRUE(frame_scroller_area->VerticalScrollbar()
->ShouldParticipateInHitTesting());
- frame_scroller_area->SetScrollbarsHiddenIfOverlay(true);
+ frame_scroller_area->SetScrollbarsHiddenForTesting(true);
EXPECT_FALSE(frame_scroller_area->HorizontalScrollbar()
->ShouldParticipateInHitTesting());
EXPECT_FALSE(frame_scroller_area->VerticalScrollbar()
->ShouldParticipateInHitTesting());
- scroller_area->SetScrollbarsHiddenIfOverlay(false);
+ scroller_area->SetScrollbarsHiddenForTesting(false);
EXPECT_TRUE(
scroller_area->HorizontalScrollbar()->ShouldParticipateInHitTesting());
EXPECT_TRUE(
scroller_area->VerticalScrollbar()->ShouldParticipateInHitTesting());
- scroller_area->SetScrollbarsHiddenIfOverlay(true);
+ scroller_area->SetScrollbarsHiddenForTesting(true);
EXPECT_FALSE(
scroller_area->HorizontalScrollbar()->ShouldParticipateInHitTesting());
EXPECT_FALSE(
@@ -733,7 +763,7 @@ TEST_F(ScrollbarsTest, MouseOverScrollbarInCustomCursorElement) {
HandleMouseMoveEvent(195, 5);
- EXPECT_EQ(ui::CursorType::kPointer, CursorType());
+ EXPECT_EQ(ui::mojom::blink::CursorType::kPointer, CursorType());
}
// Ensure mouse cursor should be override when hovering over the custom
@@ -789,7 +819,7 @@ TEST_F(ScrollbarsTest, MouseOverCustomScrollbarInCustomCursorElement) {
HandleMouseMoveEvent(195, 5);
- EXPECT_EQ(ui::CursorType::kMove, CursorType());
+ EXPECT_EQ(ui::mojom::blink::CursorType::kMove, CursorType());
}
// Makes sure that mouse hover over an overlay scrollbar doesn't activate
@@ -824,7 +854,7 @@ TEST_F(ScrollbarsTest, MouseOverLinkAndOverlayScrollbar) {
.MainFrameImpl()
->GetFrameView()
->LayoutViewport()
- ->SetScrollbarsHiddenIfOverlay(false);
+ ->SetScrollbarsHiddenForTesting(false);
Document& document = GetDocument();
Element* a_tag = document.getElementById("a");
@@ -844,13 +874,13 @@ TEST_F(ScrollbarsTest, MouseOverLinkAndOverlayScrollbar) {
// Mouse over link. Mouse cursor should be hand.
HandleMouseMoveEvent(a_tag->OffsetLeft(), a_tag->OffsetTop());
- EXPECT_EQ(ui::CursorType::kHand, CursorType());
+ EXPECT_EQ(ui::mojom::blink::CursorType::kHand, CursorType());
// Mouse over enabled overlay scrollbar. Mouse cursor should be pointer and no
// active hover element.
HandleMouseMoveEvent(x, y);
- EXPECT_EQ(ui::CursorType::kPointer, CursorType());
+ EXPECT_EQ(ui::mojom::blink::CursorType::kPointer, CursorType());
HandleMousePressEvent(x, y);
@@ -865,7 +895,7 @@ TEST_F(ScrollbarsTest, MouseOverLinkAndOverlayScrollbar) {
.MainFrameImpl()
->GetFrameView()
->LayoutViewport()
- ->SetScrollbarsHiddenIfOverlay(true);
+ ->SetScrollbarsHiddenForTesting(true);
// Ensure hittest only has link
hit_test_result = HitTest(x, y);
@@ -876,7 +906,7 @@ TEST_F(ScrollbarsTest, MouseOverLinkAndOverlayScrollbar) {
HandleMouseMoveEvent(x, y);
- EXPECT_EQ(ui::CursorType::kHand, CursorType());
+ EXPECT_EQ(ui::mojom::blink::CursorType::kHand, CursorType());
HandleMousePressEvent(x, y);
@@ -988,7 +1018,7 @@ TEST_F(ScrollbarsTest, MouseOverScrollbarAndIFrame) {
.MainFrameImpl()
->GetFrameView()
->LayoutViewport()
- ->SetScrollbarsHiddenIfOverlay(false);
+ ->SetScrollbarsHiddenForTesting(false);
frame_resource.Complete("<!DOCTYPE html>");
Compositor().BeginFrame();
@@ -1026,7 +1056,7 @@ TEST_F(ScrollbarsTest, MouseOverScrollbarAndIFrame) {
.MainFrameImpl()
->GetFrameView()
->LayoutViewport()
- ->SetScrollbarsHiddenIfOverlay(true);
+ ->SetScrollbarsHiddenForTesting(true);
// Ensure hittest has IFRAME and no scrollbar.
hit_test_result = HitTest(196, 5);
@@ -1510,8 +1540,9 @@ TEST_F(ScrollbarsTestWithVirtualTimer, TestNonCompositedOverlayScrollbarsFade) {
RunTasksForPeriod(kMockOverlayFadeOutDelay);
EXPECT_TRUE(scrollable_area->ScrollbarsHiddenIfOverlay());
- scrollable_area->SetScrollOffset(ScrollOffset(10, 10), kProgrammaticScroll,
- kScrollBehaviorInstant);
+ scrollable_area->SetScrollOffset(ScrollOffset(10, 10),
+ mojom::blink::ScrollType::kProgrammatic,
+ mojom::blink::ScrollBehavior::kInstant);
EXPECT_FALSE(scrollable_area->ScrollbarsHiddenIfOverlay());
RunTasksForPeriod(kMockOverlayFadeOutDelay);
@@ -1533,8 +1564,9 @@ TEST_F(ScrollbarsTestWithVirtualTimer, TestNonCompositedOverlayScrollbarsFade) {
// Non-composited scrollbars don't fade out while mouse is over.
EXPECT_TRUE(scrollable_area->VerticalScrollbar());
- scrollable_area->SetScrollOffset(ScrollOffset(20, 20), kProgrammaticScroll,
- kScrollBehaviorInstant);
+ scrollable_area->SetScrollOffset(ScrollOffset(20, 20),
+ mojom::blink::ScrollType::kProgrammatic,
+ mojom::blink::ScrollBehavior::kInstant);
EXPECT_FALSE(scrollable_area->ScrollbarsHiddenIfOverlay());
scrollable_area->MouseEnteredScrollbar(*scrollable_area->VerticalScrollbar());
RunTasksForPeriod(kMockOverlayFadeOutDelay);
@@ -1693,7 +1725,7 @@ TEST_P(ScrollbarAppearanceTest, HugeScrollingThumbPosition) {
Compositor().BeginFrame();
scrollable_area->SetScrollOffset(ScrollOffset(0, 10000000),
- kProgrammaticScroll);
+ mojom::blink::ScrollType::kProgrammatic);
Compositor().BeginFrame();
@@ -2124,7 +2156,7 @@ TEST_F(ScrollbarsTest,
PaintLayerScrollableArea* scrollable_div =
ToLayoutBox(div->GetLayoutObject())->GetScrollableArea();
- scrollable_div->SetScrollbarsHiddenIfOverlay(false);
+ scrollable_div->SetScrollbarsHiddenForTesting(false);
ASSERT_TRUE(scrollable_div);
ASSERT_TRUE(scrollable_div->GetPageScrollbarTheme().UsesOverlayScrollbars());
ASSERT_TRUE(scrollable_div->VerticalScrollbar());
@@ -2137,7 +2169,7 @@ TEST_F(ScrollbarsTest,
// After paint layer in scrollable dispose, we can still call scrollbar hidden
// just not change scrollbar.
- scrollable_div->SetScrollbarsHiddenIfOverlay(true);
+ scrollable_div->SetScrollbarsHiddenForTesting(true);
EXPECT_FALSE(scrollable_div->ScrollbarsHiddenIfOverlay());
}
@@ -2179,7 +2211,7 @@ TEST_F(ScrollbarsTest, PLSADisposeShouldClearPointerInLayers) {
ASSERT_TRUE(graphics_layer);
div->setAttribute(html_names::kClassAttr, "hide");
- document.UpdateStyleAndLayout();
+ document.UpdateStyleAndLayout(DocumentUpdateReason::kTest);
EXPECT_FALSE(paint_layer->GetScrollableArea());
}
@@ -2219,7 +2251,7 @@ TEST_F(ScrollbarsTest, OverlayScrollbarHitTest) {
.MainFrameImpl()
->GetFrameView()
->LayoutViewport()
- ->SetScrollbarsHiddenIfOverlay(false);
+ ->SetScrollbarsHiddenForTesting(false);
frame_resource.Complete("<!DOCTYPE html><body style='height: 999px'></body>");
Compositor().BeginFrame();
@@ -2230,7 +2262,7 @@ TEST_F(ScrollbarsTest, OverlayScrollbarHitTest) {
iframe_element->contentDocument()
->View()
->LayoutViewport()
- ->SetScrollbarsHiddenIfOverlay(false);
+ ->SetScrollbarsHiddenForTesting(false);
// Hit test on and off the main frame scrollbar.
HitTestResult hit_test_result = HitTest(295, 5);
@@ -2315,12 +2347,13 @@ TEST_F(ScrollbarsTest, MiddleDownShouldNotAffectScrollbarPress) {
EXPECT_EQ(scrollbar->PressedPart(), ScrollbarPart::kThumbPart);
// Move mouse out of scrollbar with press.
- WebMouseEvent event(WebInputEvent::kMouseMove, WebFloatPoint(5, 5),
- WebFloatPoint(5, 5), WebPointerProperties::Button::kLeft,
- 0, WebInputEvent::Modifiers::kLeftButtonDown,
+ WebMouseEvent event(WebInputEvent::kMouseMove, gfx::PointF(5, 5),
+ gfx::PointF(5, 5), WebPointerProperties::Button::kLeft, 0,
+ WebInputEvent::Modifiers::kLeftButtonDown,
base::TimeTicks::Now());
event.SetFrameScale(1);
- GetEventHandler().HandleMouseLeaveEvent(event);
+ GetEventHandler().HandleMouseMoveEvent(event, Vector<WebMouseEvent>(),
+ Vector<WebMouseEvent>());
EXPECT_EQ(scrollbar->PressedPart(), ScrollbarPart::kThumbPart);
// Middle click should not release scrollbar press state.
@@ -2614,7 +2647,7 @@ TEST_F(ScrollbarsTest, CheckScrollCornerIfThereIsNoScrollbar) {
// Make the container non-scrollable so the scrollbar and corner disappear.
element->setAttribute(html_names::kStyleAttr, "width: 100px;");
- GetDocument().UpdateStyleAndLayout();
+ GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kTest);
EXPECT_FALSE(scrollable_container->HasScrollbar());
EXPECT_FALSE(scrollable_container->ScrollCorner());
@@ -2675,8 +2708,9 @@ TEST_F(ScrollbarsTestWithVirtualTimer,
Scrollbar* scrollbar = scrollable_area->VerticalScrollbar();
// Scroll to bottom.
- scrollable_area->SetScrollOffset(ScrollOffset(0, 400), kProgrammaticScroll,
- kScrollBehaviorInstant);
+ scrollable_area->SetScrollOffset(ScrollOffset(0, 400),
+ mojom::blink::ScrollType::kProgrammatic,
+ mojom::blink::ScrollBehavior::kInstant);
EXPECT_EQ(scrollable_area->ScrollOffsetInt(), IntSize(0, 200));
HandleMouseMoveEvent(195, 195);
@@ -2803,7 +2837,8 @@ INSTANTIATE_TEST_SUITE_P(NonOverlay,
TEST_P(ScrollbarColorSchemeTest, MAYBE_ThemeEnginePaint) {
ScopedTestingPlatformSupport<ScrollbarTestingPlatformSupport> platform;
- ScopedCSSColorSchemeForTest css_feature_scope(true);
+ ScopedCSSColorSchemeForTest color_scheme_scope(true);
+ ScopedCSSColorSchemeUARenderingForTest color_scheme_ua_scope(true);
WebView().MainFrameWidget()->Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
@@ -2827,9 +2862,8 @@ TEST_P(ScrollbarColorSchemeTest, MAYBE_ThemeEnginePaint) {
</div>
)HTML");
- ColorSchemeHelper color_scheme_helper;
- color_scheme_helper.SetPreferredColorScheme(GetDocument(),
- PreferredColorScheme::kDark);
+ ColorSchemeHelper color_scheme_helper(GetDocument());
+ color_scheme_helper.SetPreferredColorScheme(PreferredColorScheme::kDark);
Compositor().BeginFrame();
diff --git a/chromium/third_party/blink/renderer/core/layout/shapes/shape.cc b/chromium/third_party/blink/renderer/core/layout/shapes/shape.cc
index f961184aee3..702e55999e0 100644
--- a/chromium/third_party/blink/renderer/core/layout/shapes/shape.cc
+++ b/chromium/third_party/blink/renderer/core/layout/shapes/shape.cc
@@ -234,7 +234,8 @@ std::unique_ptr<Shape> Shape::CreateEmptyRasterShape(WritingMode writing_mode,
static bool ExtractImageData(Image* image,
const IntSize& image_size,
- ArrayBufferContents& contents) {
+ ArrayBufferContents& contents,
+ RespectImageOrientationEnum respect_orientation) {
if (!image)
return false;
@@ -260,8 +261,8 @@ static bool ExtractImageData(Image* image,
canvas.clear(SK_ColorTRANSPARENT);
image->Draw(&canvas, flags, FloatRect(image_dest_rect), image_source_rect,
- kDoNotRespectImageOrientation,
- Image::kDoNotClampImageToSourceRect, Image::kSyncDecode);
+ respect_orientation, Image::kDoNotClampImageToSourceRect,
+ Image::kSyncDecode);
size_t size_in_bytes;
if (!StaticBitmapImage::GetSizeInBytes(image_dest_rect, color_params)
@@ -332,12 +333,14 @@ static bool IsValidRasterShapeSize(const IntSize& size) {
return size.Area() * 4 < max_image_size_bytes;
}
-std::unique_ptr<Shape> Shape::CreateRasterShape(Image* image,
- float threshold,
- const LayoutRect& image_r,
- const LayoutRect& margin_r,
- WritingMode writing_mode,
- float margin) {
+std::unique_ptr<Shape> Shape::CreateRasterShape(
+ Image* image,
+ float threshold,
+ const LayoutRect& image_r,
+ const LayoutRect& margin_r,
+ WritingMode writing_mode,
+ float margin,
+ RespectImageOrientationEnum respect_orientation) {
IntRect image_rect = PixelSnappedIntRect(image_r);
IntRect margin_rect = PixelSnappedIntRect(margin_r);
@@ -347,8 +350,10 @@ std::unique_ptr<Shape> Shape::CreateRasterShape(Image* image,
}
ArrayBufferContents contents;
- if (!ExtractImageData(image, image_rect.Size(), contents))
+ if (!ExtractImageData(image, image_rect.Size(), contents,
+ respect_orientation)) {
return CreateEmptyRasterShape(writing_mode, margin);
+ }
std::unique_ptr<RasterShapeIntervals> intervals =
ExtractIntervalsFromImageData(contents, threshold, image_rect,
diff --git a/chromium/third_party/blink/renderer/core/layout/shapes/shape.h b/chromium/third_party/blink/renderer/core/layout/shapes/shape.h
index 45be4d014bc..77f7cfacb31 100644
--- a/chromium/third_party/blink/renderer/core/layout/shapes/shape.h
+++ b/chromium/third_party/blink/renderer/core/layout/shapes/shape.h
@@ -35,6 +35,7 @@
#include "third_party/blink/renderer/core/style/basic_shapes.h"
#include "third_party/blink/renderer/core/style/style_image.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
+#include "third_party/blink/renderer/platform/graphics/image_orientation.h"
#include "third_party/blink/renderer/platform/graphics/path.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
@@ -84,7 +85,8 @@ class CORE_EXPORT Shape {
const LayoutRect& image_rect,
const LayoutRect& margin_rect,
WritingMode,
- float margin);
+ float margin,
+ RespectImageOrientationEnum);
static std::unique_ptr<Shape> CreateLayoutBoxShape(const FloatRoundedRect&,
WritingMode,
float margin);
diff --git a/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc b/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
index 96cbb7e0912..c9f477b2f0d 100644
--- a/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
+++ b/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.cc
@@ -30,6 +30,7 @@
#include "third_party/blink/renderer/core/layout/shapes/shape_outside_info.h"
#include <memory>
+
#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/frame/web_feature.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
@@ -39,6 +40,7 @@
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_image.h"
#include "third_party/blink/renderer/platform/geometry/length_functions.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
namespace blink {
@@ -152,10 +154,10 @@ static bool CheckShapeImageOrigin(Document& document,
const KURL& url = image_resource.Url();
String url_string = url.IsNull() ? "''" : url.ElidedString();
- document.AddConsoleMessage(
- ConsoleMessage::Create(mojom::ConsoleMessageSource::kSecurity,
- mojom::ConsoleMessageLevel::kError,
- "Unsafe attempt to load URL " + url_string + "."));
+ document.AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
+ mojom::ConsoleMessageSource::kSecurity,
+ mojom::ConsoleMessageLevel::kError,
+ "Unsafe attempt to load URL " + url_string + "."));
return false;
}
@@ -186,7 +188,8 @@ std::unique_ptr<Shape> ShapeOutsideInfo::CreateShapeForImage(
DCHECK(!style_image->IsPendingImage());
const LayoutSize& image_size = RoundedLayoutSize(style_image->ImageSize(
layout_box_.GetDocument(), layout_box_.StyleRef().EffectiveZoom(),
- reference_box_logical_size_));
+ reference_box_logical_size_,
+ LayoutObject::ShouldRespectImageOrientation(&layout_box_)));
const LayoutRect& margin_rect =
GetShapeImageMarginRect(layout_box_, reference_box_logical_size_);
@@ -199,9 +202,9 @@ std::unique_ptr<Shape> ShapeOutsideInfo::CreateShapeForImage(
style_image->GetImage(layout_box_, layout_box_.GetDocument(),
layout_box_.StyleRef(), FloatSize(image_size));
- return Shape::CreateRasterShape(image.get(), shape_image_threshold,
- image_rect, margin_rect, writing_mode,
- margin);
+ return Shape::CreateRasterShape(
+ image.get(), shape_image_threshold, image_rect, margin_rect, writing_mode,
+ margin, LayoutObject::ShouldRespectImageOrientation(&layout_box_));
}
const Shape& ShapeOutsideInfo::ComputedShape() const {
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/BUILD.gn b/chromium/third_party/blink/renderer/core/layout/svg/BUILD.gn
index 3c0d78bbf16..b01361cc458 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/layout/svg/BUILD.gn
@@ -12,6 +12,8 @@ blink_core_sources("svg_layout") {
"layout_svg_container.h",
"layout_svg_ellipse.cc",
"layout_svg_ellipse.h",
+ "layout_svg_filter_primitive.cc",
+ "layout_svg_filter_primitive.h",
"layout_svg_foreign_object.cc",
"layout_svg_foreign_object.h",
"layout_svg_hidden_container.cc",
@@ -34,8 +36,6 @@ blink_core_sources("svg_layout") {
"layout_svg_resource_container.h",
"layout_svg_resource_filter.cc",
"layout_svg_resource_filter.h",
- "layout_svg_resource_filter_primitive.cc",
- "layout_svg_resource_filter_primitive.h",
"layout_svg_resource_gradient.cc",
"layout_svg_resource_gradient.h",
"layout_svg_resource_linear_gradient.cc",
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.h
index 8c8dfbfff4a..e95571ca527 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.h
@@ -82,11 +82,6 @@ class LayoutSVGBlock : public LayoutBlockFlow {
const HitTestLocation&,
const PhysicalOffset& accumulated_offset,
HitTestAction) override;
-
- // The inherited version doesn't check for SVG effects.
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override {
- return false;
- }
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
index c9085ba3376..da375b67877 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.cc
@@ -84,7 +84,7 @@ void LayoutSVGContainer::UpdateLayout() {
void LayoutSVGContainer::AddChild(LayoutObject* child,
LayoutObject* before_child) {
LayoutSVGModelObject::AddChild(child, before_child);
- SVGResourcesCache::ClientWasAddedToTree(*child, child->StyleRef());
+ SVGResourcesCache::ClientWasAddedToTree(*child);
bool should_isolate_descendants =
(child->IsBlendingAllowed() && child->StyleRef().HasBlendMode()) ||
@@ -172,7 +172,6 @@ void LayoutSVGContainer::UpdateCachedBoundaries() {
SVGLayoutSupport::ComputeContainerBoundingBoxes(
this, object_bounding_box_, object_bounding_box_valid_,
stroke_bounding_box_, local_visual_rect_);
- GetElement()->SetNeedsResizeObserverUpdate();
}
bool LayoutSVGContainer::NodeAtPoint(HitTestResult& result,
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
index ba23efa422d..c0ec38b1592 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_container.h
@@ -24,6 +24,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_CONTAINER_H_
#include "third_party/blink/renderer/core/layout/svg/layout_svg_model_object.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -108,7 +109,12 @@ class LayoutSVGContainer : public LayoutSVGModelObject {
mutable bool has_non_isolated_blending_descendants_dirty_ : 1;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutSVGContainer, IsSVGContainer());
+template <>
+struct DowncastTraits<LayoutSVGContainer> {
+ static bool AllowFrom(const LayoutObject& object) {
+ return object.IsSVGContainer();
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter_primitive.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.cc
index bbc7bb39112..7ab539720ab 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter_primitive.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.cc
@@ -25,12 +25,16 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter_primitive.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.h"
#include "third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.h"
namespace blink {
+LayoutSVGFilterPrimitive::LayoutSVGFilterPrimitive(
+ SVGFilterPrimitiveStandardAttributes* filter_primitive_element)
+ : LayoutObject(filter_primitive_element) {}
+
static bool CurrentColorChanged(StyleDifference diff, const StyleColor& color) {
return diff.TextDecorationOrColorChanged() && color.IsCurrentColor();
}
@@ -51,15 +55,11 @@ static void CheckForColorChange(SVGFilterPrimitiveStandardAttributes& element,
element.PrimitiveAttributeChanged(attr_name);
}
-void LayoutSVGResourceFilterPrimitive::StyleDidChange(
- StyleDifference diff,
- const ComputedStyle* old_style) {
- LayoutSVGHiddenContainer::StyleDidChange(diff, old_style);
-
+void LayoutSVGFilterPrimitive::StyleDidChange(StyleDifference diff,
+ const ComputedStyle* old_style) {
if (!old_style)
return;
- DCHECK(GetElement());
- auto& element = To<SVGFilterPrimitiveStandardAttributes>(*GetElement());
+ auto& element = To<SVGFilterPrimitiveStandardAttributes>(*GetNode());
const SVGComputedStyle& new_style = StyleRef().SvgStyle();
if (IsA<SVGFEFloodElement>(element) || IsA<SVGFEDropShadowElement>(element)) {
CheckForColorChange(element, svg_names::kFloodColorAttr, diff,
@@ -80,4 +80,8 @@ void LayoutSVGResourceFilterPrimitive::StyleDidChange(
}
}
+void LayoutSVGFilterPrimitive::UpdateLayout() {
+ ClearNeedsLayout();
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter_primitive.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.h
index d52bdae9df2..b0e16f447fe 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter_primitive.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_filter_primitive.h
@@ -24,34 +24,42 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_RESOURCE_FILTER_PRIMITIVE_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_RESOURCE_FILTER_PRIMITIVE_H_
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_FILTER_PRIMITIVE_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_FILTER_PRIMITIVE_H_
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
namespace blink {
-class LayoutSVGResourceFilterPrimitive final : public LayoutSVGHiddenContainer {
+class SVGFilterPrimitiveStandardAttributes;
+
+class LayoutSVGFilterPrimitive final : public LayoutObject {
public:
- explicit LayoutSVGResourceFilterPrimitive(
- SVGElement* filter_primitive_element)
- : LayoutSVGHiddenContainer(filter_primitive_element) {}
+ explicit LayoutSVGFilterPrimitive(SVGFilterPrimitiveStandardAttributes*);
+ private:
bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override {
return false;
}
void StyleDidChange(StyleDifference, const ComputedStyle*) override;
+ void UpdateLayout() override;
- const char* GetName() const override {
- return "LayoutSVGResourceFilterPrimitive";
- }
+ const char* GetName() const override { return "LayoutSVGFilterPrimitive"; }
bool IsOfType(LayoutObjectType type) const override {
- return type == kLayoutObjectSVGResourceFilterPrimitive ||
- LayoutSVGHiddenContainer::IsOfType(type);
+ return type == kLayoutObjectSVG ||
+ type == kLayoutObjectSVGFilterPrimitive ||
+ LayoutObject::IsOfType(type);
+ }
+ FloatRect ObjectBoundingBox() const override { return FloatRect(); }
+ FloatRect VisualRectInLocalSVGCoordinates() const override {
+ return FloatRect();
+ }
+ FloatRect LocalBoundingBoxRectForAccessibility() const override {
+ return FloatRect();
}
};
} // namespace blink
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_RESOURCE_FILTER_PRIMITIVE_H_
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_FILTER_PRIMITIVE_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
index 838ac43a38f..9d38aab5c10 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object.h
@@ -22,6 +22,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_FOREIGN_OBJECT_H_
#include "third_party/blink/renderer/core/layout/svg/layout_svg_block.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -104,7 +105,12 @@ class LayoutSVGForeignObject final : public LayoutSVGBlock {
bool needs_transform_update_;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutSVGForeignObject, IsSVGForeignObject());
+template <>
+struct DowncastTraits<LayoutSVGForeignObject> {
+ static bool AllowFrom(const LayoutObject& object) {
+ return object.IsSVGForeignObject();
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h
index 6f01462ff3c..06e9e78248a 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h
@@ -45,9 +45,6 @@ class LayoutSVGHiddenContainer : public LayoutSVGContainer {
private:
// LayoutSVGHiddenContainer paints nothing.
void Paint(const PaintInfo&) const final {}
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const final {
- return true;
- }
PhysicalRect VisualRectInDocument(VisualRectFlags) const final {
return PhysicalRect();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
index df479631785..964f0769a77 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.cc
@@ -27,8 +27,10 @@
#include "third_party/blink/renderer/core/html/media/media_element_parser_helpers.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
+#include "third_party/blink/renderer/core/layout/intrinsic_sizing_info.h"
#include "third_party/blink/renderer/core/layout/layout_analyzer.h"
#include "third_party/blink/renderer/core/layout/layout_image_resource.h"
+#include "third_party/blink/renderer/core/layout/layout_replaced.h"
#include "third_party/blink/renderer/core/layout/pointer_events_hit_rules.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
@@ -38,6 +40,7 @@
#include "third_party/blink/renderer/core/layout/svg/transformed_hit_test_location.h"
#include "third_party/blink/renderer/core/paint/image_element_timing.h"
#include "third_party/blink/renderer/core/paint/svg_image_painter.h"
+#include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
#include "third_party/blink/renderer/core/svg/svg_image_element.h"
#include "third_party/blink/renderer/platform/geometry/length_functions.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_record.h"
@@ -78,37 +81,55 @@ static float ResolveHeightForRatio(float width,
return width * intrinsic_ratio.Height() / intrinsic_ratio.Width();
}
-IntSize LayoutSVGImage::GetOverriddenIntrinsicSize() const {
- if (auto* svg_image = DynamicTo<SVGImageElement>(GetElement())) {
- if (RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled())
- return svg_image->GetOverriddenIntrinsicSize();
- }
- return IntSize();
+bool LayoutSVGImage::HasOverriddenIntrinsicSize() const {
+ if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled())
+ return false;
+ auto* svg_image_element = DynamicTo<SVGImageElement>(GetElement());
+ return svg_image_element && svg_image_element->IsDefaultIntrinsicSize();
}
FloatSize LayoutSVGImage::CalculateObjectSize() const {
- FloatSize intrinsic_size = FloatSize(GetOverriddenIntrinsicSize());
+ FloatSize intrinsic_size;
ImageResourceContent* cached_image = image_resource_->CachedImage();
- if (intrinsic_size.IsEmpty()) {
+ bool has_intrinsic_ratio = true;
+ if (HasOverriddenIntrinsicSize()) {
+ intrinsic_size = FloatSize(LayoutReplaced::kDefaultWidth,
+ LayoutReplaced::kDefaultHeight);
+ } else {
if (!cached_image || cached_image->ErrorOccurred() ||
!cached_image->IsSizeAvailable())
return object_bounding_box_.Size();
- intrinsic_size = FloatSize(cached_image->GetImage()->Size());
+ RespectImageOrientationEnum respect_orientation =
+ LayoutObject::ShouldRespectImageOrientation(this);
+ intrinsic_size = cached_image->GetImage()->SizeAsFloat(respect_orientation);
+ if (auto* svg_image = DynamicTo<SVGImage>(cached_image->GetImage())) {
+ IntrinsicSizingInfo intrinsic_sizing_info;
+ has_intrinsic_ratio &= svg_image->GetIntrinsicSizingInfo(intrinsic_sizing_info);
+ has_intrinsic_ratio &= !intrinsic_sizing_info.aspect_ratio.IsEmpty();
+ }
}
if (StyleRef().Width().IsAuto() && StyleRef().Height().IsAuto())
return intrinsic_size;
- if (StyleRef().Height().IsAuto())
- return FloatSize(
- object_bounding_box_.Width(),
- ResolveHeightForRatio(object_bounding_box_.Width(), intrinsic_size));
+ if (StyleRef().Height().IsAuto()) {
+ if (has_intrinsic_ratio) {
+ return FloatSize(
+ object_bounding_box_.Width(),
+ ResolveHeightForRatio(object_bounding_box_.Width(), intrinsic_size));
+ }
+ return FloatSize(object_bounding_box_.Width(), intrinsic_size.Height());
+ }
DCHECK(StyleRef().Width().IsAuto());
- return FloatSize(
- ResolveWidthForRatio(object_bounding_box_.Height(), intrinsic_size),
- object_bounding_box_.Height());
+ if (has_intrinsic_ratio) {
+ return FloatSize(
+ ResolveWidthForRatio(object_bounding_box_.Height(), intrinsic_size),
+ object_bounding_box_.Height());
+ }
+
+ return FloatSize(intrinsic_size.Width(), object_bounding_box_.Height());
}
bool LayoutSVGImage::UpdateBoundingBox() {
@@ -126,7 +147,6 @@ bool LayoutSVGImage::UpdateBoundingBox() {
object_bounding_box_.SetSize(CalculateObjectSize());
if (old_object_bounding_box != object_bounding_box_) {
- GetElement()->SetNeedsResizeObserverUpdate();
SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kImage);
needs_boundaries_update_ = true;
}
@@ -174,7 +194,7 @@ void LayoutSVGImage::UpdateLayout() {
DCHECK(!needs_transform_update_);
if (auto* svg_image_element = DynamicTo<SVGImageElement>(GetElement())) {
- media_element_parser_helpers::ReportUnsizedMediaViolation(
+ media_element_parser_helpers::CheckUnsizedMediaViolation(
this, svg_image_element->IsDefaultIntrinsicSize());
}
ClearNeedsLayout();
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
index a56500db2f8..bc8b9227afa 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_image.h
@@ -80,7 +80,7 @@ class LayoutSVGImage final : public LayoutSVGModelObject {
}
FloatSize CalculateObjectSize() const;
- IntSize GetOverriddenIntrinsicSize() const;
+ bool HasOverriddenIntrinsicSize() const;
bool needs_boundaries_update_ : 1;
bool needs_transform_update_ : 1;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc
index 78e884af5cf..04b832c1ddf 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc
@@ -60,27 +60,27 @@ InlineFlowBox* LayoutSVGInline::CreateInlineFlowBox() {
}
FloatRect LayoutSVGInline::ObjectBoundingBox() const {
- if (const LayoutSVGText* text_root =
- LayoutSVGText::LocateLayoutSVGTextAncestor(this))
- return text_root->ObjectBoundingBox();
-
- return FloatRect();
+ FloatRect bounds;
+ for (InlineFlowBox* box : *LineBoxes())
+ bounds.Unite(FloatRect(box->FrameRect()));
+ return bounds;
}
FloatRect LayoutSVGInline::StrokeBoundingBox() const {
- if (const LayoutSVGText* text_root =
- LayoutSVGText::LocateLayoutSVGTextAncestor(this))
- return text_root->StrokeBoundingBox();
-
- return FloatRect();
+ if (!FirstLineBox())
+ return FloatRect();
+ return SVGLayoutSupport::ExtendTextBBoxWithStroke(*this, ObjectBoundingBox());
}
FloatRect LayoutSVGInline::VisualRectInLocalSVGCoordinates() const {
- if (const LayoutSVGText* text_root =
- LayoutSVGText::LocateLayoutSVGTextAncestor(this))
- return text_root->VisualRectInLocalSVGCoordinates();
-
- return FloatRect();
+ if (!FirstLineBox())
+ return FloatRect();
+ const LayoutSVGText* text_root =
+ LayoutSVGText::LocateLayoutSVGTextAncestor(this);
+ if (!text_root)
+ return FloatRect();
+ return SVGLayoutSupport::ComputeVisualRectForText(
+ *this, ObjectBoundingBox(), text_root->ObjectBoundingBox());
}
PhysicalRect LayoutSVGInline::VisualRectInDocument(
@@ -103,18 +103,10 @@ const LayoutObject* LayoutSVGInline::PushMappingToContainer(
void LayoutSVGInline::AbsoluteQuads(Vector<FloatQuad>& quads,
MapCoordinatesFlags mode) const {
- const LayoutSVGText* text_root =
- LayoutSVGText::LocateLayoutSVGTextAncestor(this);
- if (!text_root)
- return;
-
- FloatRect text_bounding_box = text_root->StrokeBoundingBox();
for (InlineFlowBox* box : *LineBoxes()) {
+ FloatRect box_rect(box->FrameRect());
quads.push_back(LocalToAbsoluteQuad(
- FloatRect(text_bounding_box.X() + box->X().ToFloat(),
- text_bounding_box.Y() + box->Y().ToFloat(),
- box->Width().ToFloat(), box->Height().ToFloat()),
- mode));
+ SVGLayoutSupport::ExtendTextBBoxWithStroke(*this, box_rect), mode));
}
}
@@ -145,19 +137,15 @@ void LayoutSVGInline::StyleDidChange(StyleDifference diff,
void LayoutSVGInline::AddChild(LayoutObject* child,
LayoutObject* before_child) {
LayoutInline::AddChild(child, before_child);
- SVGResourcesCache::ClientWasAddedToTree(*child, child->StyleRef());
-
- if (LayoutSVGText* text_layout_object =
- LayoutSVGText::LocateLayoutSVGTextAncestor(this))
- text_layout_object->SubtreeChildWasAdded();
+ SVGResourcesCache::ClientWasAddedToTree(*child);
+ LayoutSVGText::NotifySubtreeStructureChanged(
+ this, layout_invalidation_reason::kChildChanged);
}
void LayoutSVGInline::RemoveChild(LayoutObject* child) {
SVGResourcesCache::ClientWillBeRemovedFromTree(*child);
-
- if (LayoutSVGText* text_layout_object =
- LayoutSVGText::LocateLayoutSVGTextAncestor(this))
- text_layout_object->SubtreeChildWillBeRemoved();
+ LayoutSVGText::NotifySubtreeStructureChanged(
+ this, layout_invalidation_reason::kChildChanged);
LayoutInline::RemoveChild(child);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h
index 6322b6218cd..19b362d26fa 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.h
@@ -38,11 +38,6 @@ class LayoutSVGInline : public LayoutInline {
bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override;
- // Chapter 10.4 of the SVG Specification say that we should use the
- // object bounding box of the parent text element.
- // We search for the root text element and take its bounding box.
- // It is also necessary to take the stroke and visual rect of this element,
- // since we need it for filters.
FloatRect ObjectBoundingBox() const final;
FloatRect StrokeBoundingBox() const final;
FloatRect VisualRectInLocalSVGCoordinates() const final;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
index 5a089322736..4df02e440c4 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.cc
@@ -59,9 +59,8 @@ LayoutSVGInlineText::LayoutSVGInlineText(Node* n,
void LayoutSVGInlineText::TextDidChange() {
SetTextInternal(NormalizeWhitespace(GetText().Impl()));
LayoutText::TextDidChange();
- if (LayoutSVGText* text_layout_object =
- LayoutSVGText::LocateLayoutSVGTextAncestor(this))
- text_layout_object->SubtreeTextDidChange();
+ LayoutSVGText::NotifySubtreeStructureChanged(
+ this, layout_invalidation_reason::kTextChanged);
}
void LayoutSVGInlineText::StyleDidChange(StyleDifference diff,
@@ -69,10 +68,9 @@ void LayoutSVGInlineText::StyleDidChange(StyleDifference diff,
LayoutText::StyleDidChange(diff, old_style);
UpdateScaledFont();
- bool new_preserves =
- Style() ? StyleRef().WhiteSpace() == EWhiteSpace::kPre : false;
+ bool new_preserves = StyleRef().WhiteSpace() == EWhiteSpace::kPre;
bool old_preserves =
- old_style ? old_style->WhiteSpace() == EWhiteSpace::kPre : false;
+ old_style && old_style->WhiteSpace() == EWhiteSpace::kPre;
if (old_preserves != new_preserves) {
ForceSetText(OriginalText());
return;
@@ -153,7 +151,7 @@ bool LayoutSVGInlineText::CharacterStartsNewTextChunk(int position) const {
PositionWithAffinity LayoutSVGInlineText::PositionForPoint(
const PhysicalOffset& point) const {
- if (!HasTextBoxes() || !TextLength())
+ if (!HasInlineFragments() || !TextLength())
return CreatePositionWithAffinity(0);
DCHECK(scaling_factor_);
@@ -178,10 +176,10 @@ PositionWithAffinity LayoutSVGInlineText::PositionForPoint(
SVGInlineTextBox* closest_distance_box = nullptr;
for (InlineTextBox* box : TextBoxes()) {
- if (!box->IsSVGInlineTextBox())
+ auto* text_box = DynamicTo<SVGInlineTextBox>(box);
+ if (!text_box)
continue;
- SVGInlineTextBox* text_box = ToSVGInlineTextBox(box);
for (const SVGTextFragment& fragment : text_box->TextFragments()) {
FloatRect fragment_rect = fragment.BoundingBox(baseline);
@@ -416,8 +414,8 @@ void LayoutSVGInlineText::ComputeNewScaledFontForStyle(
FontDescription font_description = unscaled_font_description;
font_description.SetComputedSize(scaled_font_size);
- scaled_font = Font(font_description);
- scaled_font.Update(document.GetStyleEngine().GetFontSelector());
+ scaled_font =
+ Font(font_description, document.GetStyleEngine().GetFontSelector());
}
PhysicalRect LayoutSVGInlineText::VisualRectInDocument(
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.cc
index 61279e3cb9b..9f5bd0a1a6a 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.cc
@@ -56,6 +56,12 @@ void LayoutSVGPath::UpdateShapeFromElement() {
UpdateMarkers();
}
+const StylePath* LayoutSVGPath::GetStylePath() const {
+ if (!IsA<SVGPathElement>(*GetElement()))
+ return nullptr;
+ return StyleRef().SvgStyle().D();
+}
+
void LayoutSVGPath::UpdateMarkers() {
marker_positions_.clear();
@@ -74,12 +80,16 @@ void LayoutSVGPath::UpdateMarkers() {
if (!(marker_start || marker_mid || marker_end))
return;
- SVGMarkerDataBuilder(marker_positions_).Build(GetPath());
+ SVGMarkerDataBuilder builder(marker_positions_);
+ if (const StylePath* style_path = GetStylePath())
+ builder.Build(style_path->ByteStream());
+ else
+ builder.Build(GetPath());
if (marker_positions_.IsEmpty())
return;
- const float stroke_width = StrokeWidth();
+ const float stroke_width = StrokeWidthForMarkerUnits();
FloatRect boundaries;
for (const auto& position : marker_positions_) {
if (LayoutSVGResourceMarker* marker =
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.h
index 94cdea0c76c..97b0056bd1b 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.h
@@ -47,6 +47,7 @@ class LayoutSVGPath final : public LayoutSVGShape {
void UpdateShapeFromElement() override;
+ const StylePath* GetStylePath() const;
void UpdateMarkers();
Vector<MarkerPosition> marker_positions_;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
index 8778ec876b2..fcfbf011d02 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc
@@ -95,8 +95,8 @@ bool ContributesToClip(const SVGElement& element) {
}
Path PathFromElement(const SVGElement& element) {
- if (IsSVGGeometryElement(element))
- return ToSVGGeometryElement(element).ToClipPath();
+ if (auto* geometry_element = DynamicTo<SVGGeometryElement>(element))
+ return geometry_element->ToClipPath();
// Guaranteed by DetermineClipStrategy() above, only <use> element and
// SVGGraphicsElement that has a LayoutSVGShape can reach here.
@@ -106,20 +106,17 @@ Path PathFromElement(const SVGElement& element) {
} // namespace
LayoutSVGResourceClipper::LayoutSVGResourceClipper(SVGClipPathElement* node)
- : LayoutSVGResourceContainer(node), in_clip_expansion_(false) {}
+ : LayoutSVGResourceContainer(node) {}
LayoutSVGResourceClipper::~LayoutSVGResourceClipper() = default;
-void LayoutSVGResourceClipper::RemoveAllClientsFromCache(
- bool mark_for_invalidation) {
+void LayoutSVGResourceClipper::RemoveAllClientsFromCache() {
clip_content_path_validity_ = kClipContentPathUnknown;
clip_content_path_.Clear();
cached_paint_record_.reset();
local_clip_bounds_ = FloatRect();
- MarkAllClientsForInvalidation(
- mark_for_invalidation ? SVGResourceClient::kLayoutInvalidation |
- SVGResourceClient::kBoundariesInvalidation
- : SVGResourceClient::kParentOnlyInvalidation);
+ MarkAllClientsForInvalidation(SVGResourceClient::kLayoutInvalidation |
+ SVGResourceClient::kBoundariesInvalidation);
}
base::Optional<Path> LayoutSVGResourceClipper::AsPath() {
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h
index b8f71fbb74e..661f7b0dd95 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h
@@ -21,6 +21,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_RESOURCE_CLIPPER_H_
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
+#include "third_party/blink/renderer/core/style/reference_clip_path_operation.h"
#include "third_party/blink/renderer/core/svg/svg_unit_types.h"
#include "third_party/skia/include/core/SkRefCnt.h"
@@ -35,7 +36,7 @@ class LayoutSVGResourceClipper final : public LayoutSVGResourceContainer {
const char* GetName() const override { return "LayoutSVGResourceClipper"; }
- void RemoveAllClientsFromCache(bool mark_for_invalidation = true) override;
+ void RemoveAllClientsFromCache() override;
FloatRect ResourceBoundingBox(const FloatRect& reference_box);
@@ -50,16 +51,6 @@ class LayoutSVGResourceClipper final : public LayoutSVGResourceContainer {
base::Optional<Path> AsPath();
sk_sp<const PaintRecord> CreatePaintRecord();
- bool HasCycle() { return in_clip_expansion_; }
- void BeginClipExpansion() {
- DCHECK(!in_clip_expansion_);
- in_clip_expansion_ = true;
- }
- void EndClipExpansion() {
- DCHECK(in_clip_expansion_);
- in_clip_expansion_ = false;
- }
-
protected:
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
void WillBeDestroyed() override;
@@ -80,14 +71,21 @@ class LayoutSVGResourceClipper final : public LayoutSVGResourceContainer {
sk_sp<const PaintRecord> cached_paint_record_;
FloatRect local_clip_bounds_;
-
- // Reference cycle detection.
- bool in_clip_expansion_;
};
DEFINE_LAYOUT_SVG_RESOURCE_TYPE_CASTS(LayoutSVGResourceClipper,
kClipperResourceType);
+inline LayoutSVGResourceClipper* GetSVGResourceAsType(
+ const ClipPathOperation* clip_path_operation) {
+ const auto* reference_clip =
+ DynamicTo<ReferenceClipPathOperation>(clip_path_operation);
+ if (!reference_clip)
+ return nullptr;
+ return GetSVGResourceAsType<LayoutSVGResourceClipper>(
+ reference_clip->Resource());
+}
+
} // namespace blink
#endif
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
index ce06ebc5c63..da7fd935d74 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc
@@ -22,6 +22,7 @@
#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
+#include "third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h"
#include "third_party/blink/renderer/core/svg/svg_resource.h"
#include "third_party/blink/renderer/core/svg/svg_tree_scope_resources.h"
@@ -83,12 +84,66 @@ void LayoutSVGResourceContainer::StyleDidChange(
resource->NotifyResourceAttached(*this);
}
+bool LayoutSVGResourceContainer::FindCycle(
+ SVGResourcesCycleSolver& solver) const {
+ if (solver.IsKnownAcyclic(this))
+ return false;
+ SVGResourcesCycleSolver::Scope scope(solver);
+ if (!scope.Enter(this) || FindCycleFromSelf(solver))
+ return true;
+ solver.AddAcyclicSubgraph(this);
+ return false;
+}
+
+bool LayoutSVGResourceContainer::FindCycleInResources(
+ SVGResourcesCycleSolver& solver,
+ const LayoutObject& layout_object) const {
+ SVGResources* resources =
+ SVGResourcesCache::CachedResourcesForLayoutObject(layout_object);
+ if (!resources)
+ return false;
+ // Fetch all the referenced resources.
+ HashSet<LayoutSVGResourceContainer*> local_resources;
+ resources->BuildSetOfResources(local_resources);
+ // This performs a depth-first search for a back-edge in all the
+ // (potentially disjoint) graphs formed by the referenced resources.
+ for (auto* local_resource : local_resources) {
+ if (local_resource->FindCycle(solver))
+ return true;
+ }
+ return false;
+}
+
+bool LayoutSVGResourceContainer::FindCycleFromSelf(
+ SVGResourcesCycleSolver& solver) const {
+ if (FindCycleInResources(solver, *this))
+ return true;
+ return FindCycleInDescendants(solver);
+}
+
+bool LayoutSVGResourceContainer::FindCycleInDescendants(
+ SVGResourcesCycleSolver& solver) const {
+ LayoutObject* node = FirstChild();
+ while (node) {
+ // Skip subtrees which are themselves resources. (They will be
+ // processed - if needed - when they are actually referenced.)
+ if (node->IsSVGResourceContainer()) {
+ node = node->NextInPreOrderAfterChildren(this);
+ continue;
+ }
+ if (FindCycleInResources(solver, *node))
+ return true;
+ node = node->NextInPreOrder(this);
+ }
+ return false;
+}
+
void LayoutSVGResourceContainer::MarkAllClientsForInvalidation(
InvalidationModeMask invalidation_mask) {
if (is_invalidating_)
return;
LocalSVGResource* resource = ResourceForContainer(*this);
- if (!resource || !resource->HasClients())
+ if (!resource)
return;
// Remove modes for which invalidations have already been
// performed. If no modes remain we are done.
@@ -100,8 +155,7 @@ void LayoutSVGResourceContainer::MarkAllClientsForInvalidation(
is_invalidating_ = true;
// Invalidate clients registered via an SVGResource.
- if (resource)
- resource->NotifyContentChanged(invalidation_mask);
+ resource->NotifyContentChanged(invalidation_mask);
is_invalidating_ = false;
}
@@ -154,7 +208,7 @@ static inline void RemoveFromCacheAndInvalidateDependencies(
if (SVGResources* resources =
SVGResourcesCache::CachedResourcesForLayoutObject(object)) {
- SVGResourceClient* client = element->GetSVGResourceClient();
+ SVGElementResourceClient* client = element->GetSVGResourceClient();
if (InvalidationModeMask invalidation_mask =
resources->RemoveClientFromCacheAffectingObjectBounds(*client)) {
LayoutSVGResourceContainer::MarkClientForInvalidation(object,
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h
index 56cfe674218..9e5ef616025 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h
@@ -21,10 +21,14 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LAYOUT_SVG_RESOURCE_CONTAINER_H_
#include "third_party/blink/renderer/core/layout/svg/layout_svg_hidden_container.h"
+#include "third_party/blink/renderer/core/style/style_svg_resource.h"
+#include "third_party/blink/renderer/core/svg/svg_resource.h"
#include "third_party/blink/renderer/core/svg/svg_resource_client.h"
namespace blink {
+class SVGResourcesCycleSolver;
+
enum LayoutSVGResourceType {
kMaskerResourceType,
kMarkerResourceType,
@@ -40,7 +44,7 @@ class LayoutSVGResourceContainer : public LayoutSVGHiddenContainer {
explicit LayoutSVGResourceContainer(SVGElement*);
~LayoutSVGResourceContainer() override;
- virtual void RemoveAllClientsFromCache(bool mark_for_invalidation = true) = 0;
+ virtual void RemoveAllClientsFromCache() = 0;
// Remove any cached data for the |client|, and return true if so.
virtual bool RemoveClientFromCache(SVGResourceClient&) { return false; }
@@ -64,6 +68,8 @@ class LayoutSVGResourceContainer : public LayoutSVGHiddenContainer {
SubtreeLayoutScope* = nullptr);
void InvalidateCacheAndMarkForLayout(SubtreeLayoutScope* = nullptr);
+ bool FindCycle(SVGResourcesCycleSolver&) const;
+
static void MarkForLayoutAndParentResourceInvalidation(
LayoutObject&,
bool needs_layout = true);
@@ -75,6 +81,11 @@ class LayoutSVGResourceContainer : public LayoutSVGHiddenContainer {
// Used from RemoveAllClientsFromCache methods.
void MarkAllClientsForInvalidation(InvalidationModeMask);
+ bool FindCycleFromSelf(SVGResourcesCycleSolver&) const;
+ bool FindCycleInDescendants(SVGResourcesCycleSolver&) const;
+ bool FindCycleInResources(SVGResourcesCycleSolver&,
+ const LayoutObject&) const;
+
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
void WillBeDestroyed() override;
@@ -97,6 +108,30 @@ DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutSVGResourceContainer,
resource->ResourceType() == typeName, \
resource.ResourceType() == typeName)
+template <typename ContainerType>
+inline bool IsResourceOfType(const LayoutSVGResourceContainer* container) {
+ return container->ResourceType() == ContainerType::kResourceType;
+}
+
+template <typename ContainerType>
+inline ContainerType* GetSVGResourceAsType(const SVGResource* resource) {
+ if (!resource)
+ return nullptr;
+ if (LayoutSVGResourceContainer* container = resource->ResourceContainer()) {
+ if (IsResourceOfType<ContainerType>(container))
+ return static_cast<ContainerType*>(container);
+ }
+ return nullptr;
+}
+
+template <typename ContainerType>
+inline ContainerType* GetSVGResourceAsType(
+ const StyleSVGResource* style_resource) {
+ if (!style_resource)
+ return nullptr;
+ return GetSVGResourceAsType<ContainerType>(style_resource->Resource());
+}
+
} // namespace blink
#endif
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
index 9fcc0e045dd..09784e4b5e8 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc
@@ -23,66 +23,23 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h"
-#include "third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h"
#include "third_party/blink/renderer/core/svg/svg_filter_element.h"
-#include "third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.h"
-#include "third_party/blink/renderer/core/svg/svg_resource.h"
namespace blink {
-void FilterData::Trace(blink::Visitor* visitor) {
- visitor->Trace(last_effect);
- visitor->Trace(node_map);
-}
-
-void FilterData::Dispose() {
- node_map = nullptr;
- if (last_effect)
- last_effect->DisposeImageFiltersRecursive();
- last_effect = nullptr;
-}
-
LayoutSVGResourceFilter::LayoutSVGResourceFilter(SVGFilterElement* node)
- : LayoutSVGResourceContainer(node),
- filter_(MakeGarbageCollected<FilterMap>()) {}
+ : LayoutSVGResourceContainer(node) {}
LayoutSVGResourceFilter::~LayoutSVGResourceFilter() = default;
-void LayoutSVGResourceFilter::DisposeFilterMap() {
- for (auto& entry : *filter_)
- entry.value->Dispose();
- filter_->clear();
-}
-
-void LayoutSVGResourceFilter::WillBeDestroyed() {
- DisposeFilterMap();
- LayoutSVGResourceContainer::WillBeDestroyed();
-}
-
bool LayoutSVGResourceFilter::IsChildAllowed(LayoutObject* child,
const ComputedStyle&) const {
- return child->IsSVGResourceFilterPrimitive();
-}
-
-void LayoutSVGResourceFilter::RemoveAllClientsFromCache(
- bool mark_for_invalidation) {
- // LayoutSVGResourceFilter::removeClientFromCache will be called for
- // all clients through markAllClientsForInvalidation so no explicit
- // display item invalidation is needed here.
- DisposeFilterMap();
- MarkAllClientsForInvalidation(
- mark_for_invalidation ? SVGResourceClient::kLayoutInvalidation |
- SVGResourceClient::kBoundariesInvalidation
- : SVGResourceClient::kParentOnlyInvalidation);
+ return child->IsSVGFilterPrimitive();
}
-bool LayoutSVGResourceFilter::RemoveClientFromCache(SVGResourceClient& client) {
- auto entry = filter_->find(&client);
- if (entry == filter_->end())
- return false;
- entry->value->Dispose();
- filter_->erase(entry);
- return true;
+void LayoutSVGResourceFilter::RemoveAllClientsFromCache() {
+ MarkAllClientsForInvalidation(SVGResourceClient::kLayoutInvalidation |
+ SVGResourceClient::kBoundariesInvalidation);
}
FloatRect LayoutSVGResourceFilter::ResourceBoundingBox(
@@ -106,32 +63,18 @@ SVGUnitTypes::SVGUnitType LayoutSVGResourceFilter::PrimitiveUnits() const {
->EnumValue();
}
-void LayoutSVGResourceFilter::PrimitiveAttributeChanged(
- SVGFilterPrimitiveStandardAttributes& primitive,
- const QualifiedName& attribute) {
- LayoutObject* object = primitive.GetLayoutObject();
-
- for (auto& filter : *filter_) {
- FilterData* filter_data = filter.value.Get();
- if (filter_data->state_ != FilterData::kReadyToPaint)
- continue;
-
- SVGFilterGraphNodeMap* node_map = filter_data->node_map.Get();
- FilterEffect* effect = node_map->EffectByRenderer(object);
- if (!effect)
- continue;
- // Since all effects shares the same attribute value, all
- // or none of them will be changed.
- if (!primitive.SetFilterEffectAttribute(effect, attribute))
- return;
- node_map->InvalidateDependentEffects(effect);
- }
- if (auto* resource =
- To<SVGFilterElement>(GetElement())->AssociatedResource()) {
- resource->NotifyContentChanged(
- SVGResourceClient::kPaintInvalidation |
- SVGResourceClient::kSkipAncestorInvalidation);
- }
+LayoutSVGResourceFilter* GetFilterResourceForSVG(const ComputedStyle& style) {
+ if (!style.HasFilter())
+ return nullptr;
+ const FilterOperations& operations = style.Filter();
+ if (operations.size() != 1)
+ return nullptr;
+ const auto* reference_filter =
+ DynamicTo<ReferenceFilterOperation>(*operations.at(0));
+ if (!reference_filter)
+ return nullptr;
+ return GetSVGResourceAsType<LayoutSVGResourceFilter>(
+ reference_filter->Resource());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h
index 49907fcf609..e1584b2f26c 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h
@@ -29,39 +29,7 @@
namespace blink {
-class FilterEffect;
class SVGFilterElement;
-class SVGFilterGraphNodeMap;
-class SVGFilterPrimitiveStandardAttributes;
-
-class FilterData final : public GarbageCollected<FilterData> {
- public:
- /*
- * The state transitions should follow the following:
- * Initial->RecordingContent->ReadyToPaint->PaintingFilter->ReadyToPaint
- * | ^ | ^
- * v | v |
- * RecordingContentCycleDetected PaintingFilterCycle
- */
- enum FilterDataState {
- kInitial,
- kRecordingContent,
- kRecordingContentCycleDetected,
- kReadyToPaint,
- kPaintingFilter,
- kPaintingFilterCycleDetected
- };
-
- FilterData() : state_(kInitial) {}
-
- void Dispose();
-
- void Trace(blink::Visitor*);
-
- Member<FilterEffect> last_effect;
- Member<SVGFilterGraphNodeMap> node_map;
- FilterDataState state_;
-};
class LayoutSVGResourceFilter final : public LayoutSVGResourceContainer {
public:
@@ -71,44 +39,24 @@ class LayoutSVGResourceFilter final : public LayoutSVGResourceContainer {
bool IsChildAllowed(LayoutObject*, const ComputedStyle&) const override;
const char* GetName() const override { return "LayoutSVGResourceFilter"; }
- bool IsOfType(LayoutObjectType type) const override {
- return type == kLayoutObjectSVGResourceFilter ||
- LayoutSVGResourceContainer::IsOfType(type);
- }
- void RemoveAllClientsFromCache(bool mark_for_invalidation = true) override;
- bool RemoveClientFromCache(SVGResourceClient&) override;
+ void RemoveAllClientsFromCache() override;
FloatRect ResourceBoundingBox(const FloatRect& reference_box) const;
SVGUnitTypes::SVGUnitType FilterUnits() const;
SVGUnitTypes::SVGUnitType PrimitiveUnits() const;
- void PrimitiveAttributeChanged(SVGFilterPrimitiveStandardAttributes&,
- const QualifiedName&);
-
static const LayoutSVGResourceType kResourceType = kFilterResourceType;
LayoutSVGResourceType ResourceType() const override { return kResourceType; }
-
- FilterData* GetFilterDataForClient(const SVGResourceClient* client) {
- return filter_->at(const_cast<SVGResourceClient*>(client));
- }
- void SetFilterDataForClient(const SVGResourceClient* client,
- FilterData* filter_data) {
- filter_->Set(const_cast<SVGResourceClient*>(client), filter_data);
- }
-
- protected:
- void WillBeDestroyed() override;
-
- private:
- void DisposeFilterMap();
-
- using FilterMap = HeapHashMap<Member<SVGResourceClient>, Member<FilterData>>;
- Persistent<FilterMap> filter_;
};
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutSVGResourceFilter, IsSVGResourceFilter());
+// Get the LayoutSVGResourceFilter from the 'filter' property iff the 'filter'
+// is a single url(...) reference.
+LayoutSVGResourceFilter* GetFilterResourceForSVG(const ComputedStyle&);
+
+DEFINE_LAYOUT_SVG_RESOURCE_TYPE_CASTS(LayoutSVGResourceFilter,
+ kFilterResourceType);
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc
index 62d1617857a..2461347012a 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc
@@ -24,21 +24,28 @@
#include <memory>
+#include "third_party/blink/renderer/platform/graphics/gradient.h"
+
namespace blink {
+struct GradientData {
+ USING_FAST_MALLOC(GradientData);
+
+ public:
+ scoped_refptr<Gradient> gradient;
+ AffineTransform userspace_transform;
+};
+
LayoutSVGResourceGradient::LayoutSVGResourceGradient(SVGGradientElement* node)
: LayoutSVGResourcePaintServer(node),
should_collect_gradient_attributes_(true),
gradient_map_(MakeGarbageCollected<GradientMap>()) {}
-void LayoutSVGResourceGradient::RemoveAllClientsFromCache(
- bool mark_for_invalidation) {
+void LayoutSVGResourceGradient::RemoveAllClientsFromCache() {
gradient_map_->clear();
should_collect_gradient_attributes_ = true;
To<SVGGradientElement>(*GetElement()).InvalidateDependentGradients();
- MarkAllClientsForInvalidation(
- mark_for_invalidation ? SVGResourceClient::kPaintInvalidation
- : SVGResourceClient::kParentOnlyInvalidation);
+ MarkAllClientsForInvalidation(SVGResourceClient::kPaintInvalidation);
}
bool LayoutSVGResourceGradient::RemoveClientFromCache(
@@ -50,50 +57,52 @@ bool LayoutSVGResourceGradient::RemoveClientFromCache(
return true;
}
-SVGPaintServer LayoutSVGResourceGradient::PreparePaintServer(
- const SVGResourceClient& client,
+std::unique_ptr<GradientData> LayoutSVGResourceGradient::BuildGradientData(
const FloatRect& object_bounding_box) {
- ClearInvalidationMask();
+ // Create gradient object
+ auto gradient_data = std::make_unique<GradientData>();
// Validate gradient DOM state before building the actual
// gradient. This should avoid tearing down the gradient we're
// currently working on. Preferably the state validation should have
// no side-effects though.
if (should_collect_gradient_attributes_) {
- if (!CollectGradientAttributes())
- return SVGPaintServer::Invalid();
+ CollectGradientAttributes();
should_collect_gradient_attributes_ = false;
}
- // Spec: When the geometry of the applicable element has no width or height
- // and objectBoundingBox is specified, then the given effect (e.g. a gradient
- // or a filter) will be ignored.
- if (GradientUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox &&
- object_bounding_box.IsEmpty())
- return SVGPaintServer::Invalid();
+ // We want the text bounding box applied to the gradient space transform
+ // now, so the gradient shader can use it.
+ if (GradientUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
+ // Spec: When the geometry of the applicable element has no width or height
+ // and objectBoundingBox is specified, then the given effect (e.g. a
+ // gradient or a filter) will be ignored.
+ if (object_bounding_box.IsEmpty())
+ return gradient_data;
+ gradient_data->userspace_transform.Translate(object_bounding_box.X(),
+ object_bounding_box.Y());
+ gradient_data->userspace_transform.ScaleNonUniform(
+ object_bounding_box.Width(), object_bounding_box.Height());
+ }
+
+ // Create gradient object
+ gradient_data->gradient = BuildGradient();
+
+ AffineTransform gradient_transform = CalculateGradientTransform();
+ gradient_data->userspace_transform *= gradient_transform;
+
+ return gradient_data;
+}
+
+SVGPaintServer LayoutSVGResourceGradient::PreparePaintServer(
+ const SVGResourceClient& client,
+ const FloatRect& object_bounding_box) {
+ ClearInvalidationMask();
std::unique_ptr<GradientData>& gradient_data =
gradient_map_->insert(&client, nullptr).stored_value->value;
if (!gradient_data)
- gradient_data = std::make_unique<GradientData>();
-
- // Create gradient object
- if (!gradient_data->gradient) {
- gradient_data->gradient = BuildGradient();
-
- // We want the text bounding box applied to the gradient space transform
- // now, so the gradient shader can use it.
- if (GradientUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox &&
- !object_bounding_box.IsEmpty()) {
- gradient_data->userspace_transform.Translate(object_bounding_box.X(),
- object_bounding_box.Y());
- gradient_data->userspace_transform.ScaleNonUniform(
- object_bounding_box.Width(), object_bounding_box.Height());
- }
-
- AffineTransform gradient_transform = CalculateGradientTransform();
- gradient_data->userspace_transform *= gradient_transform;
- }
+ gradient_data = BuildGradientData(object_bounding_box);
if (!gradient_data->gradient)
return SVGPaintServer::Invalid();
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.h
index 6b974699227..530933fdc0d 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.h
@@ -25,25 +25,18 @@
#include <memory>
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h"
#include "third_party/blink/renderer/core/svg/svg_gradient_element.h"
-#include "third_party/blink/renderer/platform/graphics/gradient.h"
#include "third_party/blink/renderer/platform/transforms/affine_transform.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
namespace blink {
-struct GradientData {
- USING_FAST_MALLOC(GradientData);
-
- public:
- scoped_refptr<Gradient> gradient;
- AffineTransform userspace_transform;
-};
+struct GradientData;
class LayoutSVGResourceGradient : public LayoutSVGResourcePaintServer {
public:
explicit LayoutSVGResourceGradient(SVGGradientElement*);
- void RemoveAllClientsFromCache(bool mark_for_invalidation = true) final;
+ void RemoveAllClientsFromCache() final;
bool RemoveClientFromCache(SVGResourceClient&) final;
SVGPaintServer PreparePaintServer(const SVGResourceClient&,
@@ -54,13 +47,16 @@ class LayoutSVGResourceGradient : public LayoutSVGResourcePaintServer {
protected:
virtual SVGUnitTypes::SVGUnitType GradientUnits() const = 0;
virtual AffineTransform CalculateGradientTransform() const = 0;
- virtual bool CollectGradientAttributes() = 0;
+ virtual void CollectGradientAttributes() = 0;
virtual scoped_refptr<Gradient> BuildGradient() const = 0;
static GradientSpreadMethod PlatformSpreadMethodFromSVGType(
SVGSpreadMethodType);
private:
+ std::unique_ptr<GradientData> BuildGradientData(
+ const FloatRect& object_bounding_box);
+
bool should_collect_gradient_attributes_ : 1;
using GradientMap = HeapHashMap<Member<const SVGResourceClient>,
std::unique_ptr<GradientData>>;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_linear_gradient.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_linear_gradient.cc
index 460a76c10da..8d88444f724 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_linear_gradient.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_linear_gradient.cc
@@ -33,10 +33,10 @@ LayoutSVGResourceLinearGradient::LayoutSVGResourceLinearGradient(
LayoutSVGResourceLinearGradient::~LayoutSVGResourceLinearGradient() = default;
-bool LayoutSVGResourceLinearGradient::CollectGradientAttributes() {
+void LayoutSVGResourceLinearGradient::CollectGradientAttributes() {
DCHECK(GetElement());
attributes_wrapper_->Set(LinearGradientAttributes());
- return To<SVGLinearGradientElement>(GetElement())
+ To<SVGLinearGradientElement>(GetElement())
->CollectGradientAttributes(MutableAttributes());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_linear_gradient.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_linear_gradient.h
index bbad601c2c1..48c43d53806 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_linear_gradient.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_linear_gradient.h
@@ -47,7 +47,7 @@ class LayoutSVGResourceLinearGradient final : public LayoutSVGResourceGradient {
AffineTransform CalculateGradientTransform() const override {
return Attributes().GradientTransform();
}
- bool CollectGradientAttributes() override;
+ void CollectGradientAttributes() override;
scoped_refptr<Gradient> BuildGradient() const override;
FloatPoint StartPoint(const LinearGradientAttributes&) const;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc
index ba43918adba..491b18a5c92 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc
@@ -47,12 +47,9 @@ void LayoutSVGResourceMarker::UpdateLayout() {
ClearInvalidationMask();
}
-void LayoutSVGResourceMarker::RemoveAllClientsFromCache(
- bool mark_for_invalidation) {
- MarkAllClientsForInvalidation(
- mark_for_invalidation ? SVGResourceClient::kLayoutInvalidation |
- SVGResourceClient::kBoundariesInvalidation
- : SVGResourceClient::kParentOnlyInvalidation);
+void LayoutSVGResourceMarker::RemoveAllClientsFromCache() {
+ MarkAllClientsForInvalidation(SVGResourceClient::kLayoutInvalidation |
+ SVGResourceClient::kBoundariesInvalidation);
}
FloatRect LayoutSVGResourceMarker::MarkerBoundaries(
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h
index d8596cdafdf..58a23afc549 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h
@@ -35,7 +35,7 @@ class LayoutSVGResourceMarker final : public LayoutSVGResourceContainer {
const char* GetName() const override { return "LayoutSVGResourceMarker"; }
- void RemoveAllClientsFromCache(bool mark_for_invalidation = true) override;
+ void RemoveAllClientsFromCache() override;
// Calculates marker boundaries, mapped to the target element's coordinate
// space.
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
index df8d4817416..b1e201d9a8b 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.cc
@@ -36,14 +36,11 @@ LayoutSVGResourceMasker::LayoutSVGResourceMasker(SVGMaskElement* node)
LayoutSVGResourceMasker::~LayoutSVGResourceMasker() = default;
-void LayoutSVGResourceMasker::RemoveAllClientsFromCache(
- bool mark_for_invalidation) {
+void LayoutSVGResourceMasker::RemoveAllClientsFromCache() {
cached_paint_record_.reset();
mask_content_boundaries_ = FloatRect();
- MarkAllClientsForInvalidation(
- mark_for_invalidation ? SVGResourceClient::kLayoutInvalidation |
- SVGResourceClient::kBoundariesInvalidation
- : SVGResourceClient::kParentOnlyInvalidation);
+ MarkAllClientsForInvalidation(SVGResourceClient::kLayoutInvalidation |
+ SVGResourceClient::kBoundariesInvalidation);
}
sk_sp<const PaintRecord> LayoutSVGResourceMasker::CreatePaintRecord(
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h
index 70442a2ddbd..6bb360059c0 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h
@@ -38,7 +38,7 @@ class LayoutSVGResourceMasker final : public LayoutSVGResourceContainer {
const char* GetName() const override { return "LayoutSVGResourceMasker"; }
- void RemoveAllClientsFromCache(bool mark_for_invalidation = true) override;
+ void RemoveAllClientsFromCache() override;
FloatRect ResourceBoundingBox(const FloatRect& reference_box);
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc
index fdc8bc00edd..58231ff80fc 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc
@@ -147,7 +147,7 @@ SVGPaintServer SVGPaintServer::RequestForLayoutObject(
return SVGPaintServer(paint_description.color);
SVGPaintServer paint_server = paint_description.resource->PreparePaintServer(
*SVGResources::GetClient(layout_object),
- layout_object.ObjectBoundingBox());
+ SVGResources::ReferenceBoxForEffects(layout_object));
if (paint_server.IsValid())
return paint_server;
if (paint_description.has_fallback)
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h
index fad76f41cb6..9706a786c85 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h
@@ -114,11 +114,11 @@ class LayoutSVGResourcePaintServer : public LayoutSVGResourceContainer {
LayoutSVGResourceMode);
};
-DEFINE_TYPE_CASTS(LayoutSVGResourcePaintServer,
- LayoutSVGResourceContainer,
- resource,
- resource->IsSVGPaintServer(),
- resource.IsSVGPaintServer());
+template <>
+inline bool IsResourceOfType<LayoutSVGResourcePaintServer>(
+ const LayoutSVGResourceContainer* container) {
+ return container->IsSVGPaintServer();
+}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
index 754d3cef50d..6944d125c20 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc
@@ -52,13 +52,10 @@ LayoutSVGResourcePattern::LayoutSVGResourcePattern(SVGPatternElement* node)
attributes_wrapper_(MakeGarbageCollected<PatternAttributesWrapper>()),
pattern_map_(MakeGarbageCollected<PatternMap>()) {}
-void LayoutSVGResourcePattern::RemoveAllClientsFromCache(
- bool mark_for_invalidation) {
+void LayoutSVGResourcePattern::RemoveAllClientsFromCache() {
pattern_map_->clear();
should_collect_pattern_attributes_ = true;
- MarkAllClientsForInvalidation(
- mark_for_invalidation ? SVGResourceClient::kPaintInvalidation
- : SVGResourceClient::kParentOnlyInvalidation);
+ MarkAllClientsForInvalidation(SVGResourceClient::kPaintInvalidation);
}
bool LayoutSVGResourcePattern::RemoveClientFromCache(
@@ -70,51 +67,53 @@ bool LayoutSVGResourcePattern::RemoveClientFromCache(
return true;
}
-PatternData* LayoutSVGResourcePattern::PatternForClient(
- const SVGResourceClient& client,
+std::unique_ptr<PatternData> LayoutSVGResourcePattern::BuildPatternData(
const FloatRect& object_bounding_box) {
- DCHECK(!should_collect_pattern_attributes_);
+ auto pattern_data = std::make_unique<PatternData>();
- // FIXME: the double hash lookup is needed to guard against paint-time
- // invalidation (painting animated images may trigger layout invals which
- // delete our map entry). Hopefully that will be addressed at some point, and
- // then we can optimize the lookup.
- if (PatternData* current_data = pattern_map_->at(&client))
- return current_data;
-
- return pattern_map_->Set(&client, BuildPatternData(object_bounding_box))
- .stored_value->value.get();
-}
+ DCHECK(GetElement());
+ // Validate pattern DOM state before building the actual pattern. This should
+ // avoid tearing down the pattern we're currently working on. Preferably the
+ // state validation should have no side-effects though.
+ if (should_collect_pattern_attributes_) {
+ attributes_wrapper_->Set(PatternAttributes());
+ auto* pattern_element = To<SVGPatternElement>(GetElement());
+ pattern_element->CollectPatternAttributes(MutableAttributes());
+ should_collect_pattern_attributes_ = false;
+ }
-std::unique_ptr<PatternData> LayoutSVGResourcePattern::BuildPatternData(
- const FloatRect& object_bounding_box) {
- // If we couldn't determine the pattern content element root, stop here.
const PatternAttributes& attributes = Attributes();
- if (!attributes.PatternContentElement())
- return nullptr;
- // An empty viewBox disables layout.
- if (attributes.HasViewBox() && attributes.ViewBox().IsEmpty())
- return nullptr;
+ // Spec: When the geometry of the applicable element has no width or height
+ // and objectBoundingBox is specified, then the given effect (e.g. a gradient
+ // or a filter) will be ignored.
+ if (attributes.PatternUnits() ==
+ SVGUnitTypes::kSvgUnitTypeObjectboundingbox &&
+ object_bounding_box.IsEmpty())
+ return pattern_data;
+
+ // If there's no content disable rendering of the pattern.
+ if (!attributes.PatternContentElement())
+ return pattern_data;
- DCHECK(GetElement());
// Compute tile metrics.
FloatRect tile_bounds = SVGLengthContext::ResolveRectangle(
GetElement(), attributes.PatternUnits(), object_bounding_box,
*attributes.X(), *attributes.Y(), *attributes.Width(),
*attributes.Height());
if (tile_bounds.IsEmpty())
- return nullptr;
+ return pattern_data;
AffineTransform tile_transform;
if (attributes.HasViewBox()) {
+ // An empty viewBox disables rendering of the pattern.
if (attributes.ViewBox().IsEmpty())
- return nullptr;
+ return pattern_data;
tile_transform = SVGFitToViewBox::ViewBoxToViewTransform(
attributes.ViewBox(), attributes.PreserveAspectRatio(),
tile_bounds.Width(), tile_bounds.Height());
} else {
- // A viewbox overrides patternContentUnits, per spec.
+ // A viewBox overrides patternContentUnits, per spec.
if (attributes.PatternContentUnits() ==
SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
tile_transform.Scale(object_bounding_box.Width(),
@@ -122,7 +121,6 @@ std::unique_ptr<PatternData> LayoutSVGResourcePattern::BuildPatternData(
}
}
- std::unique_ptr<PatternData> pattern_data = base::WrapUnique(new PatternData);
pattern_data->pattern = Pattern::CreatePaintRecordPattern(
AsPaintRecord(tile_bounds.Size(), tile_transform),
FloatRect(FloatPoint(), tile_bounds.Size()));
@@ -139,27 +137,12 @@ SVGPaintServer LayoutSVGResourcePattern::PreparePaintServer(
const FloatRect& object_bounding_box) {
ClearInvalidationMask();
- // Validate pattern DOM state before building the actual
- // pattern. This should avoid tearing down the pattern we're
- // currently working on. Preferably the state validation should have
- // no side-effects though.
- if (should_collect_pattern_attributes_) {
- attributes_wrapper_->Set(PatternAttributes());
- auto* pattern_element = To<SVGPatternElement>(GetElement());
- pattern_element->CollectPatternAttributes(MutableAttributes());
- should_collect_pattern_attributes_ = false;
- }
-
- // Spec: When the geometry of the applicable element has no width or height
- // and objectBoundingBox is specified, then the given effect (e.g. a gradient
- // or a filter) will be ignored.
- if (Attributes().PatternUnits() ==
- SVGUnitTypes::kSvgUnitTypeObjectboundingbox &&
- object_bounding_box.IsEmpty())
- return SVGPaintServer::Invalid();
+ std::unique_ptr<PatternData>& pattern_data =
+ pattern_map_->insert(&client, nullptr).stored_value->value;
+ if (!pattern_data)
+ pattern_data = BuildPatternData(object_bounding_box);
- PatternData* pattern_data = PatternForClient(client, object_bounding_box);
- if (!pattern_data || !pattern_data->pattern)
+ if (!pattern_data->pattern)
return SVGPaintServer::Invalid();
return SVGPaintServer(pattern_data->pattern, pattern_data->transform);
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.h
index e293f39d1ba..4630fee0837 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.h
@@ -41,7 +41,7 @@ class LayoutSVGResourcePattern final : public LayoutSVGResourcePaintServer {
const char* GetName() const override { return "LayoutSVGResourcePattern"; }
- void RemoveAllClientsFromCache(bool mark_for_invalidation = true) override;
+ void RemoveAllClientsFromCache() override;
bool RemoveClientFromCache(SVGResourceClient&) override;
SVGPaintServer PreparePaintServer(
@@ -56,8 +56,6 @@ class LayoutSVGResourcePattern final : public LayoutSVGResourcePaintServer {
const FloatRect& object_bounding_box);
sk_sp<PaintRecord> AsPaintRecord(const FloatSize&,
const AffineTransform&) const;
- PatternData* PatternForClient(const SVGResourceClient&,
- const FloatRect& object_bounding_box);
const LayoutSVGResourceContainer* ResolveContentElement() const;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.cc
index 9b335862268..bf85cc000e6 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.cc
@@ -34,10 +34,10 @@ LayoutSVGResourceRadialGradient::LayoutSVGResourceRadialGradient(
LayoutSVGResourceRadialGradient::~LayoutSVGResourceRadialGradient() = default;
-bool LayoutSVGResourceRadialGradient::CollectGradientAttributes() {
+void LayoutSVGResourceRadialGradient::CollectGradientAttributes() {
DCHECK(GetElement());
attributes_wrapper_->Set(RadialGradientAttributes());
- return To<SVGRadialGradientElement>(GetElement())
+ To<SVGRadialGradientElement>(GetElement())
->CollectGradientAttributes(MutableAttributes());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.h
index d6f1b760124..41771233f1f 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_radial_gradient.h
@@ -47,7 +47,7 @@ class LayoutSVGResourceRadialGradient final : public LayoutSVGResourceGradient {
AffineTransform CalculateGradientTransform() const override {
return Attributes().GradientTransform();
}
- bool CollectGradientAttributes() override;
+ void CollectGradientAttributes() override;
scoped_refptr<Gradient> BuildGradient() const override;
FloatPoint CenterPoint(const RadialGradientAttributes&) const;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
index 534abb8f071..551f84f910c 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc
@@ -130,7 +130,7 @@ LayoutUnit LayoutSVGRoot::ComputeReplacedLogicalWidth(
// (border-image/background-image/<html:img>/...) we're forced to resize to a
// specific size.
if (!container_size_.IsEmpty())
- return LayoutUnit(container_size_.Width());
+ return container_size_.Width();
if (IsEmbeddedThroughFrameContainingSVGDocument())
return ContainingBlock()->AvailableLogicalWidth();
@@ -144,7 +144,7 @@ LayoutUnit LayoutSVGRoot::ComputeReplacedLogicalHeight(
// (border-image/background-image/<html:img>/...) we're forced to resize to a
// specific size.
if (!container_size_.IsEmpty())
- return LayoutUnit(container_size_.Height());
+ return container_size_.Height();
if (IsEmbeddedThroughFrameContainingSVGDocument())
return ContainingBlock()->AvailableLogicalHeight(
@@ -300,7 +300,7 @@ bool LayoutSVGRoot::StyleChangeAffectsIntrinsicSize(
}
void LayoutSVGRoot::IntrinsicSizingInfoChanged() {
- SetPreferredLogicalWidthsDirty();
+ SetIntrinsicLogicalWidthsDirty();
// TODO(fs): Merge with IntrinsicSizeChanged()? (from LayoutReplaced)
// Ignore changes to intrinsic dimensions if the <svg> is not in an SVG
@@ -315,7 +315,7 @@ void LayoutSVGRoot::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) {
if (diff.NeedsFullLayout())
SetNeedsBoundariesUpdate();
- if (diff.NeedsFullPaintInvalidation()) {
+ if (diff.NeedsPaintInvalidation()) {
// Box decorations may have appeared/disappeared - recompute status.
has_box_decoration_background_ = StyleRef().HasBoxDecorationBackground();
}
@@ -336,7 +336,7 @@ bool LayoutSVGRoot::IsChildAllowed(LayoutObject* child,
void LayoutSVGRoot::AddChild(LayoutObject* child, LayoutObject* before_child) {
LayoutReplaced::AddChild(child, before_child);
- SVGResourcesCache::ClientWasAddedToTree(*child, child->StyleRef());
+ SVGResourcesCache::ClientWasAddedToTree(*child);
bool should_isolate_descendants =
(child->IsBlendingAllowed() && child->StyleRef().HasBlendMode()) ||
@@ -383,7 +383,7 @@ void LayoutSVGRoot::DescendantIsolationRequirementsChanged(
void LayoutSVGRoot::InsertedIntoTree() {
LayoutReplaced::InsertedIntoTree();
- SVGResourcesCache::ClientWasAddedToTree(*this, StyleRef());
+ SVGResourcesCache::ClientWasAddedToTree(*this);
}
void LayoutSVGRoot::WillBeRemovedFromTree() {
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
index 3246ac260bf..4bba76f4efb 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h
@@ -65,8 +65,8 @@ class CORE_EXPORT LayoutSVGRoot final : public LayoutReplaced {
needs_boundaries_or_transform_update_ = true;
}
- IntSize ContainerSize() const { return container_size_; }
- void SetContainerSize(const IntSize& container_size) {
+ LayoutSize ContainerSize() const { return container_size_; }
+ void SetContainerSize(const LayoutSize& container_size) {
// SVGImage::draw() does a view layout prior to painting,
// and we need that layout to know of the new size otherwise
// the layout may be incorrectly using the old size.
@@ -162,7 +162,7 @@ class CORE_EXPORT LayoutSVGRoot final : public LayoutReplaced {
PositionWithAffinity PositionForPoint(const PhysicalOffset&) const final;
LayoutObjectChildList children_;
- IntSize container_size_;
+ LayoutSize container_size_;
FloatRect object_bounding_box_;
bool object_bounding_box_valid_;
FloatRect stroke_bounding_box_;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc
index cc0f2983d0b..40e7ae0d1b4 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root_test.cc
@@ -96,39 +96,6 @@ TEST_F(LayoutSVGRootTest, VisualRectMappingWithViewportClipAndBorder) {
EXPECT_EQ(PhysicalRect(0, 0, 220, 120), root_visual_rect);
}
-TEST_F(LayoutSVGRootTest,
- PaintedOutputOfObjectHasNoEffectRegardlessOfSizeEmpty) {
- SetBodyInnerHTML(R"HTML(
- <svg id="svg" width="100.1%" height="16">
- <rect width="100%" height="16" fill="#fff"></rect>
- </svg>
- )HTML");
-
- const LayoutSVGRoot& root =
- *ToLayoutSVGRoot(GetLayoutObjectByElementId("svg"));
- EXPECT_FALSE(root.PaintedOutputOfObjectHasNoEffectRegardlessOfSize());
-}
-
-TEST_F(LayoutSVGRootTest,
- PaintedOutputOfObjectHasNoEffectRegardlessOfSizeMask) {
- SetBodyInnerHTML(R"HTML(
- <svg id="svg" width="16" height="16" mask="url(#test)">
- <rect width="100%" height="16" fill="#fff"></rect>
- <defs>
- <mask id="test">
- <g>
- <rect width="100%" height="100%" fill="#ffffff" style=""></rect>
- </g>
- </mask>
- </defs>
- </svg>
- )HTML");
-
- const LayoutSVGRoot& root =
- *ToLayoutSVGRoot(GetLayoutObjectByElementId("svg"));
- EXPECT_FALSE(root.PaintedOutputOfObjectHasNoEffectRegardlessOfSize());
-}
-
TEST_F(LayoutSVGRootTest, RectBasedHitTestPartialOverlap) {
SetBodyInnerHTML(R"HTML(
<style>body { margin: 0 }</style>
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
index 6286842b095..66bff8d5bd1 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc
@@ -79,13 +79,13 @@ void LayoutSVGShape::WillBeDestroyed() {
void LayoutSVGShape::CreatePath() {
if (!path_)
path_ = std::make_unique<Path>();
- *path_ = ToSVGGeometryElement(GetElement())->AsPath();
+ *path_ = To<SVGGeometryElement>(GetElement())->AsPath();
}
float LayoutSVGShape::DashScaleFactor() const {
if (StyleRef().SvgStyle().StrokeDashArray()->data.IsEmpty())
return 1;
- return ToSVGGeometryElement(*GetElement()).PathLengthScaleFactor();
+ return To<SVGGeometryElement>(*GetElement()).PathLengthScaleFactor();
}
void LayoutSVGShape::UpdateShapeFromElement() {
@@ -229,7 +229,6 @@ void LayoutSVGShape::UpdateLayout() {
FloatRect old_object_bounding_box = ObjectBoundingBox();
UpdateShapeFromElement();
if (old_object_bounding_box != ObjectBoundingBox()) {
- GetElement()->SetNeedsResizeObserverUpdate();
SetShouldDoFullPaintInvalidation();
bbox_changed = true;
}
@@ -393,6 +392,21 @@ float LayoutSVGShape::StrokeWidth() const {
return length_context.ValueForLength(StyleRef().SvgStyle().StrokeWidth());
}
+float LayoutSVGShape::StrokeWidthForMarkerUnits() const {
+ float stroke_width = StrokeWidth();
+ if (HasNonScalingStroke()) {
+ const auto& non_scaling_transform = NonScalingStrokeTransform();
+ if (!non_scaling_transform.IsInvertible())
+ return 0;
+ float scale_factor =
+ clampTo<float>(sqrt((non_scaling_transform.XScaleSquared() +
+ non_scaling_transform.YScaleSquared()) /
+ 2));
+ stroke_width /= scale_factor;
+ }
+ return stroke_width;
+}
+
LayoutSVGShapeRareData& LayoutSVGShape::EnsureRareData() const {
if (!rare_data_)
rare_data_ = std::make_unique<LayoutSVGShapeRareData>();
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
index 1b11df34d50..803a52ec322 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h
@@ -101,6 +101,7 @@ class LayoutSVGShape : public LayoutSVGModelObject {
}
float StrokeWidth() const;
+ float StrokeWidthForMarkerUnits() const;
virtual ShapeGeometryCodePath GeometryCodePath() const {
return kPathGeometry;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
index 34c734ab14f..373e99fb652 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc
@@ -111,15 +111,8 @@ static inline void CollectDescendantTextNodes(
}
}
-void LayoutSVGText::InvalidatePositioningValues(
+void LayoutSVGText::SubtreeStructureChanged(
LayoutInvalidationReasonForTracing reason) {
- descendant_text_nodes_.clear();
- SetNeedsPositioningValuesUpdate();
- // TODO(fs): Restore the passing of |reason| here.
- LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(*this);
-}
-
-void LayoutSVGText::SubtreeChildWasAdded() {
if (BeingDestroyed() || !EverHadLayout()) {
DCHECK(descendant_text_nodes_.IsEmpty());
return;
@@ -128,37 +121,20 @@ void LayoutSVGText::SubtreeChildWasAdded() {
return;
// The positioning elements cache depends on the size of each text
- // layoutObject in the subtree. If this changes, clear the cache. It will be
+ // LayoutObject in the subtree. If this changes, clear the cache. It will be
// rebuilt on the next layout.
- InvalidatePositioningValues(layout_invalidation_reason::kChildChanged);
- SetNeedsTextMetricsUpdate();
-}
-
-void LayoutSVGText::SubtreeChildWillBeRemoved() {
- if (BeingDestroyed() || !EverHadLayout()) {
- DCHECK(descendant_text_nodes_.IsEmpty());
- return;
- }
-
- // The positioning elements cache depends on the size of each text
- // layoutObject in the subtree. If this changes, clear the cache. It will be
- // rebuilt on the next layout.
- InvalidatePositioningValues(layout_invalidation_reason::kChildChanged);
+ descendant_text_nodes_.clear();
+ SetNeedsPositioningValuesUpdate();
SetNeedsTextMetricsUpdate();
+ // TODO(fs): Restore the passing of |reason| here.
+ LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(*this);
}
-void LayoutSVGText::SubtreeTextDidChange() {
- DCHECK(!BeingDestroyed());
- if (!EverHadLayout()) {
- DCHECK(descendant_text_nodes_.IsEmpty());
- return;
- }
-
- // The positioning elements cache depends on the size of each text object in
- // the subtree. If this changes, clear the cache and mark it for rebuilding
- // in the next layout.
- InvalidatePositioningValues(layout_invalidation_reason::kTextChanged);
- SetNeedsTextMetricsUpdate();
+void LayoutSVGText::NotifySubtreeStructureChanged(
+ LayoutObject* object,
+ LayoutInvalidationReasonForTracing reason) {
+ if (LayoutSVGText* layout_text = LocateLayoutSVGTextAncestor(object))
+ layout_text->SubtreeStructureChanged(reason);
}
static inline void UpdateFontAndMetrics(LayoutSVGText& text_root) {
@@ -365,8 +341,8 @@ PositionWithAffinity LayoutSVGText::PositionForPoint(
DCHECK(!root_box->NextRootBox());
DCHECK(ChildrenInline());
- InlineBox* closest_box =
- ToSVGRootInlineBox(root_box)->ClosestLeafChildForPosition(
+ auto* closest_box =
+ To<SVGRootInlineBox>(root_box)->ClosestLeafChildForPosition(
clipped_point_in_contents);
if (!closest_box)
return CreatePositionWithAffinity(0);
@@ -391,27 +367,17 @@ FloatRect LayoutSVGText::ObjectBoundingBox() const {
}
FloatRect LayoutSVGText::StrokeBoundingBox() const {
- FloatRect stroke_boundaries = ObjectBoundingBox();
- const SVGComputedStyle& svg_style = StyleRef().SvgStyle();
- if (!svg_style.HasStroke())
- return stroke_boundaries;
-
- DCHECK(GetElement());
- SVGLengthContext length_context(GetElement());
- stroke_boundaries.Inflate(
- length_context.ValueForLength(svg_style.StrokeWidth()));
- return stroke_boundaries;
+ if (!FirstRootBox())
+ return FloatRect();
+ return SVGLayoutSupport::ExtendTextBBoxWithStroke(*this, ObjectBoundingBox());
}
FloatRect LayoutSVGText::VisualRectInLocalSVGCoordinates() const {
- FloatRect visual_rect = StrokeBoundingBox();
- SVGLayoutSupport::AdjustVisualRectWithResources(*this, ObjectBoundingBox(),
- visual_rect);
-
- if (const ShadowList* text_shadow = StyleRef().TextShadow())
- text_shadow->AdjustRectForShadow(visual_rect);
-
- return visual_rect;
+ if (!FirstRootBox())
+ return FloatRect();
+ const FloatRect object_bounds = ObjectBoundingBox();
+ return SVGLayoutSupport::ComputeVisualRectForText(*this, object_bounds,
+ object_bounds);
}
void LayoutSVGText::AddOutlineRects(Vector<PhysicalRect>& rects,
@@ -428,13 +394,13 @@ bool LayoutSVGText::IsObjectBoundingBoxValid() const {
void LayoutSVGText::AddChild(LayoutObject* child, LayoutObject* before_child) {
LayoutSVGBlock::AddChild(child, before_child);
- SVGResourcesCache::ClientWasAddedToTree(*child, child->StyleRef());
- SubtreeChildWasAdded();
+ SVGResourcesCache::ClientWasAddedToTree(*child);
+ SubtreeStructureChanged(layout_invalidation_reason::kChildChanged);
}
void LayoutSVGText::RemoveChild(LayoutObject* child) {
SVGResourcesCache::ClientWillBeRemovedFromTree(*child);
- SubtreeChildWillBeRemoved();
+ SubtreeStructureChanged(layout_invalidation_reason::kChildChanged);
LayoutSVGBlock::RemoveChild(child);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.h b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
index 2360fe04afd..c5ebeb9f698 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.h
@@ -53,15 +53,14 @@ class LayoutSVGText final : public LayoutSVGBlock {
static LayoutSVGText* LocateLayoutSVGTextAncestor(LayoutObject*);
static const LayoutSVGText* LocateLayoutSVGTextAncestor(const LayoutObject*);
+ static void NotifySubtreeStructureChanged(LayoutObject*,
+ LayoutInvalidationReasonForTracing);
+
bool NeedsReordering() const { return needs_reordering_; }
const Vector<LayoutSVGInlineText*>& DescendantTextNodes() const {
return descendant_text_nodes_;
}
- void SubtreeChildWasAdded();
- void SubtreeChildWillBeRemoved();
- void SubtreeTextDidChange();
-
void RecalcVisualOverflow() override;
const char* GetName() const override { return "LayoutSVGText"; }
@@ -94,7 +93,7 @@ class LayoutSVGText final : public LayoutSVGBlock {
RootInlineBox* CreateRootInlineBox() override;
- void InvalidatePositioningValues(LayoutInvalidationReasonForTracing);
+ void SubtreeStructureChanged(LayoutInvalidationReasonForTracing);
bool needs_reordering_ : 1;
bool needs_positioning_values_update_ : 1;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.cc
index bcf433726ee..1290e22820c 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text_path.cc
@@ -62,8 +62,7 @@ bool LayoutSVGTextPath::IsChildAllowed(LayoutObject* child,
std::unique_ptr<PathPositionMapper> LayoutSVGTextPath::LayoutPath() const {
const auto& text_path_element = To<SVGTextPathElement>(*GetNode());
Element* target_element = SVGURIReference::TargetElementFromIRIString(
- text_path_element.HrefString(),
- text_path_element.TreeScopeForIdResolution());
+ text_path_element.HrefString(), text_path_element.OriginatingTreeScope());
const auto* path_element = DynamicTo<SVGPathElement>(target_element);
if (!path_element)
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_flow_box.h b/chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_flow_box.h
index b4a32b6a14b..d62be330937 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_flow_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_flow_box.h
@@ -22,6 +22,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LINE_SVG_INLINE_FLOW_BOX_H_
#include "third_party/blink/renderer/core/layout/line/inline_flow_box.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -42,7 +43,12 @@ class SVGInlineFlowBox final : public InlineFlowBox {
LayoutUnit logical_height_;
};
-DEFINE_INLINE_BOX_TYPE_CASTS(SVGInlineFlowBox);
+template <>
+struct DowncastTraits<SVGInlineFlowBox> {
+ static bool AllowFrom(const InlineBox& box) {
+ return box.IsSVGInlineFlowBox();
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h b/chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h
index 3ce95efaac1..6c19bd6f4ba 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/line/svg_inline_text_box.h
@@ -109,7 +109,12 @@ class SVGInlineTextBox final : public InlineTextBox {
Vector<SVGTextFragment> text_fragments_;
};
-DEFINE_INLINE_BOX_TYPE_CASTS(SVGInlineTextBox);
+template <>
+struct DowncastTraits<SVGInlineTextBox> {
+ static bool AllowFrom(const InlineBox& box) {
+ return box.IsSVGInlineTextBox();
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.cc b/chromium/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.cc
index 240be07bf5c..cf3fffe5517 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.cc
@@ -86,8 +86,8 @@ void SVGRootInlineBox::ComputePerCharacterLayoutInformation() {
FloatRect SVGRootInlineBox::LayoutInlineBoxes(InlineBox& box) {
FloatRect rect;
- if (box.IsSVGInlineTextBox()) {
- rect = ToSVGInlineTextBox(box).CalculateBoundaries();
+ if (auto* svg_inline_text_box = DynamicTo<SVGInlineTextBox>(box)) {
+ rect = svg_inline_text_box->CalculateBoundaries();
} else {
for (InlineBox* child = ToInlineFlowBox(box).FirstChild(); child;
child = child->NextOnLine())
@@ -101,12 +101,12 @@ FloatRect SVGRootInlineBox::LayoutInlineBoxes(InlineBox& box) {
box.SetX(logical_rect.X());
box.SetY(logical_rect.Y());
box.SetLogicalWidth(logical_rect.Width());
- if (box.IsSVGInlineTextBox())
- ToSVGInlineTextBox(box).SetLogicalHeight(logical_rect.Height());
- else if (box.IsSVGInlineFlowBox())
- ToSVGInlineFlowBox(box).SetLogicalHeight(logical_rect.Height());
+ if (auto* svg_inline_text_box = DynamicTo<SVGInlineTextBox>(box))
+ svg_inline_text_box->SetLogicalHeight(logical_rect.Height());
+ else if (auto* svg_inline_flow_box = DynamicTo<SVGInlineFlowBox>(box))
+ svg_inline_flow_box->SetLogicalHeight(logical_rect.Height());
else
- ToSVGRootInlineBox(box).SetLogicalHeight(logical_rect.Height());
+ To<SVGRootInlineBox>(box).SetLogicalHeight(logical_rect.Height());
return rect;
}
@@ -170,10 +170,9 @@ static inline void ReverseInlineBoxRangeAndValueListsIfNeeded(
if (first == last || first == --last)
return;
- if ((*last)->IsSVGInlineTextBox() && (*first)->IsSVGInlineTextBox()) {
- SVGInlineTextBox* first_text_box = ToSVGInlineTextBox(*first);
- SVGInlineTextBox* last_text_box = ToSVGInlineTextBox(*last);
-
+ auto* first_text_box = DynamicTo<SVGInlineTextBox>(*first);
+ auto* last_text_box = DynamicTo<SVGInlineTextBox>(*last);
+ if (last_text_box && first_text_box) {
// Reordering is only necessary for BiDi text that is _absolutely_
// positioned.
if (first_text_box->Len() == 1 &&
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h b/chromium/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h
index 8f741b84c92..3fc347d75a5 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h
@@ -24,6 +24,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_LINE_SVG_ROOT_INLINE_BOX_H_
#include "third_party/blink/renderer/core/layout/line/root_inline_box.h"
+#include "third_party/blink/renderer/platform/wtf/casting.h"
namespace blink {
@@ -60,7 +61,12 @@ class SVGRootInlineBox final : public RootInlineBox {
LayoutUnit logical_height_;
};
-DEFINE_INLINE_BOX_TYPE_CASTS(SVGRootInlineBox);
+template <>
+struct DowncastTraits<SVGRootInlineBox> {
+ static bool AllowFrom(const InlineBox& box) {
+ return box.IsSVGRootInlineBox();
+ }
+};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
index 40000a9c319..14eabbb2fcc 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc
@@ -210,10 +210,9 @@ inline void SVGLayoutSupport::UpdateObjectBoundingBox(
bool& object_bounding_box_valid,
LayoutObject* other,
FloatRect other_bounding_box) {
+ auto* svg_container = DynamicTo<LayoutSVGContainer>(other);
bool other_valid =
- other->IsSVGContainer()
- ? ToLayoutSVGContainer(other)->IsObjectBoundingBoxValid()
- : true;
+ svg_container ? svg_container->IsObjectBoundingBoxValid() : true;
if (!other_valid)
return;
@@ -236,8 +235,8 @@ static bool HasValidBoundingBoxForContainer(const LayoutObject* object) {
if (object->IsSVGHiddenContainer())
return false;
- if (object->IsSVGForeignObject())
- return ToLayoutSVGForeignObject(object)->IsObjectBoundingBoxValid();
+ if (auto* foreign_object = DynamicTo<LayoutSVGForeignObject>(object))
+ return foreign_object->IsObjectBoundingBoxValid();
if (object->IsSVGImage())
return ToLayoutSVGImage(object)->IsObjectBoundingBoxValid();
@@ -409,6 +408,34 @@ void SVGLayoutSupport::AdjustVisualRectWithResources(
visual_rect.Intersect(masker->ResourceBoundingBox(object_bounding_box));
}
+FloatRect SVGLayoutSupport::ExtendTextBBoxWithStroke(
+ const LayoutObject& layout_object,
+ const FloatRect& text_bounds) {
+ DCHECK(layout_object.IsSVGText() || layout_object.IsSVGInline());
+ FloatRect bounds = text_bounds;
+ const SVGComputedStyle& svg_style = layout_object.StyleRef().SvgStyle();
+ if (svg_style.HasStroke()) {
+ SVGLengthContext length_context(To<SVGElement>(layout_object.GetNode()));
+ // TODO(fs): This approximation doesn't appear to be conservative enough
+ // since while text (usually?) won't have caps it could have joins and thus
+ // miters.
+ bounds.Inflate(length_context.ValueForLength(svg_style.StrokeWidth()));
+ }
+ return bounds;
+}
+
+FloatRect SVGLayoutSupport::ComputeVisualRectForText(
+ const LayoutObject& layout_object,
+ const FloatRect& text_bounds,
+ const FloatRect& reference_box) {
+ DCHECK(layout_object.IsSVGText() || layout_object.IsSVGInline());
+ FloatRect visual_rect = ExtendTextBBoxWithStroke(layout_object, text_bounds);
+ if (const ShadowList* text_shadow = layout_object.StyleRef().TextShadow())
+ text_shadow->AdjustRectForShadow(visual_rect);
+ AdjustVisualRectWithResources(layout_object, reference_box, visual_rect);
+ return visual_rect;
+}
+
bool SVGLayoutSupport::HasFilterResource(const LayoutObject& object) {
SVGResources* resources =
SVGResourcesCache::CachedResourcesForLayoutObject(object);
@@ -442,8 +469,8 @@ bool SVGLayoutSupport::HitTestChildren(LayoutObject* last_child,
HitTestAction hit_test_action) {
for (LayoutObject* child = last_child; child;
child = child->PreviousSibling()) {
- if (child->IsSVGForeignObject()) {
- if (ToLayoutSVGForeignObject(child)->NodeAtPointFromSVG(
+ if (auto* foreign_object = DynamicTo<LayoutSVGForeignObject>(child)) {
+ if (foreign_object->NodeAtPointFromSVG(
result, location, accumulated_offset, hit_test_action))
return true;
} else {
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
index 92b33e48eb6..214bf35707b 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.h
@@ -68,6 +68,15 @@ class CORE_EXPORT SVGLayoutSupport {
const FloatRect& object_bounding_box,
FloatRect&);
+ // Add any contribution from 'stroke' to a text content bounding rect.
+ static FloatRect ExtendTextBBoxWithStroke(const LayoutObject&,
+ const FloatRect& text_bounds);
+
+ // Compute the visual rect for the a text content LayoutObject.
+ static FloatRect ComputeVisualRectForText(const LayoutObject&,
+ const FloatRect& text_bounds,
+ const FloatRect& reference_box);
+
// Determine if the LayoutObject references a filter resource object.
static bool HasFilterResource(const LayoutObject&);
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
index 9c5236a6c29..214b062de87 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc
@@ -383,12 +383,10 @@ static WTF::TextStream& operator<<(WTF::TextStream& ts,
WriteNameValuePair(ts, "r",
length_context.ValueForLength(svg_style.R(), style,
SVGLengthMode::kOther));
- } else if (IsSVGPolyElement(*svg_element)) {
- WriteNameAndQuotedValue(ts, "points",
- ToSVGPolyElement(*svg_element)
- .Points()
- ->CurrentValue()
- ->ValueAsString());
+ } else if (auto* svg_poly_element = DynamicTo<SVGPolyElement>(svg_element)) {
+ WriteNameAndQuotedValue(
+ ts, "points",
+ svg_poly_element->Points()->CurrentValue()->ValueAsString());
} else if (IsA<SVGPathElement>(*svg_element)) {
const StylePath& path =
svg_style.D() ? *svg_style.D() : *StylePath::EmptyPath();
@@ -410,7 +408,7 @@ static WTF::TextStream& operator<<(WTF::TextStream& ts,
static void WriteLayoutSVGTextBox(WTF::TextStream& ts,
const LayoutSVGText& text) {
- SVGRootInlineBox* box = ToSVGRootInlineBox(text.FirstRootBox());
+ auto* box = To<SVGRootInlineBox>(text.FirstRootBox());
if (!box)
return;
@@ -495,10 +493,11 @@ static inline void WriteSVGInlineTextBoxes(WTF::TextStream& ts,
const LayoutText& text,
int indent) {
for (InlineTextBox* box : text.TextBoxes()) {
- if (!box->IsSVGInlineTextBox())
+ auto* svg_inline_text_box = DynamicTo<SVGInlineTextBox>(box);
+ if (!svg_inline_text_box)
continue;
- WriteSVGInlineTextBox(ts, ToSVGInlineTextBox(box), indent);
+ WriteSVGInlineTextBox(ts, svg_inline_text_box, indent);
}
}
@@ -648,9 +647,6 @@ void WriteSVGResourceContainer(WTF::TextStream& ts,
void WriteSVGContainer(WTF::TextStream& ts,
const LayoutObject& container,
int indent) {
- // Currently LayoutSVGResourceFilterPrimitive has no meaningful output.
- if (container.IsSVGResourceFilterPrimitive())
- return;
WriteStandardPrefix(ts, container, indent);
WritePositionAndStyle(ts, container);
ts << "\n";
@@ -741,7 +737,7 @@ void WriteResources(WTF::TextStream& ts,
WriteStandardPrefix(ts, *clipper, 0);
ts << " " << clipper->ResourceBoundingBox(reference_box) << "\n";
}
- if (LayoutSVGResourceFilter* filter = resources->Filter()) {
+ if (LayoutSVGResourceFilter* filter = GetFilterResourceForSVG(style)) {
DCHECK(style.HasFilter());
DCHECK_EQ(style.Filter().size(), 1u);
const FilterOperation& filter_operation = *style.Filter().at(0);
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_marker_data.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_marker_data.cc
index 0892cd34cfd..3673515b7c9 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_marker_data.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_marker_data.cc
@@ -19,6 +19,9 @@
#include "third_party/blink/renderer/core/layout/svg/svg_marker_data.h"
+#include "base/auto_reset.h"
+#include "third_party/blink/renderer/core/svg/svg_path_byte_stream_source.h"
+#include "third_party/blink/renderer/core/svg/svg_path_parser.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
@@ -32,12 +35,7 @@ static double BisectingAngle(double in_angle, double out_angle) {
void SVGMarkerDataBuilder::Build(const Path& path) {
path.Apply(this, SVGMarkerDataBuilder::UpdateFromPathElement);
- if (positions_.IsEmpty())
- return;
- const bool kEndsSubpath = true;
- UpdateAngle(kEndsSubpath);
- // Mark the last marker as 'end'.
- positions_.back().type = kEndMarker;
+ Flush();
}
void SVGMarkerDataBuilder::UpdateFromPathElement(void* info,
@@ -45,6 +43,109 @@ void SVGMarkerDataBuilder::UpdateFromPathElement(void* info,
static_cast<SVGMarkerDataBuilder*>(info)->UpdateFromPathElement(*element);
}
+namespace {
+
+// Path processor that converts an arc segment to a cubic segment with
+// equivalent start/end tangents.
+class MarkerPathSegmentProcessor : public SVGPathNormalizer {
+ STACK_ALLOCATED();
+
+ public:
+ MarkerPathSegmentProcessor(SVGPathConsumer* consumer)
+ : SVGPathNormalizer(consumer) {}
+
+ void EmitSegment(const PathSegmentData&);
+
+ private:
+ Vector<PathSegmentData> DecomposeArc(const PathSegmentData&);
+};
+
+Vector<PathSegmentData> MarkerPathSegmentProcessor::DecomposeArc(
+ const PathSegmentData& segment) {
+ class SegmentCollector : public SVGPathConsumer {
+ STACK_ALLOCATED();
+
+ public:
+ void EmitSegment(const PathSegmentData& segment) override {
+ DCHECK_EQ(segment.command, kPathSegCurveToCubicAbs);
+ segments_.push_back(segment);
+ }
+ Vector<PathSegmentData> ReturnSegments() { return std::move(segments_); }
+
+ private:
+ Vector<PathSegmentData> segments_;
+ } collector;
+ // Temporarily switch to our "collector" to collect the curve segments
+ // emitted by DecomposeArcToCubic(), and then switch back to the actual
+ // consumer.
+ base::AutoReset<SVGPathConsumer*> consumer_scope(&consumer_, &collector);
+ DecomposeArcToCubic(current_point_, segment);
+ return collector.ReturnSegments();
+}
+
+void MarkerPathSegmentProcessor::EmitSegment(
+ const PathSegmentData& original_segment) {
+ PathSegmentData segment = original_segment;
+ // Convert a relative arc to absolute.
+ if (segment.command == kPathSegArcRel) {
+ segment.command = kPathSegArcAbs;
+ segment.target_point += current_point_;
+ }
+ if (segment.command == kPathSegArcAbs) {
+ // Decompose and then pass/emit a synthesized cubic with matching tangents.
+ Vector<PathSegmentData> decomposed_arc_curves = DecomposeArc(segment);
+ if (decomposed_arc_curves.IsEmpty()) {
+ segment.command = kPathSegLineToAbs;
+ } else {
+ // Use the first control point from the first curve and the second and
+ // last control points from the last curve. (If the decomposition only
+ // has one curve then the second line just copies the same point again.)
+ segment = decomposed_arc_curves.back();
+ segment.point1 = decomposed_arc_curves[0].point1;
+ }
+ }
+ // Invoke the base class to normalize and emit to the consumer
+ // (SVGMarkerDataBuilder).
+ SVGPathNormalizer::EmitSegment(segment);
+}
+
+} // namespace
+
+void SVGMarkerDataBuilder::Build(const SVGPathByteStream& stream) {
+ SVGPathByteStreamSource source(stream);
+ MarkerPathSegmentProcessor processor(this);
+ svg_path_parser::ParsePath(source, processor);
+ Flush();
+}
+
+void SVGMarkerDataBuilder::EmitSegment(const PathSegmentData& segment) {
+ PathElement element;
+ FloatPoint points[3];
+ element.points = points;
+ switch (segment.command) {
+ case kPathSegClosePath:
+ element.type = kPathElementCloseSubpath;
+ break;
+ case kPathSegMoveToAbs:
+ element.type = kPathElementMoveToPoint;
+ element.points[0] = segment.target_point;
+ break;
+ case kPathSegLineToAbs:
+ element.type = kPathElementAddLineToPoint;
+ element.points[0] = segment.target_point;
+ break;
+ case kPathSegCurveToCubicAbs:
+ element.type = kPathElementAddCurveToPoint;
+ element.points[0] = segment.point1;
+ element.points[1] = segment.point2;
+ element.points[2] = segment.target_point;
+ break;
+ default:
+ NOTREACHED();
+ }
+ UpdateFromPathElement(element);
+}
+
double SVGMarkerDataBuilder::CurrentAngle(AngleType type) const {
// For details of this calculation, see:
// http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement
@@ -176,4 +277,13 @@ void SVGMarkerDataBuilder::UpdateFromPathElement(const PathElement& element) {
positions_.push_back(MarkerPosition(marker_type, origin_, 0));
}
+void SVGMarkerDataBuilder::Flush() {
+ if (positions_.IsEmpty())
+ return;
+ const bool kEndsSubpath = true;
+ UpdateAngle(kEndsSubpath);
+ // Mark the last marker as 'end'.
+ positions_.back().type = kEndMarker;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_marker_data.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_marker_data.h
index adbda9ab99c..40d150d0bff 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_marker_data.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_marker_data.h
@@ -20,6 +20,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_MARKER_DATA_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_MARKER_DATA_H_
+#include "third_party/blink/renderer/core/svg/svg_path_consumer.h"
#include "third_party/blink/renderer/platform/graphics/path.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
@@ -29,6 +30,7 @@ namespace blink {
enum SVGMarkerType { kStartMarker, kMidMarker, kEndMarker };
class LayoutSVGResourceMarker;
+class SVGPathByteStream;
struct MarkerPosition {
DISALLOW_NEW();
@@ -58,7 +60,7 @@ struct MarkerPosition {
float angle;
};
-class SVGMarkerDataBuilder {
+class SVGMarkerDataBuilder : private SVGPathConsumer {
STACK_ALLOCATED();
public:
@@ -67,9 +69,21 @@ class SVGMarkerDataBuilder {
last_moveto_index_(0),
last_element_type_(kPathElementMoveToPoint) {}
+ // Build marker data for a Path.
void Build(const Path&);
+ // Build marker data for a SVGPathByteStream.
+ //
+ // A SVGPathByteStream is semantically higher-level than a Path, and thus
+ // this allows those higher-level constructs (for example arcs) to be handled
+ // correctly. This should be used in cases where the original path data can
+ // contain such higher-level constructs.
+ void Build(const SVGPathByteStream&);
+
private:
+ // SVGPathConsumer
+ void EmitSegment(const PathSegmentData&) override;
+
static void UpdateFromPathElement(void* info, const PathElement*);
enum AngleType {
@@ -95,6 +109,7 @@ class SVGMarkerDataBuilder {
const FloatPoint& end);
SegmentData ExtractPathElementFeatures(const PathElement&) const;
void UpdateFromPathElement(const PathElement&);
+ void Flush();
Vector<MarkerPosition>& positions_;
unsigned last_moveto_index_;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc
index 1ff19413ab7..4d1cc23961b 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc
@@ -27,15 +27,22 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_masker.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/reference_clip_path_operation.h"
#include "third_party/blink/renderer/core/style/style_svg_resource.h"
+#include "third_party/blink/renderer/core/svg/graphics/filters/svg_filter_builder.h"
+#include "third_party/blink/renderer/core/svg/svg_filter_primitive_standard_attributes.h"
#include "third_party/blink/renderer/core/svg/svg_pattern_element.h"
#include "third_party/blink/renderer/core/svg/svg_resource.h"
#include "third_party/blink/renderer/core/svg/svg_tree_scope_resources.h"
#include "third_party/blink/renderer/core/svg/svg_uri_reference.h"
#include "third_party/blink/renderer/core/svg_names.h"
+#include "third_party/blink/renderer/platform/graphics/filters/filter.h"
+#include "third_party/blink/renderer/platform/graphics/filters/filter_effect.h"
+#include "third_party/blink/renderer/platform/graphics/filters/paint_filter_builder.h"
+#include "third_party/blink/renderer/platform/graphics/filters/source_graphic.h"
#if DCHECK_IS_ON()
#include <stdio.h>
@@ -45,10 +52,32 @@ namespace blink {
SVGResources::SVGResources() : linked_resource_(nullptr) {}
-SVGResourceClient* SVGResources::GetClient(const LayoutObject& object) {
+SVGElementResourceClient* SVGResources::GetClient(const LayoutObject& object) {
return To<SVGElement>(object.GetNode())->GetSVGResourceClient();
}
+FloatRect SVGResources::ReferenceBoxForEffects(
+ const LayoutObject& layout_object) {
+ // For SVG foreign objects, remove the position part of the bounding box. The
+ // position is already baked into the transform, and we don't want to re-apply
+ // the offset when, e.g., using "objectBoundingBox" for clipPathUnits.
+ if (layout_object.IsSVGForeignObject()) {
+ FloatRect rect = layout_object.ObjectBoundingBox();
+ return FloatRect(FloatPoint::Zero(), rect.Size());
+ }
+
+ // Text "sub-elements" (<tspan>, <textpath>, <a>) should use the entire
+ // <text>s object bounding box rather then their own.
+ // https://svgwg.org/svg2-draft/text.html#ObjectBoundingBoxUnitsTextObjects
+ const LayoutObject* obb_layout_object = &layout_object;
+ if (layout_object.IsSVGInline()) {
+ obb_layout_object =
+ LayoutSVGText::LocateLayoutSVGTextAncestor(&layout_object);
+ }
+ DCHECK(obb_layout_object);
+ return obb_layout_object->ObjectBoundingBox();
+}
+
static HashSet<AtomicString>& ClipperFilterMaskerTags() {
DEFINE_STATIC_LOCAL(
HashSet<AtomicString>, tag_list,
@@ -115,37 +144,6 @@ static HashSet<AtomicString>& FillAndStrokeTags() {
return tag_list;
}
-namespace {
-
-template <typename ContainerType>
-bool IsResourceOfType(LayoutSVGResourceContainer* container) {
- return container->ResourceType() == ContainerType::kResourceType;
-}
-
-template <>
-bool IsResourceOfType<LayoutSVGResourcePaintServer>(
- LayoutSVGResourceContainer* container) {
- return container->IsSVGPaintServer();
-}
-
-template <typename ContainerType>
-ContainerType* CastResource(SVGResource* resource) {
- if (!resource)
- return nullptr;
- if (LayoutSVGResourceContainer* container = resource->ResourceContainer()) {
- if (IsResourceOfType<ContainerType>(container))
- return static_cast<ContainerType*>(container);
- }
- return nullptr;
-}
-
-template <typename ContainerType>
-ContainerType* CastResource(StyleSVGResource& style_resource) {
- return CastResource<ContainerType>(style_resource.Resource());
-}
-
-} // namespace
-
bool SVGResources::HasResourceData() const {
return clipper_filter_masker_data_ || marker_data_ || fill_stroke_data_ ||
linked_resource_;
@@ -176,59 +174,51 @@ std::unique_ptr<SVGResources> SVGResources::BuildResources(
std::unique_ptr<SVGResources> resources;
if (ClipperFilterMaskerTags().Contains(tag_name)) {
if (computed_style.ClipPath() && !object.IsSVGRoot()) {
- ClipPathOperation* clip_path_operation = computed_style.ClipPath();
- if (clip_path_operation->GetType() == ClipPathOperation::REFERENCE) {
- const ReferenceClipPathOperation& clip_path_reference =
- To<ReferenceClipPathOperation>(*clip_path_operation);
- EnsureResources(resources).SetClipper(
- CastResource<LayoutSVGResourceClipper>(
- clip_path_reference.Resource()));
+ if (LayoutSVGResourceClipper* clipper =
+ GetSVGResourceAsType(computed_style.ClipPath())) {
+ EnsureResources(resources).SetClipper(clipper);
}
}
if (computed_style.HasFilter() && !object.IsSVGRoot()) {
- const FilterOperations& filter_operations = computed_style.Filter();
- if (filter_operations.size() == 1) {
- const FilterOperation& filter_operation = *filter_operations.at(0);
- if (const auto* reference_filter_operation =
- DynamicTo<ReferenceFilterOperation>(filter_operation)) {
- EnsureResources(resources).SetFilter(
- CastResource<LayoutSVGResourceFilter>(
- reference_filter_operation->Resource()));
- }
+ if (LayoutSVGResourceFilter* filter =
+ GetFilterResourceForSVG(computed_style)) {
+ EnsureResources(resources).SetFilter(filter);
}
}
- if (StyleSVGResource* masker_resource = style.MaskerResource()) {
- EnsureResources(resources).SetMasker(
- CastResource<LayoutSVGResourceMasker>(*masker_resource));
+ if (auto* masker = GetSVGResourceAsType<LayoutSVGResourceMasker>(
+ style.MaskerResource())) {
+ EnsureResources(resources).SetMasker(masker);
}
}
if (style.HasMarkers() && SupportsMarkers(element)) {
- if (StyleSVGResource* marker_start_resource = style.MarkerStartResource()) {
- EnsureResources(resources).SetMarkerStart(
- CastResource<LayoutSVGResourceMarker>(*marker_start_resource));
+ if (auto* marker = GetSVGResourceAsType<LayoutSVGResourceMarker>(
+ style.MarkerStartResource())) {
+ EnsureResources(resources).SetMarkerStart(marker);
}
- if (StyleSVGResource* marker_mid_resource = style.MarkerMidResource()) {
- EnsureResources(resources).SetMarkerMid(
- CastResource<LayoutSVGResourceMarker>(*marker_mid_resource));
+ if (auto* marker = GetSVGResourceAsType<LayoutSVGResourceMarker>(
+ style.MarkerMidResource())) {
+ EnsureResources(resources).SetMarkerMid(marker);
}
- if (StyleSVGResource* marker_end_resource = style.MarkerEndResource()) {
- EnsureResources(resources).SetMarkerEnd(
- CastResource<LayoutSVGResourceMarker>(*marker_end_resource));
+ if (auto* marker = GetSVGResourceAsType<LayoutSVGResourceMarker>(
+ style.MarkerEndResource())) {
+ EnsureResources(resources).SetMarkerEnd(marker);
}
}
if (FillAndStrokeTags().Contains(tag_name)) {
- if (StyleSVGResource* fill_resource = style.FillPaint().Resource()) {
- EnsureResources(resources).SetFill(
- CastResource<LayoutSVGResourcePaintServer>(*fill_resource));
+ if (auto* paint_resource =
+ GetSVGResourceAsType<LayoutSVGResourcePaintServer>(
+ style.FillPaint().Resource())) {
+ EnsureResources(resources).SetFill(paint_resource);
}
- if (StyleSVGResource* stroke_resource = style.StrokePaint().Resource()) {
- EnsureResources(resources).SetStroke(
- CastResource<LayoutSVGResourcePaintServer>(*stroke_resource));
+ if (auto* paint_resource =
+ GetSVGResourceAsType<LayoutSVGResourcePaintServer>(
+ style.StrokePaint().Resource())) {
+ EnsureResources(resources).SetStroke(paint_resource);
}
}
@@ -277,41 +267,28 @@ void SVGResources::LayoutIfNeeded() {
linked_resource_->LayoutIfNeeded();
}
-InvalidationModeMask SVGResources::RemoveClientFromCacheAffectingObjectBounds(
- SVGResourceClient& client) const {
- if (!clipper_filter_masker_data_)
- return 0;
- InvalidationModeMask invalidation_flags = 0;
- if (LayoutSVGResourceClipper* clipper = clipper_filter_masker_data_->clipper)
- clipper->RemoveClientFromCache(client);
- if (LayoutSVGResourceFilter* filter = clipper_filter_masker_data_->filter) {
- if (filter->RemoveClientFromCache(client))
- invalidation_flags |= SVGResourceClient::kPaintInvalidation;
- }
- if (LayoutSVGResourceMasker* masker = clipper_filter_masker_data_->masker)
- masker->RemoveClientFromCache(client);
- return invalidation_flags | SVGResourceClient::kBoundariesInvalidation;
+bool SVGResources::DifferenceNeedsLayout(const SVGResources* a,
+ const SVGResources* b) {
+ bool a_has_bounds_affecting_resource = a && a->clipper_filter_masker_data_;
+ bool b_has_bounds_affecting_resource = b && b->clipper_filter_masker_data_;
+ if (a_has_bounds_affecting_resource != b_has_bounds_affecting_resource)
+ return true;
+ if (!a_has_bounds_affecting_resource)
+ return false;
+ return a->Clipper() != b->Clipper() || a->Filter() != b->Filter() ||
+ a->Masker() != b->Masker();
}
-InvalidationModeMask SVGResources::RemoveClientFromCache(
- SVGResourceClient& client) const {
- if (!HasResourceData())
+InvalidationModeMask SVGResources::RemoveClientFromCacheAffectingObjectBounds(
+ SVGElementResourceClient& client) const {
+ if (!clipper_filter_masker_data_)
return 0;
-
- // We never call this method for the elements where this would be non-null.
- DCHECK(!linked_resource_);
-
InvalidationModeMask invalidation_flags =
- RemoveClientFromCacheAffectingObjectBounds(client);
-
- if (fill_stroke_data_) {
- if (LayoutSVGResourcePaintServer* fill = fill_stroke_data_->fill)
- fill->RemoveClientFromCache(client);
- if (LayoutSVGResourcePaintServer* stroke = fill_stroke_data_->stroke)
- stroke->RemoveClientFromCache(client);
- invalidation_flags |= SVGResourceClient::kPaintInvalidation;
+ SVGResourceClient::kBoundariesInvalidation;
+ if (clipper_filter_masker_data_->filter) {
+ if (client.ClearFilterData())
+ invalidation_flags |= SVGResourceClient::kPaintInvalidation;
}
-
return invalidation_flags;
}
@@ -465,9 +442,7 @@ void SVGResources::BuildSetOfResources(
}
void SVGResources::SetClipper(LayoutSVGResourceClipper* clipper) {
- if (!clipper)
- return;
-
+ DCHECK(clipper);
DCHECK_EQ(clipper->ResourceType(), kClipperResourceType);
if (!clipper_filter_masker_data_)
@@ -477,9 +452,7 @@ void SVGResources::SetClipper(LayoutSVGResourceClipper* clipper) {
}
void SVGResources::SetFilter(LayoutSVGResourceFilter* filter) {
- if (!filter)
- return;
-
+ DCHECK(filter);
DCHECK_EQ(filter->ResourceType(), kFilterResourceType);
if (!clipper_filter_masker_data_)
@@ -489,9 +462,7 @@ void SVGResources::SetFilter(LayoutSVGResourceFilter* filter) {
}
void SVGResources::SetMarkerStart(LayoutSVGResourceMarker* marker_start) {
- if (!marker_start)
- return;
-
+ DCHECK(marker_start);
DCHECK_EQ(marker_start->ResourceType(), kMarkerResourceType);
if (!marker_data_)
@@ -501,9 +472,7 @@ void SVGResources::SetMarkerStart(LayoutSVGResourceMarker* marker_start) {
}
void SVGResources::SetMarkerMid(LayoutSVGResourceMarker* marker_mid) {
- if (!marker_mid)
- return;
-
+ DCHECK(marker_mid);
DCHECK_EQ(marker_mid->ResourceType(), kMarkerResourceType);
if (!marker_data_)
@@ -513,9 +482,7 @@ void SVGResources::SetMarkerMid(LayoutSVGResourceMarker* marker_mid) {
}
void SVGResources::SetMarkerEnd(LayoutSVGResourceMarker* marker_end) {
- if (!marker_end)
- return;
-
+ DCHECK(marker_end);
DCHECK_EQ(marker_end->ResourceType(), kMarkerResourceType);
if (!marker_data_)
@@ -525,9 +492,7 @@ void SVGResources::SetMarkerEnd(LayoutSVGResourceMarker* marker_end) {
}
void SVGResources::SetMasker(LayoutSVGResourceMasker* masker) {
- if (!masker)
- return;
-
+ DCHECK(masker);
DCHECK_EQ(masker->ResourceType(), kMaskerResourceType);
if (!clipper_filter_masker_data_)
@@ -537,8 +502,7 @@ void SVGResources::SetMasker(LayoutSVGResourceMasker* masker) {
}
void SVGResources::SetFill(LayoutSVGResourcePaintServer* fill) {
- if (!fill)
- return;
+ DCHECK(fill);
if (!fill_stroke_data_)
fill_stroke_data_ = std::make_unique<FillStrokeData>();
@@ -547,8 +511,7 @@ void SVGResources::SetFill(LayoutSVGResourcePaintServer* fill) {
}
void SVGResources::SetStroke(LayoutSVGResourcePaintServer* stroke) {
- if (!stroke)
- return;
+ DCHECK(stroke);
if (!fill_stroke_data_)
fill_stroke_data_ = std::make_unique<FillStrokeData>();
@@ -705,6 +668,83 @@ void SVGResources::ClearMarkers(SVGElement& element,
marker_resource->RemoveClient(*client);
}
+bool FilterData::UpdateStateOnFinish() {
+ switch (state_) {
+ // A cycle can occur when an FeImage references a source that
+ // makes use of the FeImage itself. This is the first place we
+ // would hit the cycle so we reset the state and continue.
+ case kGeneratingFilterCycleDetected:
+ state_ = kGeneratingFilter;
+ return false;
+ case kRecordingContentCycleDetected:
+ state_ = kRecordingContent;
+ return false;
+ default:
+ return true;
+ }
+}
+
+void FilterData::UpdateStateOnPrepare() {
+ switch (state_) {
+ case kGeneratingFilter:
+ state_ = kGeneratingFilterCycleDetected;
+ break;
+ case kRecordingContent:
+ state_ = kRecordingContentCycleDetected;
+ break;
+ default:
+ break;
+ }
+}
+
+void FilterData::UpdateContent(sk_sp<PaintRecord> content) {
+ DCHECK_EQ(state_, kRecordingContent);
+ Filter* filter = last_effect_->GetFilter();
+ FloatRect bounds = filter->FilterRegion();
+ DCHECK(filter->GetSourceGraphic());
+ paint_filter_builder::BuildSourceGraphic(filter->GetSourceGraphic(),
+ std::move(content), bounds);
+ state_ = kReadyToPaint;
+}
+
+sk_sp<PaintFilter> FilterData::CreateFilter() {
+ DCHECK_EQ(state_, kReadyToPaint);
+ state_ = kGeneratingFilter;
+ sk_sp<PaintFilter> image_filter =
+ paint_filter_builder::Build(last_effect_, kInterpolationSpaceSRGB);
+ state_ = kReadyToPaint;
+ return image_filter;
+}
+
+FloatRect FilterData::MapRect(const FloatRect& input_rect) const {
+ DCHECK_EQ(state_, kReadyToPaint);
+ return last_effect_->MapRect(input_rect);
+}
+
+bool FilterData::Invalidate(SVGFilterPrimitiveStandardAttributes& primitive,
+ const QualifiedName& attribute) {
+ if (state_ != kReadyToPaint)
+ return true;
+ if (FilterEffect* effect = node_map_->EffectForElement(primitive)) {
+ if (!primitive.SetFilterEffectAttribute(effect, attribute))
+ return false; // No change
+ node_map_->InvalidateDependentEffects(effect);
+ }
+ return true;
+}
+
+void FilterData::Trace(Visitor* visitor) {
+ visitor->Trace(last_effect_);
+ visitor->Trace(node_map_);
+}
+
+void FilterData::Dispose() {
+ node_map_ = nullptr;
+ if (last_effect_)
+ last_effect_->DisposeImageFiltersRecursive();
+ last_effect_ = nullptr;
+}
+
SVGElementResourceClient::SVGElementResourceClient(SVGElement* element)
: element_(element) {}
@@ -713,22 +753,15 @@ void SVGElementResourceClient::ResourceContentChanged(
LayoutObject* layout_object = element_->GetLayoutObject();
if (!layout_object)
return;
- bool mark_for_invalidation =
- invalidation_mask & ~SVGResourceClient::kParentOnlyInvalidation;
if (layout_object->IsSVGResourceContainer()) {
- ToLayoutSVGResourceContainer(layout_object)
- ->RemoveAllClientsFromCache(mark_for_invalidation);
+ ToLayoutSVGResourceContainer(layout_object)->RemoveAllClientsFromCache();
return;
}
- if (mark_for_invalidation) {
- LayoutSVGResourceContainer::MarkClientForInvalidation(*layout_object,
- invalidation_mask);
- }
+ LayoutSVGResourceContainer::MarkClientForInvalidation(*layout_object,
+ invalidation_mask);
- // Special case for filter invalidation.
- if (invalidation_mask & SVGResourceClient::kSkipAncestorInvalidation)
- return;
+ ClearFilterData();
bool needs_layout =
invalidation_mask & SVGResourceClient::kLayoutInvalidation;
@@ -737,8 +770,10 @@ void SVGElementResourceClient::ResourceContentChanged(
}
void SVGElementResourceClient::ResourceElementChanged() {
- if (LayoutObject* layout_object = element_->GetLayoutObject())
+ if (LayoutObject* layout_object = element_->GetLayoutObject()) {
+ ClearFilterData();
SVGResourcesCache::ResourceReferenceChanged(*layout_object);
+ }
}
void SVGElementResourceClient::ResourceDestroyed(
@@ -752,8 +787,32 @@ void SVGElementResourceClient::ResourceDestroyed(
resources->ResourceDestroyed(resource);
}
+void SVGElementResourceClient::FilterPrimitiveChanged(
+ SVGFilterPrimitiveStandardAttributes& primitive,
+ const QualifiedName& attribute) {
+ if (filter_data_ && !filter_data_->Invalidate(primitive, attribute))
+ return; // No change
+ LayoutObject* layout_object = element_->GetLayoutObject();
+ if (!layout_object)
+ return;
+ LayoutSVGResourceContainer::MarkClientForInvalidation(
+ *layout_object, SVGResourceClient::kPaintInvalidation);
+}
+
+void SVGElementResourceClient::SetFilterData(FilterData* filter_data) {
+ filter_data_ = filter_data;
+}
+
+bool SVGElementResourceClient::ClearFilterData() {
+ FilterData* filter_data = filter_data_.Release();
+ if (filter_data)
+ filter_data->Dispose();
+ return !!filter_data;
+}
+
void SVGElementResourceClient::Trace(Visitor* visitor) {
visitor->Trace(element_);
+ visitor->Trace(filter_data_);
SVGResourceClient::Trace(visitor);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.h
index 5a158e2c60d..96db2ccc575 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources.h
@@ -32,6 +32,7 @@
namespace blink {
class ComputedStyle;
+class FilterEffect;
class LayoutObject;
class LayoutSVGResourceClipper;
class LayoutSVGResourceFilter;
@@ -39,6 +40,8 @@ class LayoutSVGResourceMarker;
class LayoutSVGResourceMasker;
class LayoutSVGResourcePaintServer;
class SVGElement;
+class SVGElementResourceClient;
+class SVGFilterGraphNodeMap;
// Holds a set of resources associated with a LayoutObject
class SVGResources {
@@ -47,7 +50,8 @@ class SVGResources {
public:
SVGResources();
- static SVGResourceClient* GetClient(const LayoutObject&);
+ static SVGElementResourceClient* GetClient(const LayoutObject&);
+ static FloatRect ReferenceBoxForEffects(const LayoutObject&);
static std::unique_ptr<SVGResources> BuildResources(const LayoutObject&,
const ComputedStyle&);
@@ -110,12 +114,13 @@ class SVGResources {
void BuildSetOfResources(HashSet<LayoutSVGResourceContainer*>&);
// Methods operating on all cached resources
- InvalidationModeMask RemoveClientFromCache(SVGResourceClient&) const;
InvalidationModeMask RemoveClientFromCacheAffectingObjectBounds(
- SVGResourceClient&) const;
+ SVGElementResourceClient&) const;
void ResourceDestroyed(LayoutSVGResourceContainer*);
void ClearReferencesTo(LayoutSVGResourceContainer*);
+ static bool DifferenceNeedsLayout(const SVGResources*, const SVGResources*);
+
#if DCHECK_IS_ON()
void Dump(const LayoutObject*);
#endif
@@ -188,6 +193,51 @@ class SVGResources {
DISALLOW_COPY_AND_ASSIGN(SVGResources);
};
+class FilterData final : public GarbageCollected<FilterData> {
+ public:
+ FilterData(FilterEffect* last_effect, SVGFilterGraphNodeMap* node_map)
+ : last_effect_(last_effect),
+ node_map_(node_map),
+ state_(kRecordingContent) {}
+
+ void UpdateStateOnPrepare();
+ bool UpdateStateOnFinish();
+ bool ContentNeedsUpdate() const { return state_ == kRecordingContent; }
+ void UpdateContent(sk_sp<PaintRecord> content);
+ sk_sp<PaintFilter> CreateFilter();
+ FloatRect MapRect(const FloatRect& input_rect) const;
+ // Perform a finegrained invalidation of the filter chain for the
+ // specified filter primitive and attribute. Returns false if no
+ // further invalidation is required, otherwise true.
+ bool Invalidate(SVGFilterPrimitiveStandardAttributes& primitive,
+ const QualifiedName& attribute);
+
+ void Dispose();
+
+ void Trace(Visitor*);
+
+ private:
+ Member<FilterEffect> last_effect_;
+ Member<SVGFilterGraphNodeMap> node_map_;
+
+ /*
+ * The state transitions should follow the following:
+ *
+ * RecordingContent->ReadyToPaint->GeneratingFilter->ReadyToPaint
+ * | ^ | ^
+ * v | v |
+ * RecordingContentCycleDetected GeneratingFilterCycleDetected
+ */
+ enum FilterDataState {
+ kRecordingContent,
+ kRecordingContentCycleDetected,
+ kReadyToPaint,
+ kGeneratingFilter,
+ kGeneratingFilterCycleDetected
+ };
+ FilterDataState state_;
+};
+
class SVGElementResourceClient final
: public GarbageCollected<SVGElementResourceClient>,
public SVGResourceClient {
@@ -200,10 +250,18 @@ class SVGElementResourceClient final
void ResourceElementChanged() override;
void ResourceDestroyed(LayoutSVGResourceContainer*) override;
+ void FilterPrimitiveChanged(SVGFilterPrimitiveStandardAttributes& primitive,
+ const QualifiedName& attribute) override;
+
+ void SetFilterData(FilterData*);
+ bool ClearFilterData();
+ FilterData* GetFilterData() const { return filter_data_; }
+
void Trace(Visitor*) override;
private:
Member<SVGElement> element_;
+ Member<FilterData> filter_data_;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
index 30fc8f834a4..61d0dfb9d2a 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc
@@ -22,6 +22,7 @@
#include <memory>
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h"
#include "third_party/blink/renderer/core/svg/svg_document_extensions.h"
@@ -32,7 +33,7 @@ SVGResourcesCache::SVGResourcesCache() = default;
SVGResourcesCache::~SVGResourcesCache() = default;
-bool SVGResourcesCache::AddResourcesFromLayoutObject(
+SVGResources* SVGResourcesCache::AddResourcesFromLayoutObject(
LayoutObject& object,
const ComputedStyle& style) {
DCHECK(!cache_.Contains(&object));
@@ -41,7 +42,7 @@ bool SVGResourcesCache::AddResourcesFromLayoutObject(
std::unique_ptr<SVGResources> new_resources =
SVGResources::BuildResources(object, style);
if (!new_resources)
- return false;
+ return nullptr;
// Put object in cache.
SVGResources* resources =
@@ -51,12 +52,12 @@ bool SVGResourcesCache::AddResourcesFromLayoutObject(
HashSet<LayoutSVGResourceContainer*> resource_set;
resources->BuildSetOfResources(resource_set);
- SVGResourcesCycleSolver solver(object);
+ SVGResourcesCycleSolver solver;
for (auto* resource_container : resource_set) {
- if (solver.FindCycle(resource_container))
+ if (resource_container->FindCycle(solver))
resources->ClearReferencesTo(resource_container);
}
- return true;
+ return resources;
}
bool SVGResourcesCache::RemoveResourcesFromLayoutObject(LayoutObject& object) {
@@ -64,12 +65,15 @@ bool SVGResourcesCache::RemoveResourcesFromLayoutObject(LayoutObject& object) {
return !!resources;
}
-bool SVGResourcesCache::UpdateResourcesFromLayoutObject(
+SVGResourcesCache::ResourceUpdateInfo
+SVGResourcesCache::UpdateResourcesFromLayoutObject(
LayoutObject& object,
const ComputedStyle& new_style) {
- bool did_update = RemoveResourcesFromLayoutObject(object);
- did_update |= AddResourcesFromLayoutObject(object, new_style);
- return did_update;
+ std::unique_ptr<SVGResources> old_resources = cache_.Take(&object);
+ SVGResources* new_resources = AddResourcesFromLayoutObject(object, new_style);
+ return {
+ old_resources || new_resources,
+ SVGResources::DifferenceNeedsLayout(old_resources.get(), new_resources)};
}
static inline SVGResourcesCache& ResourcesCache(Document& document) {
@@ -85,14 +89,22 @@ void SVGResourcesCache::ClientLayoutChanged(LayoutObject& object) {
SVGResources* resources = CachedResourcesForLayoutObject(object);
if (!resources)
return;
-
// Invalidate the resources if either the LayoutObject itself changed,
// or we have filter resources, which could depend on the layout of children.
if (!object.SelfNeedsLayout() && !resources->Filter())
return;
- SVGResourceClient* client = SVGResources::GetClient(object);
- if (InvalidationModeMask invalidation_flags =
- resources->RemoveClientFromCache(*client)) {
+ SVGElementResourceClient* client = SVGResources::GetClient(object);
+ InvalidationModeMask invalidation_flags =
+ resources->RemoveClientFromCacheAffectingObjectBounds(*client);
+ if (LayoutSVGResourcePaintServer* fill = resources->Fill()) {
+ fill->RemoveClientFromCache(*client);
+ invalidation_flags |= SVGResourceClient::kPaintInvalidation;
+ }
+ if (LayoutSVGResourcePaintServer* stroke = resources->Stroke()) {
+ stroke->RemoveClientFromCache(*client);
+ invalidation_flags |= SVGResourceClient::kPaintInvalidation;
+ }
+ if (invalidation_flags) {
LayoutSVGResourceContainer::MarkClientForInvalidation(object,
invalidation_flags);
}
@@ -124,28 +136,34 @@ void SVGResourcesCache::ClientStyleChanged(LayoutObject& layout_object,
if (!diff.HasDifference() || !layout_object.Parent())
return;
- // In this case the proper SVGFE*Element will decide whether the modified CSS
- // properties require
- // a relayout or paintInvalidation.
- if (layout_object.IsSVGResourceFilterPrimitive() && !diff.NeedsLayout())
- return;
+ // LayoutObjects for SVGFE*Element should not be calling this function.
+ DCHECK(!layout_object.IsSVGFilterPrimitive());
// Dynamic changes of CSS properties like 'clip-path' may require us to
// recompute the associated resources for a LayoutObject.
// TODO(fs): Avoid passing in a useless StyleDifference, but instead compare
// oldStyle/newStyle to see which resources changed to be able to selectively
// rebuild individual resources, instead of all of them.
+ bool needs_layout = false;
if (LayoutObjectCanHaveResources(layout_object)) {
SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument());
- if (cache.UpdateResourcesFromLayoutObject(layout_object, new_style))
+ auto update_info =
+ cache.UpdateResourcesFromLayoutObject(layout_object, new_style);
+ if (update_info) {
layout_object.SetNeedsPaintPropertyUpdate();
+ // Since the visual rect has the bounds of the clip-path, mask and filter
+ // baked in, and the visual rect is updated during layout, we need to
+ // trigger layout if the style change could somehow have affected the
+ // bounds that form the visual rect.
+ needs_layout = update_info.needs_layout;
+ }
}
// If this layoutObject is the child of ResourceContainer and it require
// repainting that changes of CSS properties such as 'visibility',
// request repainting.
- bool needs_layout = diff.NeedsFullPaintInvalidation() &&
- IsLayoutObjectOfResourceContainer(layout_object);
+ needs_layout |= diff.NeedsPaintInvalidation() &&
+ IsLayoutObjectOfResourceContainer(layout_object);
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
layout_object, needs_layout);
@@ -173,8 +191,7 @@ void SVGResourcesCache::ResourceReferenceChanged(LayoutObject& layout_object) {
layout_object, true);
}
-void SVGResourcesCache::ClientWasAddedToTree(LayoutObject& layout_object,
- const ComputedStyle& new_style) {
+void SVGResourcesCache::ClientWasAddedToTree(LayoutObject& layout_object) {
if (!layout_object.GetNode())
return;
LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
@@ -183,7 +200,8 @@ void SVGResourcesCache::ClientWasAddedToTree(LayoutObject& layout_object,
if (!LayoutObjectCanHaveResources(layout_object))
return;
SVGResourcesCache& cache = ResourcesCache(layout_object.GetDocument());
- if (cache.AddResourcesFromLayoutObject(layout_object, new_style))
+ if (cache.AddResourcesFromLayoutObject(layout_object,
+ layout_object.StyleRef()))
layout_object.SetNeedsPaintPropertyUpdate();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h
index c44ec39599f..fe545ef76ba 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h
@@ -42,8 +42,7 @@ class SVGResourcesCache {
static SVGResources* CachedResourcesForLayoutObject(const LayoutObject&);
// Called from all SVG layoutObjects addChild() methods.
- static void ClientWasAddedToTree(LayoutObject&,
- const ComputedStyle& new_style);
+ static void ClientWasAddedToTree(LayoutObject&);
// Called from all SVG layoutObjects removeChild() methods.
static void ClientWillBeRemovedFromTree(LayoutObject&);
@@ -84,9 +83,17 @@ class SVGResourcesCache {
};
private:
- bool AddResourcesFromLayoutObject(LayoutObject&, const ComputedStyle&);
+ struct ResourceUpdateInfo {
+ bool changed;
+ bool needs_layout;
+
+ explicit operator bool() const { return changed; }
+ };
+ SVGResources* AddResourcesFromLayoutObject(LayoutObject&,
+ const ComputedStyle&);
bool RemoveResourcesFromLayoutObject(LayoutObject&);
- bool UpdateResourcesFromLayoutObject(LayoutObject&, const ComputedStyle&);
+ ResourceUpdateInfo UpdateResourcesFromLayoutObject(LayoutObject&,
+ const ComputedStyle&);
typedef HashMap<const LayoutObject*, std::unique_ptr<SVGResources>> CacheMap;
CacheMap cache_;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.cc
index e39121ebe6b..5ede5cc597b 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.cc
@@ -19,99 +19,30 @@
#include "third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h"
-#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources.h"
-#include "third_party/blink/renderer/core/layout/svg/svg_resources_cache.h"
-
namespace blink {
-SVGResourcesCycleSolver::SVGResourcesCycleSolver(LayoutObject& layout_object)
- : layout_object_(layout_object) {
- if (layout_object.IsSVGResourceContainer())
- active_resources_.insert(ToLayoutSVGResourceContainer(&layout_object));
-}
+SVGResourcesCycleSolver::SVGResourcesCycleSolver() = default;
SVGResourcesCycleSolver::~SVGResourcesCycleSolver() = default;
-class ScopedTraversalPath {
- public:
- typedef SVGResourcesCycleSolver::ResourceSet ResourceSet;
-
- ScopedTraversalPath(ResourceSet& active_set)
- : active_set_(active_set), resource_(nullptr) {}
- ~ScopedTraversalPath() {
- if (resource_)
- active_set_.erase(resource_);
- }
-
- bool Enter(LayoutSVGResourceContainer* resource) {
- if (!active_set_.insert(resource).is_new_entry)
- return false;
- resource_ = resource;
- return true;
- }
-
- private:
- ResourceSet& active_set_;
- LayoutSVGResourceContainer* resource_;
-};
-
-bool SVGResourcesCycleSolver::TraverseResourceContainer(
- LayoutSVGResourceContainer* resource) {
- // If we've traversed this sub-graph before and no cycles were observed, then
- // reuse that result.
- if (dag_cache_.Contains(resource))
- return false;
-
- ScopedTraversalPath scope(active_resources_);
- if (!scope.Enter(resource))
- return true;
-
- LayoutObject* node = resource;
- while (node) {
- // Skip subtrees which are themselves resources. (They will be
- // processed - if needed - when they are actually referenced.)
- if (node != resource && node->IsSVGResourceContainer()) {
- node = node->NextInPreOrderAfterChildren(resource);
- continue;
- }
- if (TraverseResources(*node))
- return true;
- node = node->NextInPreOrder(resource);
- }
-
- // No cycles found in (or from) this resource. Add it to the "DAG cache".
- dag_cache_.insert(resource);
- return false;
+bool SVGResourcesCycleSolver::IsKnownAcyclic(
+ const LayoutSVGResourceContainer* resource) const {
+ return dag_cache_.Contains(resource);
}
-bool SVGResourcesCycleSolver::TraverseResources(LayoutObject& layout_object) {
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(layout_object);
- return resources && TraverseResources(resources);
+void SVGResourcesCycleSolver::AddAcyclicSubgraph(
+ const LayoutSVGResourceContainer* resource) {
+ dag_cache_.insert(resource);
}
-bool SVGResourcesCycleSolver::TraverseResources(SVGResources* resources) {
- // Fetch all the referenced resources.
- ResourceSet local_resources;
- resources->BuildSetOfResources(local_resources);
-
- // This performs a depth-first search for a back-edge in all the
- // (potentially disjoint) graphs formed by the referenced resources.
- for (auto* local_resource : local_resources) {
- if (TraverseResourceContainer(local_resource))
- return true;
- }
- return false;
+bool SVGResourcesCycleSolver::EnterResource(
+ const LayoutSVGResourceContainer* resource) {
+ return active_resources_.insert(resource).is_new_entry;
}
-bool SVGResourcesCycleSolver::FindCycle(
- LayoutSVGResourceContainer* start_node) {
- DCHECK(active_resources_.IsEmpty() ||
- (active_resources_.size() == 1 &&
- active_resources_.Contains(
- ToLayoutSVGResourceContainer(&layout_object_))));
- return TraverseResourceContainer(start_node);
+void SVGResourcesCycleSolver::LeaveResource(
+ const LayoutSVGResourceContainer* resource) {
+ active_resources_.erase(resource);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h
index bf44ebdde60..6a9068479c5 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cycle_solver.h
@@ -21,15 +21,12 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_RESOURCES_CYCLE_SOLVER_H_
#include "base/macros.h"
+#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
namespace blink {
-class LayoutObject;
-class LayoutSVGResourceContainer;
-class SVGResources;
-
// This class traverses the graph formed by SVGResources of
// LayoutObjects, maintaining the active path as LayoutObjects are
// visited. It also maintains a cache of sub-graphs that has already
@@ -38,22 +35,40 @@ class SVGResourcesCycleSolver {
STACK_ALLOCATED();
public:
- SVGResourcesCycleSolver(LayoutObject&);
+ SVGResourcesCycleSolver();
~SVGResourcesCycleSolver();
- // Traverse the graph starting at the resource container
- // passed. Returns true if a cycle is detected.
- bool FindCycle(LayoutSVGResourceContainer*);
+ bool IsKnownAcyclic(const LayoutSVGResourceContainer*) const;
+ void AddAcyclicSubgraph(const LayoutSVGResourceContainer*);
- typedef HashSet<LayoutSVGResourceContainer*> ResourceSet;
+ class Scope {
+ STACK_ALLOCATED();
- private:
- bool TraverseResourceContainer(LayoutSVGResourceContainer*);
- bool TraverseResources(LayoutObject&);
- bool TraverseResources(SVGResources*);
+ public:
+ Scope(SVGResourcesCycleSolver& solver)
+ : solver_(solver), resource_(nullptr) {}
+ ~Scope() {
+ if (resource_)
+ solver_.LeaveResource(resource_);
+ }
+
+ bool Enter(const LayoutSVGResourceContainer* resource) {
+ if (!solver_.EnterResource(resource))
+ return false;
+ resource_ = resource;
+ return true;
+ }
- LayoutObject& layout_object_;
+ private:
+ SVGResourcesCycleSolver& solver_;
+ const LayoutSVGResourceContainer* resource_;
+ };
+
+ private:
+ bool EnterResource(const LayoutSVGResourceContainer*);
+ void LeaveResource(const LayoutSVGResourceContainer*);
+ using ResourceSet = HashSet<const LayoutSVGResourceContainer*>;
ResourceSet active_resources_;
ResourceSet dag_cache_;
DISALLOW_COPY_AND_ASSIGN(SVGResourcesCycleSolver);
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc
index 5c3e12cf096..94ddd75bcb5 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.cc
@@ -26,8 +26,6 @@
namespace blink {
-namespace {
-
float CalculateTextAnchorShift(const ComputedStyle& style, float length) {
bool is_ltr = style.IsLeftToRightDirection();
switch (style.SvgStyle().TextAnchor()) {
@@ -43,6 +41,8 @@ float CalculateTextAnchorShift(const ComputedStyle& style, float length) {
}
}
+namespace {
+
bool NeedsTextAnchorAdjustment(const ComputedStyle& style) {
bool is_ltr = style.IsLeftToRightDirection();
switch (style.SvgStyle().TextAnchor()) {
@@ -143,10 +143,7 @@ void SVGTextChunkBuilder::ProcessTextChunks(
}
SVGTextPathChunkBuilder::SVGTextPathChunkBuilder()
- : SVGTextChunkBuilder(),
- total_length_(0),
- total_characters_(0),
- total_text_anchor_shift_(0) {}
+ : SVGTextChunkBuilder(), total_length_(0), total_characters_(0) {}
void SVGTextPathChunkBuilder::HandleTextChunk(BoxListConstIterator box_start,
BoxListConstIterator box_end) {
@@ -155,10 +152,6 @@ void SVGTextPathChunkBuilder::HandleTextChunk(BoxListConstIterator box_start,
ChunkLengthAccumulator length_accumulator(!style.IsHorizontalWritingMode());
length_accumulator.ProcessRange(box_start, box_end);
- // Handle text-anchor as additional start offset for text paths.
- total_text_anchor_shift_ +=
- CalculateTextAnchorShift(style, length_accumulator.length());
-
total_length_ += length_accumulator.length();
total_characters_ += length_accumulator.NumCharacters();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.h
index 4e8da8976a3..b3ba82fc438 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_chunk_builder.h
@@ -26,6 +26,7 @@
namespace blink {
+class ComputedStyle;
class SVGInlineTextBox;
struct SVGTextFragment;
@@ -76,7 +77,6 @@ class SVGTextPathChunkBuilder final : public SVGTextChunkBuilder {
float TotalLength() const { return total_length_; }
unsigned TotalCharacters() const { return total_characters_; }
- float TotalTextAnchorShift() const { return total_text_anchor_shift_; }
private:
void HandleTextChunk(BoxListConstIterator box_start,
@@ -84,11 +84,13 @@ class SVGTextPathChunkBuilder final : public SVGTextChunkBuilder {
float total_length_;
unsigned total_characters_;
- float total_text_anchor_shift_;
DISALLOW_COPY_AND_ASSIGN(SVGTextPathChunkBuilder);
};
+// Compute the "shift" induced by the 'text-anchor' property.
+float CalculateTextAnchorShift(const ComputedStyle&, float length);
+
} // namespace blink
#endif
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.cc
index c2c41825bda..6f537e09faf 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.cc
@@ -172,15 +172,15 @@ class AttributeListsIterator {
private:
SVGLengthContext length_context_;
- Member<SVGLengthList> x_list_;
+ SVGLengthList* x_list_;
unsigned x_list_remaining_;
- Member<SVGLengthList> y_list_;
+ SVGLengthList* y_list_;
unsigned y_list_remaining_;
- Member<SVGLengthList> dx_list_;
+ SVGLengthList* dx_list_;
unsigned dx_list_remaining_;
- Member<SVGLengthList> dy_list_;
+ SVGLengthList* dy_list_;
unsigned dy_list_remaining_;
- Member<SVGNumberList> rotate_list_;
+ SVGNumberList* rotate_list_;
unsigned rotate_list_remaining_;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.h
index 37d9ed65f2e..956c93cc526 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_attributes_builder.h
@@ -58,7 +58,7 @@ class SVGTextLayoutAttributesBuilder {
unsigned new_length = 0)
: element(new_element), start(new_start), length(new_length) {}
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
Member<SVGTextPositioningElement> element;
unsigned start;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc
index b4af6bc127a..7628afd5795 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc
@@ -178,11 +178,7 @@ void SVGTextLayoutEngine::BeginTextPathLayout(SVGInlineFlowBox* flow_box) {
text_path_chunk_layout_builder.ProcessTextChunks(
line_layout.line_layout_boxes_);
- text_path_start_offset_ +=
- text_path_chunk_layout_builder.TotalTextAnchorShift();
- text_path_current_offset_ = text_path_start_offset_;
-
- // Eventually handle textLength adjustments.
+ // Handle 'textLength' adjustments.
SVGLengthAdjustType length_adjust = kSVGLengthAdjustUnknown;
float desired_text_length = 0;
@@ -199,20 +195,26 @@ void SVGTextLayoutEngine::BeginTextPathLayout(SVGInlineFlowBox* flow_box) {
desired_text_length = 0;
}
- if (!desired_text_length)
- return;
-
- float total_length = text_path_chunk_layout_builder.TotalLength();
- if (length_adjust == kSVGLengthAdjustSpacing) {
- text_path_spacing_ = 0;
- if (text_path_chunk_layout_builder.TotalCharacters() > 1) {
- text_path_spacing_ = desired_text_length - total_length;
- text_path_spacing_ /=
- text_path_chunk_layout_builder.TotalCharacters() - 1;
+ float text_path_content_length = text_path_chunk_layout_builder.TotalLength();
+ if (desired_text_length) {
+ if (length_adjust == kSVGLengthAdjustSpacing) {
+ text_path_spacing_ = 0;
+ if (text_path_chunk_layout_builder.TotalCharacters() > 1) {
+ text_path_spacing_ = desired_text_length - text_path_content_length;
+ text_path_spacing_ /=
+ text_path_chunk_layout_builder.TotalCharacters() - 1;
+ }
+ } else {
+ text_path_scaling_ = desired_text_length / text_path_content_length;
}
- } else {
- text_path_scaling_ = desired_text_length / total_length;
+ text_path_content_length = desired_text_length;
}
+
+ // Perform text-anchor adjustment.
+ float text_anchor_shift =
+ CalculateTextAnchorShift(text_path.StyleRef(), text_path_content_length);
+ text_path_start_offset_ += text_anchor_shift;
+ text_path_current_offset_ = text_path_start_offset_;
}
void SVGTextLayoutEngine::EndTextPathLayout() {
@@ -263,16 +265,16 @@ void SVGTextLayoutEngine::LayoutCharactersInTextBoxes(InlineFlowBox* start) {
for (InlineBox* child = start->FirstChild(); child;
child = child->NextOnLine()) {
- if (child->IsSVGInlineTextBox()) {
+ if (auto* svg_inline_text_box = DynamicTo<SVGInlineTextBox>(child)) {
DCHECK(child->GetLineLayoutItem().IsSVGInlineText());
- LayoutInlineTextBox(ToSVGInlineTextBox(child));
+ LayoutInlineTextBox(svg_inline_text_box);
} else {
// Skip generated content.
Node* node = child->GetLineLayoutItem().GetNode();
if (!node)
continue;
- SVGInlineFlowBox* flow_box = ToSVGInlineFlowBox(child);
+ auto* flow_box = To<SVGInlineFlowBox>(child);
bool is_text_path = IsA<SVGTextPathElement>(*node);
if (is_text_path)
BeginTextPathLayout(flow_box);
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_query.cc b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_query.cc
index 93250c14255..45a09e6d0aa 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_text_query.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_text_query.cc
@@ -93,8 +93,8 @@ static void CollectTextBoxesInFlowBox(InlineFlowBox* flow_box,
continue;
}
- if (child->IsSVGInlineTextBox())
- text_boxes.push_back(ToSVGInlineTextBox(child));
+ if (auto* svg_inline_text_box = DynamicTo<SVGInlineTextBox>(child))
+ text_boxes.push_back(svg_inline_text_box);
}
}
@@ -139,7 +139,7 @@ static void CollectTextBoxesInLogicalOrder(
text_boxes.Shrink(0);
for (InlineTextBox* text_box = text_line_layout.FirstTextBox(); text_box;
text_box = text_box->NextForSameLayoutObject())
- text_boxes.push_back(ToSVGInlineTextBox(text_box));
+ text_boxes.push_back(To<SVGInlineTextBox>(text_box));
std::sort(text_boxes.begin(), text_boxes.end(),
InlineTextBox::CompareByStart);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc b/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
index 11d8591fd6f..1b571da3649 100644
--- a/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
+++ b/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_auto.cc
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/core/layout/layout_table_cell.h"
#include "third_party/blink/renderer/core/layout/layout_table_col.h"
#include "third_party/blink/renderer/core/layout/layout_table_section.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_cell_interface.h"
#include "third_party/blink/renderer/core/layout/ng/table/layout_ng_table_interface.h"
#include "third_party/blink/renderer/core/layout/text_autosizer.h"
@@ -53,7 +54,7 @@ void TableLayoutAlgorithmAuto::RecalcColumn(unsigned eff_col) {
// we need to clear their dirty bits so that if we call
// setPreferredWidthsDirty(true) on a col or one of its descendants, we'll
// mark it's ancestors as dirty.
- ToLayoutTableCol(child)->ClearPreferredLogicalWidthsDirtyBits();
+ ToLayoutTableCol(child)->ClearIntrinsicLogicalWidthsDirtyBits();
} else if (child->IsTableSection()) {
LayoutTableSection* section = To<LayoutTableSection>(child);
unsigned num_rows = section->NumRows();
@@ -67,17 +68,20 @@ void TableLayoutAlgorithmAuto::RecalcColumn(unsigned eff_col) {
continue;
column_layout.column_has_no_cells = false;
- if (cell->MaxPreferredLogicalWidth())
+ MinMaxSizes cell_preferred_logical_widths =
+ cell->PreferredLogicalWidths();
+
+ if (cell_preferred_logical_widths.max_size)
column_layout.empty_cells_only = false;
if (cell->ColSpan() == 1) {
column_layout.min_logical_width =
- std::max<int>(cell->MinPreferredLogicalWidth().ToInt(),
+ std::max<int>(cell_preferred_logical_widths.min_size.ToInt(),
column_layout.min_logical_width);
- if (cell->MaxPreferredLogicalWidth() >
+ if (cell_preferred_logical_widths.max_size >
column_layout.max_logical_width) {
column_layout.max_logical_width =
- cell->MaxPreferredLogicalWidth().ToInt();
+ cell_preferred_logical_widths.max_size.ToInt();
max_contributor = cell;
}
@@ -143,7 +147,7 @@ void TableLayoutAlgorithmAuto::RecalcColumn(unsigned eff_col) {
// min/max width of at least 1px for it.
column_layout.min_logical_width =
std::max<int>(column_layout.min_logical_width,
- cell->MaxPreferredLogicalWidth() ? 1 : 0);
+ cell_preferred_logical_widths.max_size ? 1 : 0);
// This spanning cell originates in this column. Insert the cell into
// spanning cells list.
@@ -220,7 +224,7 @@ static bool ShouldScaleColumnsForParent(LayoutTable* table) {
// TODO(layout-dev): We can probably abort before reaching LayoutView in many
// cases. For example, if we find an object with contain:size, or even if we
// find a regular block with fixed logical width.
- while (!cb->IsLayoutView()) {
+ while (!IsA<LayoutView>(cb)) {
// It doesn't matter if our table is auto or fixed: auto means we don't
// scale. Fixed doesn't care if we do or not because it doesn't depend
// on the cell contents' preferred widths.
@@ -262,7 +266,7 @@ static bool ShouldScaleColumnsForSelf(LayoutNGTableInterface* table) {
return true;
LayoutBlock* cb = layout_table->ContainingBlock();
- while (!cb->IsLayoutView() && !cb->IsTableCell() &&
+ while (!IsA<LayoutView>(cb) && !cb->IsTableCell() &&
cb->StyleRef().Width().IsAuto() && !cb->IsOutOfFlowPositioned())
cb = cb->ContainingBlock();
@@ -404,10 +408,13 @@ int TableLayoutAlgorithmAuto::CalcEffectiveLogicalWidth() {
unsigned eff_col =
table_->AbsoluteColumnToEffectiveColumn(cell->AbsoluteColumnIndex());
wtf_size_t last_col = eff_col;
+ MinMaxSizes cell_preferred_logical_widths = cell->PreferredLogicalWidths();
int cell_min_logical_width =
- (cell->MinPreferredLogicalWidth() + spacing_in_row_direction).ToInt();
+ (cell_preferred_logical_widths.min_size + spacing_in_row_direction)
+ .ToInt();
int cell_max_logical_width =
- (cell->MaxPreferredLogicalWidth() + spacing_in_row_direction).ToInt();
+ (cell_preferred_logical_widths.max_size + spacing_in_row_direction)
+ .ToInt();
float total_percent = 0;
int span_min_logical_width = 0;
int span_max_logical_width = 0;
@@ -538,8 +545,11 @@ int TableLayoutAlgorithmAuto::CalcEffectiveLogicalWidth() {
layout_struct_[pos].effective_min_logical_width =
std::max(layout_struct_[pos].effective_min_logical_width,
column_min_logical_width);
+ column_max_logical_width =
+ std::max(column_max_logical_width, column_min_logical_width);
layout_struct_[pos].effective_max_logical_width =
- column_max_logical_width;
+ std::max(layout_struct_[pos].effective_max_logical_width,
+ column_max_logical_width);
allocated_min_logical_width += column_min_logical_width;
allocated_max_logical_width += column_max_logical_width;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc b/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
index f869ceb3a9d..7081480b880 100644
--- a/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
+++ b/chromium/third_party/blink/renderer/core/layout/table_layout_algorithm_fixed.cc
@@ -91,9 +91,9 @@ int TableLayoutAlgorithmFixed::CalcWidthArray() {
col = col->NextColumn()) {
// LayoutTableCols don't have the concept of preferred logical width, but we
// need to clear their dirty bits so that if we call
- // setPreferredWidthsDirty(true) on a col or one of its descendants, we'll
+ // SetPreferredWidthsDirty(true) on a col or one of its descendants, we'll
// mark it's ancestors as dirty.
- col->ClearPreferredLogicalWidthsDirtyBits();
+ col->ClearIntrinsicLogicalWidthsDirtyBits();
// Width specified by column-groups that have column child does not affect
// column width in fixed layout tables
@@ -184,12 +184,12 @@ int TableLayoutAlgorithmFixed::CalcWidthArray() {
++current_column;
}
- // TableLayoutAlgorithmFixed doesn't use min/maxPreferredLogicalWidths, but
- // we need to clear the dirty bit on the cell so that we'll correctly mark
- // its ancestors dirty in case we later call
- // setPreferredLogicalWidthsDirty() on it later.
- if (cell->PreferredLogicalWidthsDirty())
- cell->ClearPreferredLogicalWidthsDirty();
+ // TableLayoutAlgorithmFixed doesn't use PreferredLogicalWidths, but we
+ // need to clear the dirty bit on the cell so that we'll correctly mark its
+ // ancestors dirty in case we later call SetIntrinsicLogicalWidthsDirty()
+ // on it later.
+ if (cell->IntrinsicLogicalWidthsDirty())
+ cell->ClearIntrinsicLogicalWidthsDirty();
}
return used_width;
diff --git a/chromium/third_party/blink/renderer/core/layout/text_autosizer.cc b/chromium/third_party/blink/renderer/core/layout/text_autosizer.cc
index 400c1ee28e5..f3609dc9801 100644
--- a/chromium/third_party/blink/renderer/core/layout/text_autosizer.cc
+++ b/chromium/third_party/blink/renderer/core/layout/text_autosizer.cc
@@ -52,7 +52,6 @@
#include "third_party/blink/renderer/core/layout/layout_table_cell.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/ng/list/layout_ng_list_item.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
#include "third_party/blink/renderer/core/layout/style_retain_scope.h"
#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/page/page.h"
@@ -112,7 +111,7 @@ static bool IsPotentialClusterRoot(const LayoutObject* layout_object) {
// - Must not be normal list items, as items in the same list should look
// consistent, unless they are floating or position:absolute/fixed.
Node* node = layout_object->GeneratingNode();
- if (node && !node->hasChildren() && !layout_object->IsLayoutView())
+ if (node && !node->hasChildren() && !IsA<LayoutView>(layout_object))
return false;
if (!layout_object->IsLayoutBlock())
return false;
@@ -130,7 +129,7 @@ static bool IsIndependentDescendant(const LayoutBlock* layout_object) {
DCHECK(IsPotentialClusterRoot(layout_object));
LayoutBlock* containing_block = layout_object->ContainingBlock();
- return layout_object->IsLayoutView() || layout_object->IsFloating() ||
+ return IsA<LayoutView>(layout_object) || layout_object->IsFloating() ||
layout_object->IsOutOfFlowPositioned() ||
layout_object->IsTableCell() || layout_object->IsTableCaption() ||
layout_object->IsFlexibleBoxIncludingDeprecatedAndNG() ||
@@ -196,7 +195,7 @@ static bool BlockHeightConstrained(const LayoutBlock* block) {
// height:100%, without intending to constrain the height of the content
// within them.
return !block->IsDocumentElement() && !block->IsBody() &&
- !block->IsLayoutView();
+ !IsA<LayoutView>(block);
}
if (block->IsFloating())
return false;
@@ -324,7 +323,7 @@ TextAutosizer::BeginLayoutBehavior TextAutosizer::PrepareForLayout(
if (!first_block_to_begin_layout_) {
first_block_to_begin_layout_ = block;
PrepareClusterStack(block->Parent());
- if (block->IsLayoutView())
+ if (IsA<LayoutView>(block))
CheckSuperclusterConsistency();
} else if (block == CurrentCluster()->root_) {
// Ignore beginLayout on the same block twice.
@@ -359,7 +358,7 @@ void TextAutosizer::BeginLayout(LayoutBlock* block,
if (block->IsRubyRun() || block->IsRubyBase() || block->IsRubyText())
return;
- DCHECK(!cluster_stack_.IsEmpty() || block->IsLayoutView());
+ DCHECK(!cluster_stack_.IsEmpty() || IsA<LayoutView>(block));
if (cluster_stack_.IsEmpty())
did_check_cross_site_use_count_ = false;
@@ -465,11 +464,11 @@ float TextAutosizer::Inflate(LayoutObject* parent,
if (behavior == kDescendToInnerBlocks) {
// The ancestor nodes might be inline-blocks. We should
- // setPreferredLogicalWidthsDirty for ancestor nodes here.
- child->SetPreferredLogicalWidthsDirty();
+ // SetIntrinsicLogicalWidthsDirty for ancestor nodes here.
+ child->SetIntrinsicLogicalWidthsDirty();
} else if (parent->IsLayoutInline()) {
// FIXME: Investigate why MarkOnlyThis is sufficient.
- child->SetPreferredLogicalWidthsDirty(kMarkOnlyThis);
+ child->SetIntrinsicLogicalWidthsDirty(kMarkOnlyThis);
}
} else if (child->IsLayoutInline()) {
multiplier = Inflate(child, layouter, behavior, multiplier);
@@ -509,12 +508,13 @@ float TextAutosizer::Inflate(LayoutObject* parent,
else if (parent->IsLayoutNGListItem())
marker = ToLayoutNGListItem(parent)->Marker();
- // A LayoutNGListMarker has a text child that needs its font multiplier
- // updated. Just mark the entire subtree, to make sure we get to it.
+ // A LayoutNGOutsideListMarker has a text child that needs its font
+ // multiplier updated. Just mark the entire subtree, to make sure we get to
+ // it.
for (LayoutObject* walker = marker; walker;
walker = walker->NextInPreOrder(marker)) {
ApplyMultiplier(walker, multiplier, layouter);
- walker->SetPreferredLogicalWidthsDirty(kMarkOnlyThis);
+ walker->SetIntrinsicLogicalWidthsDirty(kMarkOnlyThis);
}
}
@@ -604,7 +604,7 @@ void TextAutosizer::UpdatePageInfoInAllFrames(Frame* main_frame) {
page_info.shared_info_);
// Remember the RemotePageSettings in the mainframe's renderer so we
// know when they change.
- document->GetPage()->SetTextAutosizePageInfo(page_info.shared_info_);
+ document->GetPage()->SetTextAutosizerPageInfo(page_info.shared_info_);
}
}
}
@@ -881,7 +881,7 @@ TextAutosizer::Cluster* TextAutosizer::MaybeCreateCluster(LayoutBlock* block) {
Cluster* parent_cluster =
cluster_stack_.IsEmpty() ? nullptr : CurrentCluster();
- DCHECK(parent_cluster || block->IsLayoutView());
+ DCHECK(parent_cluster || IsA<LayoutView>(block));
// If a non-independent block would not alter the SUPPRESSING flag, it doesn't
// need to be a cluster.
@@ -1091,7 +1091,7 @@ const LayoutBlock* TextAutosizer::DeepestBlockContainingAllText(
const LayoutBlock* root) const {
// To avoid font-size shaking caused by the change of LayoutView's
// DeepestBlockContainingAllText.
- if (root->IsLayoutView())
+ if (IsA<LayoutView>(root))
return root;
size_t first_depth = 0;
@@ -1171,10 +1171,9 @@ const LayoutObject* TextAutosizer::FindTextLeaf(
}
static bool IsCrossSite(const Frame& frame1, const Frame& frame2) {
- // Cross-site differs from cross-origin (LocalFrame::IsCrossOriginSubframe).
- // For example, http://foo.com and http://sub.foo.com are cross-origin but
- // same-site. Only cross-site text autosizing is impacted by site isolation
- // (crbug.com/393285).
+ // Cross-site differs from cross-origin. For example, http://foo.com and
+ // http://sub.foo.com are cross-origin but same-site. Only cross-site text
+ // autosizing is impacted by site isolation (crbug.com/393285).
const auto* origin1 = frame1.GetSecurityContext()->GetSecurityOrigin();
const auto* origin2 = frame2.GetSecurityContext()->GetSecurityOrigin();
@@ -1441,17 +1440,18 @@ TextAutosizer::DeferUpdatePageInfo::DeferUpdatePageInfo(Page* page)
}
}
-TextAutosizer::NGLayoutScope::NGLayoutScope(const NGBlockNode& node,
+TextAutosizer::NGLayoutScope::NGLayoutScope(LayoutBox* box,
LayoutUnit inline_size)
- : text_autosizer_(node.GetLayoutBox()->GetDocument().GetTextAutosizer()),
- block_(To<LayoutBlockFlow>(node.GetLayoutBox())) {
+ : text_autosizer_(box->GetDocument().GetTextAutosizer()), box_(box) {
+ // Bail if:
+ // - Text autosizing isn't enabled.
+ // - If the chid isn't a LayoutBlock.
+ // - If the child is a LayoutNGOutsideListMarker. (They are super-small
+ // blocks, and using them to determine if we should autosize the text will
+ // typically false, overriding whatever its parent has already correctly
+ // determined).
if (!text_autosizer_ || !text_autosizer_->ShouldHandleLayout() ||
- block_->IsLayoutNGListMarker()) {
- // Bail if text autosizing isn't enabled, but also if this is a
- // IsLayoutNGListMarker. They are super-small blocks, and using them to
- // determine if we should autosize the text will typically always yield
- // false, overriding whatever its parent (typically the list item) has
- // already correctly determined.
+ box_->IsLayoutNGOutsideListMarker() || !box_->IsLayoutBlock()) {
text_autosizer_ = nullptr;
return;
}
@@ -1460,14 +1460,14 @@ TextAutosizer::NGLayoutScope::NGLayoutScope(const NGBlockNode& node,
// know the inline size of the block. So set it. LayoutNG normally writes back
// to the legacy tree *after* layout, but this one must be set before, at
// least if the autosizer is enabled.
- block_->SetLogicalWidth(inline_size);
+ box_->SetLogicalWidth(inline_size);
- text_autosizer_->BeginLayout(block_, nullptr);
+ text_autosizer_->BeginLayout(To<LayoutBlock>(box_), nullptr);
}
TextAutosizer::NGLayoutScope::~NGLayoutScope() {
if (text_autosizer_)
- text_autosizer_->EndLayout(block_);
+ text_autosizer_->EndLayout(To<LayoutBlock>(box_));
}
TextAutosizer::DeferUpdatePageInfo::~DeferUpdatePageInfo() {
@@ -1548,7 +1548,7 @@ void TextAutosizer::CheckSuperclusterConsistency() {
potentially_inconsistent_superclusters.clear();
}
-void TextAutosizer::Trace(blink::Visitor* visitor) {
+void TextAutosizer::Trace(Visitor* visitor) {
visitor->Trace(document_);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/text_autosizer.h b/chromium/third_party/blink/renderer/core/layout/text_autosizer.h
index 19111b9123b..7a6390abf7b 100644
--- a/chromium/third_party/blink/renderer/core/layout/text_autosizer.h
+++ b/chromium/third_party/blink/renderer/core/layout/text_autosizer.h
@@ -47,11 +47,11 @@ class Document;
class Frame;
class IntSize;
class LayoutBlock;
+class LayoutBox;
class LayoutNGTableInterface;
class LayoutObject;
class LayoutText;
class LocalFrame;
-class NGBlockNode;
class Page;
class SubtreeLayoutScope;
@@ -80,7 +80,7 @@ class CORE_EXPORT TextAutosizer final : public GarbageCollected<TextAutosizer> {
bool PageNeedsAutosizing() const;
- void Trace(blink::Visitor*);
+ void Trace(Visitor*);
class LayoutScope {
STACK_ALLOCATED();
@@ -90,7 +90,7 @@ class CORE_EXPORT TextAutosizer final : public GarbageCollected<TextAutosizer> {
~LayoutScope();
protected:
- Member<TextAutosizer> text_autosizer_;
+ TextAutosizer* text_autosizer_;
LayoutBlock* block_;
};
@@ -105,12 +105,12 @@ class CORE_EXPORT TextAutosizer final : public GarbageCollected<TextAutosizer> {
STACK_ALLOCATED();
public:
- explicit NGLayoutScope(const NGBlockNode& node, LayoutUnit inline_size);
+ explicit NGLayoutScope(LayoutBox*, LayoutUnit inline_size);
~NGLayoutScope();
protected:
- Member<TextAutosizer> text_autosizer_;
- LayoutBlock* block_;
+ TextAutosizer* text_autosizer_;
+ LayoutBox* box_;
};
class CORE_EXPORT DeferUpdatePageInfo {
@@ -121,7 +121,7 @@ class CORE_EXPORT TextAutosizer final : public GarbageCollected<TextAutosizer> {
~DeferUpdatePageInfo();
private:
- Member<LocalFrame> main_frame_;
+ LocalFrame* main_frame_;
};
private:
diff --git a/chromium/third_party/blink/renderer/core/layout/text_autosizer_test.cc b/chromium/third_party/blink/renderer/core/layout/text_autosizer_test.cc
index fcf01c4cbce..dd9ad6e1102 100644
--- a/chromium/third_party/blink/renderer/core/layout/text_autosizer_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/text_autosizer_test.cc
@@ -579,7 +579,7 @@ TEST_F(TextAutosizerTest, ChangingSuperClusterFirstText) {
UpdateAllLifecyclePhasesForTest();
Element* long_text_element = GetDocument().getElementById("longText");
- long_text_element->SetInnerHTMLFromString(
+ long_text_element->setInnerHTML(
" Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed "
"do eiusmod tempor"
" incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
@@ -624,7 +624,7 @@ TEST_F(TextAutosizerTest, ChangingSuperClusterSecondText) {
UpdateAllLifecyclePhasesForTest();
Element* long_text_element = GetDocument().getElementById("longText");
- long_text_element->SetInnerHTMLFromString(
+ long_text_element->setInnerHTML(
" Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed "
"do eiusmod tempor"
" incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
@@ -669,7 +669,7 @@ TEST_F(TextAutosizerTest, AddingSuperCluster) {
UpdateAllLifecyclePhasesForTest();
Element* container = GetDocument().getElementById("container");
- container->SetInnerHTMLFromString(
+ container->setInnerHTML(
"<div class='supercluster' id='longText'>"
" Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed "
"do eiusmod tempor"
@@ -717,7 +717,7 @@ TEST_F(TextAutosizerTest, ChangingInheritedClusterTextInsideSuperCluster) {
UpdateAllLifecyclePhasesForTest();
Element* long_text_element = GetDocument().getElementById("longText");
- long_text_element->SetInnerHTMLFromString(
+ long_text_element->setInnerHTML(
" Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed "
"do eiusmod tempor"
" incididunt ut labore et dolore magna aliqua. Ut enim ad minim "
@@ -803,7 +803,7 @@ TEST_F(TextAutosizerTest, ResizeAndGlyphOverflowChanged) {
GetDocument().GetSettings()->SetTextAutosizingWindowSizeOverride(
IntSize(360, 640));
Element* html = GetDocument().body()->parentElement();
- html->SetInnerHTMLFromString(
+ html->setInnerHTML(
"<head>"
" <meta name='viewport' content='width=800'>"
" <style>"
@@ -843,7 +843,7 @@ TEST_F(TextAutosizerTest, ResizeAndGlyphOverflowChanged) {
TEST_F(TextAutosizerTest, narrowContentInsideNestedWideBlock) {
Element* html = GetDocument().body()->parentElement();
- html->SetInnerHTMLFromString(
+ html->setInnerHTML(
"<head>"
" <meta name='viewport' content='width=800'>"
" <style>"
@@ -879,7 +879,7 @@ TEST_F(TextAutosizerTest, narrowContentInsideNestedWideBlock) {
TEST_F(TextAutosizerTest, LayoutViewWidthProvider) {
Element* html = GetDocument().body()->parentElement();
- html->SetInnerHTMLFromString(
+ html->setInnerHTML(
"<head>"
" <meta name='viewport' content='width=800'>"
" <style>"
@@ -908,8 +908,8 @@ TEST_F(TextAutosizerTest, LayoutViewWidthProvider) {
EXPECT_FLOAT_EQ(40.f,
content->GetLayoutObject()->StyleRef().ComputedFontSize());
- GetDocument().getElementById("panel")->SetInnerHTMLFromString("insert text");
- content->SetInnerHTMLFromString(content->InnerHTMLAsString());
+ GetDocument().getElementById("panel")->setInnerHTML("insert text");
+ content->setInnerHTML(content->innerHTML());
UpdateAllLifecyclePhasesForTest();
// (specified font-size = 16px) * (viewport width = 800px) /
@@ -920,7 +920,7 @@ TEST_F(TextAutosizerTest, LayoutViewWidthProvider) {
TEST_F(TextAutosizerTest, MultiColumns) {
Element* html = GetDocument().body()->parentElement();
- html->SetInnerHTMLFromString(
+ html->setInnerHTML(
"<head>"
" <meta name='viewport' content='width=800'>"
" <style>"
diff --git a/chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc b/chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
index d65144043d6..cd5349c1f8f 100644
--- a/chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc
@@ -287,7 +287,7 @@ TEST_P(VisualRectMappingTest, LayoutView) {
// This case involves clipping: frame height is 50, y-coordinate of result
// rect is 13, so height should be clipped to (50 - 13) == 37.
ChildDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0, 47), kProgrammaticScroll);
+ ScrollOffset(0, 47), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
PhysicalRect original_rect(4, 60, 20, 80);
@@ -363,7 +363,7 @@ TEST_P(VisualRectMappingTest, LayoutViewDisplayNone) {
// This part is copied from the LayoutView test, just to ensure that the
// mapped rect is valid before display:none is set on the iframe.
ChildDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0, 47), kProgrammaticScroll);
+ ScrollOffset(0, 47), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
PhysicalRect original_rect(4, 60, 20, 80);
@@ -761,7 +761,8 @@ TEST_P(VisualRectMappingTest,
To<LayoutBlock>(GetLayoutObjectByElementId("stacking-context"));
auto* absolute = To<LayoutBlock>(GetLayoutObjectByElementId("absolute"));
auto* container = To<LayoutBlock>(GetLayoutObjectByElementId("container"));
- EXPECT_EQ(absolute->View(), &absolute->ContainerForPaintInvalidation());
+ if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+ EXPECT_EQ(absolute->View(), &absolute->ContainerForPaintInvalidation());
EXPECT_EQ(container, absolute->Container());
PhysicalRect absolute_visual_rect = absolute->LocalVisualRect();
@@ -1188,7 +1189,7 @@ TEST_P(VisualRectMappingTest, FixedContentsInIframe) {
root_view, kDefaultVisualRectFlags, true);
ChildDocument().View()->LayoutViewport()->SetScrollOffset(
- ScrollOffset(0, 50), kProgrammaticScroll);
+ ScrollOffset(0, 50), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// The fixed element should not scroll so the mapped visual rect should not
@@ -1221,8 +1222,8 @@ TEST_P(VisualRectMappingTest, FixedContentsWithScrollOffset) {
PhysicalRect(0, -10, 400, 300), fixed,
ancestor, kDefaultVisualRectFlags, true);
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 50),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 50), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// The fixed element does not scroll but the ancestor does which changes the
@@ -1249,8 +1250,8 @@ TEST_P(VisualRectMappingTest, FixedContentsUnderViewWithScrollOffset) {
PhysicalRect(0, 0, 400, 300), PhysicalRect(0, 0, 400, 300), fixed,
fixed->View(), kDefaultVisualRectFlags, true);
- GetDocument().View()->LayoutViewport()->SetScrollOffset(ScrollOffset(0, 50),
- kProgrammaticScroll);
+ GetDocument().View()->LayoutViewport()->SetScrollOffset(
+ ScrollOffset(0, 50), mojom::blink::ScrollType::kProgrammatic);
UpdateAllLifecyclePhasesForTest();
// Results of mapping to ancestor are in absolute coordinates of the