summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/layout
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-08-24 12:15:48 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-08-28 13:30:04 +0000
commitb014812705fc80bff0a5c120dfcef88f349816dc (patch)
tree25a2e2d9fa285f1add86aa333389a839f81a39ae /chromium/third_party/blink/renderer/core/layout
parent9f4560b1027ae06fdb497023cdcaf91b8511fa74 (diff)
downloadqtwebengine-chromium-b014812705fc80bff0a5c120dfcef88f349816dc.tar.gz
BASELINE: Update Chromium to 68.0.3440.125
Change-Id: I23f19369e01f688e496f5bf179abb521ad73874f Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/third_party/blink/renderer/core/layout')
-rw-r--r--chromium/third_party/blink/renderer/core/layout/BUILD.gn25
-rw-r--r--chromium/third_party/blink/renderer/core/layout/DEPS5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/custom_layout_child.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/custom_layout_constraints.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/custom_layout_constraints_options.idl4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc48
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/layout_custom.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/layout_custom.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_baseline_alignment.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_baseline_alignment.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_layout_utils.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.cc182
-rw-r--r--chromium/third_party/blink/renderer/core/layout/grid_track_sizing_algorithm.h60
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_request.h13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/hit_test_result.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/intersection_geometry.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/jank_tracker.cc161
-rw-r--r--chromium/third_party/blink/renderer/core/layout/jank_tracker.h58
-rw-r--r--chromium/third_party/blink/renderer/core/layout/jank_tracker_test.cc68
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block.cc59
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block.h10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_flow.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_flow.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_block_flow_line.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box.cc362
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box.h62
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_model_object.cc90
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_model_object_test.cc116
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_box_test.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_br.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_br.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_count_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_deprecated_flexible_box.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_embedded_content.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_embedded_object.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_embedded_object.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_flexible_box.cc104
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_flexible_box.h12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_full_screen.cc98
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_full_screen.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_geometry_map.cc12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_geometry_map_test.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_grid.cc200
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_grid.h27
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_html_canvas.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_iframe.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_iframe.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image.cc132
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_image.h21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_inline.cc41
-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.cc122
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_item.cc54
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_marker.cc41
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_list_marker.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_media.cc7
-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.cc67
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_menu_list.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.cc47
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object.cc129
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object.h51
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object_child_list.cc36
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_object_test.cc69
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_progress.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_quote.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_replaced.cc45
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_replaced.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_scrollbar.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_scrollbar_theme.cc33
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_scrollbar_theme.h25
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_slider.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_slider.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_slider_container.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_slider_thumb.cc56
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_slider_thumb.h56
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_state.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_box_component.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_caption.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_cell.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_cell.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_table_section.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text.cc285
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text.h24
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_combine.cc68
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_combine.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control.cc39
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control_multi_line.cc14
-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.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_control_single_line.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_fragment.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_fragment.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_text_test.cc64
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_default.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_default.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_mac.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_theme_mac.mm17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.cc70
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.h13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_video.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_view.cc87
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_view.h22
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_word_break.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/layout_word_break.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/inline_box.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.cc14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/line_orientation_utils.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/line_orientation_utils.h30
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/line_orientation_utils_test.cc44
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/root_inline_box.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/line/root_inline_box.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/map_coordinates_flags.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/map_coordinates_test.cc249
-rw-r--r--chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc74
-rw-r--r--chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group_test.cc103
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space_test.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.cc172
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h45
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h66
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_shape_exclusions.h35
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_edge.h21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h64
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc313
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h55
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position_test.cc (renamed from chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect_test.cc)88
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.cc276
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h45
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.cc102
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_box_state.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.cc58
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h68
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h12
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.cc141
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.h16
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder_test.cc108
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.cc182
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm_test.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.cc294
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h50
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h32
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_test.cc29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.cc34
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.cc306
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h48
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker_test.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc201
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h51
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_utils.cc31
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_utils.h25
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.cc24
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h14
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_test.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.cc47
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.cc97
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc10
-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.h31
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.cc132
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h35
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc49
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h26
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.cc19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/layout_ng_list_marker_image.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.cc25
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.cc129
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_absolute_utils_test.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_base_fragment_builder.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_base_fragment_builder.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_child_iterator_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.cc770
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm.h66
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_layout_algorithm_test.cc30
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.cc223
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_node.h13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_block_node_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.cc77
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_box_fragment.h4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.cc28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm_test.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc153
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space.h144
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc109
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h77
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h29
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_exclusion.h28
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.cc27
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.cc156
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h19
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc18
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_inline_layout_test.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.cc16
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_result.h63
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_test.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc23
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.h21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.cc297
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils.h68
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_length_utils_test.cc111
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.cc15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.cc69
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.h42
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.cc179
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h16
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment_test.cc1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.cc199
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.cc57
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h34
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_positioned_float.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_positioned_float.h5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_relative_utils.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.h7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.cc8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h1
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.cc21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/scroll_anchor_test.cc78
-rw-r--r--chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc263
-rw-r--r--chromium/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/shapes/polygon_shape.h2
-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.cc70
-rw-r--r--chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/subtree_layout_scope.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc5
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_inline.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.cc11
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_path.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.cc59
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_clipper.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.cc94
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h17
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_filter.h15
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.cc7
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_gradient.h8
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.cc4
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_paint_server.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.cc13
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_resource_pattern.h10
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.cc20
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_root.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.cc76
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_shape.h21
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.cc9
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/layout_svg_text.h2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_layout_support.cc2
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.cc135
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.h24
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources.cc252
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources.h40
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.cc53
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_resources_cache.h3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.cc6
-rw-r--r--chromium/third_party/blink/renderer/core/layout/text_autosizer_test.cc3
-rw-r--r--chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_perftest.cc173
-rw-r--r--chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_test.cc103
316 files changed, 8973 insertions, 4903 deletions
diff --git a/chromium/third_party/blink/renderer/core/layout/BUILD.gn b/chromium/third_party/blink/renderer/core/layout/BUILD.gn
index 1651d24669c..052db1932e7 100644
--- a/chromium/third_party/blink/renderer/core/layout/BUILD.gn
+++ b/chromium/third_party/blink/renderer/core/layout/BUILD.gn
@@ -92,6 +92,8 @@ blink_core_sources("layout") {
"hit_testing_transform_state.h",
"intersection_geometry.cc",
"intersection_geometry.h",
+ "jank_tracker.cc",
+ "jank_tracker.h",
"layout_analyzer.cc",
"layout_analyzer.h",
"layout_block.cc",
@@ -197,8 +199,6 @@ blink_core_sources("layout") {
"layout_slider.h",
"layout_slider_container.cc",
"layout_slider_container.h",
- "layout_slider_thumb.cc",
- "layout_slider_thumb.h",
"layout_state.cc",
"layout_state.h",
"layout_table.cc",
@@ -268,6 +268,8 @@ blink_core_sources("layout") {
"line/line_breaker.h",
"line/line_info.h",
"line/line_layout_state.h",
+ "line/line_orientation_utils.cc",
+ "line/line_orientation_utils.h",
"line/line_width.cc",
"line/line_width.h",
"line/root_inline_box.cc",
@@ -284,6 +286,10 @@ blink_core_sources("layout") {
"multi_column_fragmentainer_group.h",
"ng/exclusions/ng_exclusion_space.cc",
"ng/exclusions/ng_exclusion_space.h",
+ "ng/exclusions/ng_layout_opportunity.cc",
+ "ng/exclusions/ng_layout_opportunity.h",
+ "ng/exclusions/ng_line_layout_opportunity.h",
+ "ng/exclusions/ng_shape_exclusions.h",
"ng/geometry/ng_bfc_offset.cc",
"ng/geometry/ng_bfc_offset.h",
"ng/geometry/ng_bfc_rect.cc",
@@ -292,7 +298,6 @@ blink_core_sources("layout") {
"ng/geometry/ng_border_edges.h",
"ng/geometry/ng_box_strut.cc",
"ng/geometry/ng_box_strut.h",
- "ng/geometry/ng_edge.h",
"ng/geometry/ng_logical_offset.cc",
"ng/geometry/ng_logical_offset.h",
"ng/geometry/ng_logical_rect.cc",
@@ -318,6 +323,8 @@ blink_core_sources("layout") {
"ng/inline/ng_baseline.h",
"ng/inline/ng_bidi_paragraph.cc",
"ng/inline/ng_bidi_paragraph.h",
+ "ng/inline/ng_caret_position.cc",
+ "ng/inline/ng_caret_position.h",
"ng/inline/ng_caret_rect.cc",
"ng/inline/ng_caret_rect.h",
"ng/inline/ng_inline_box_state.cc",
@@ -346,6 +353,10 @@ blink_core_sources("layout") {
"ng/inline/ng_line_breaker.h",
"ng/inline/ng_line_height_metrics.cc",
"ng/inline/ng_line_height_metrics.h",
+ "ng/inline/ng_line_truncator.cc",
+ "ng/inline/ng_line_truncator.h",
+ "ng/inline/ng_line_utils.cc",
+ "ng/inline/ng_line_utils.h",
"ng/inline/ng_offset_mapping.cc",
"ng/inline/ng_offset_mapping.h",
"ng/inline/ng_offset_mapping_builder.cc",
@@ -360,8 +371,12 @@ blink_core_sources("layout") {
"ng/inline/ng_text_fragment_builder.h",
"ng/layout_ng_block_flow.cc",
"ng/layout_ng_block_flow.h",
+ "ng/layout_ng_flexible_box.cc",
+ "ng/layout_ng_flexible_box.h",
"ng/layout_ng_mixin.cc",
"ng/layout_ng_mixin.h",
+ "ng/layout_ng_table_caption.cc",
+ "ng/layout_ng_table_caption.h",
"ng/layout_ng_table_cell.cc",
"ng/layout_ng_table_cell.h",
"ng/legacy_layout_tree_walking.cc",
@@ -415,11 +430,15 @@ blink_core_sources("layout") {
"ng/ng_layout_input_node.h",
"ng/ng_layout_result.cc",
"ng/ng_layout_result.h",
+ "ng/ng_layout_utils.cc",
+ "ng/ng_layout_utils.h",
"ng/ng_length_utils.cc",
"ng/ng_length_utils.h",
"ng/ng_out_of_flow_layout_part.cc",
"ng/ng_out_of_flow_layout_part.h",
"ng/ng_out_of_flow_positioned_descendant.h",
+ "ng/ng_outline_utils.cc",
+ "ng/ng_outline_utils.h",
"ng/ng_page_layout_algorithm.cc",
"ng/ng_page_layout_algorithm.h",
"ng/ng_physical_box_fragment.cc",
diff --git a/chromium/third_party/blink/renderer/core/layout/DEPS b/chromium/third_party/blink/renderer/core/layout/DEPS
new file mode 100644
index 00000000000..3b34fd02b70
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/DEPS
@@ -0,0 +1,5 @@
+specific_include_rules = {
+ "layout_theme\.cc": [
+ "+ui/native_theme/native_theme.h",
+ ],
+}
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc b/chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc
index 804ffe2869e..6e690135457 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc
+++ b/chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.cc
@@ -5,9 +5,9 @@
#include "third_party/blink/renderer/core/layout/custom/css_layout_definition.h"
#include <memory>
-#include "third_party/blink/renderer/bindings/core/v8/dictionary_iterator.h"
#include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
+#include "third_party/blink/renderer/bindings/core/v8/script_iterator.h"
#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_layout_fragment_request.h"
@@ -121,7 +121,7 @@ bool CSSLayoutDefinition::Instance::Layout(
v8::Local<v8::Object> generator =
v8::Local<v8::Object>::Cast(generator_value);
- DictionaryIterator iterator(generator, isolate);
+ ScriptIterator iterator(generator, isolate);
v8::Local<v8::Value> next_value;
// We run the generator until it's exhausted.
@@ -274,8 +274,7 @@ void CSSLayoutDefinition::Instance::Trace(blink::Visitor* visitor) {
visitor->Trace(definition_);
}
-void CSSLayoutDefinition::TraceWrappers(
- const ScriptWrappableVisitor* visitor) const {
+void CSSLayoutDefinition::TraceWrappers(ScriptWrappableVisitor* visitor) const {
visitor->TraceWrappers(constructor_.Cast<v8::Value>());
visitor->TraceWrappers(intrinsic_sizes_.Cast<v8::Value>());
visitor->TraceWrappers(layout_.Cast<v8::Value>());
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.h b/chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.h
index cae5fa26f58..c0ff5e73cfc 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.h
+++ b/chromium/third_party/blink/renderer/core/layout/custom/css_layout_definition.h
@@ -81,7 +81,7 @@ class CSSLayoutDefinition final
}
void Trace(blink::Visitor* visitor) {}
- void TraceWrappers(const ScriptWrappableVisitor*) const override;
+ void TraceWrappers(ScriptWrappableVisitor*) const override;
const char* NameInHeapSnapshot() const override {
return "CSSLayoutDefinition";
}
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_child.h b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_child.h
index 3049da7f000..4e1193e15b3 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_child.h
+++ b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_child.h
@@ -27,7 +27,7 @@ class CustomLayoutChild : public ScriptWrappable {
public:
CustomLayoutChild(const CSSLayoutDefinition&, LayoutBox*);
- virtual ~CustomLayoutChild() = default;
+ ~CustomLayoutChild() override = default;
// LayoutChild.idl
PrepopulatedComputedStylePropertyMap* styleMap() const { return style_map_; }
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_constraints.h b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_constraints.h
index f45f5da75ae..7c3d6150412 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_constraints.h
+++ b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_constraints.h
@@ -18,7 +18,7 @@ class CustomLayoutConstraints : public ScriptWrappable {
public:
CustomLayoutConstraints(LayoutUnit fixed_inline_size)
: fixed_inline_size_(fixed_inline_size.ToDouble()) {}
- virtual ~CustomLayoutConstraints() = default;
+ ~CustomLayoutConstraints() override = default;
// LayoutConstraints.idl
double fixedInlineSize() const { return fixed_inline_size_; }
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_constraints_options.idl b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_constraints_options.idl
index 47c198f857f..8742a7752a5 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_constraints_options.idl
+++ b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_constraints_options.idl
@@ -8,8 +8,8 @@
// don't want the resulting generated class to have a Layout* prefix.
// This name is fine, as it doesn't appear to javascript at all.
dictionary CustomLayoutConstraintsOptions {
- // double availableInlineSize = 0;
- // double availableBlockSize = 0;
+ double availableInlineSize = 0;
+ double availableBlockSize = 0;
double fixedInlineSize;
double fixedBlockSize;
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.h b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.h
index 4970f13030a..8c18e76bb2c 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment.h
@@ -31,7 +31,7 @@ class CustomLayoutFragment : public ScriptWrappable {
CustomLayoutFragment(CustomLayoutFragmentRequest*,
const LayoutUnit inline_size,
const LayoutUnit block_size);
- virtual ~CustomLayoutFragment() = default;
+ ~CustomLayoutFragment() override = default;
double inlineSize() const { return inline_size_; }
double blockSize() const { return block_size_; }
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc
index cf4371e864b..b401bbaf7ce 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc
+++ b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.cc
@@ -25,12 +25,6 @@ CustomLayoutFragment* CustomLayoutFragmentRequest::PerformLayout() {
LayoutBox* box = child_->GetLayoutBox();
const ComputedStyle& style = box->StyleRef();
- // TODO(ikilpatrick): At the moment we just pretend that we are being sized
- // off something which is 0x0. Additional fields inside the constraints
- // object will allow the developer to override this.
- box->SetOverrideContainingBlockContentLogicalWidth(LayoutUnit());
- box->SetOverrideContainingBlockContentLogicalHeight(LayoutUnit());
-
DCHECK(box->Parent());
DCHECK(box->Parent()->IsLayoutCustom());
DCHECK(box->Parent() == box->ContainingBlock());
@@ -42,35 +36,43 @@ CustomLayoutFragment* CustomLayoutFragmentRequest::PerformLayout() {
if (options_.hasFixedInlineSize()) {
if (is_parallel_writing_mode) {
- box->SetOverrideLogicalContentWidth(
- (LayoutUnit::FromDoubleRound(options_.fixedInlineSize()) -
- box->BorderAndPaddingLogicalWidth())
- .ClampNegativeToZero());
+ box->SetOverrideLogicalWidth(
+ LayoutUnit::FromDoubleRound(options_.fixedInlineSize()));
+ } else {
+ box->SetOverrideLogicalHeight(
+ LayoutUnit::FromDoubleRound(options_.fixedInlineSize()));
+ }
+ } else {
+ if (is_parallel_writing_mode) {
+ box->SetOverrideContainingBlockContentLogicalWidth(
+ LayoutUnit::FromDoubleRound(options_.availableInlineSize()));
} else {
- box->SetOverrideLogicalContentHeight(
- (LayoutUnit::FromDoubleRound(options_.fixedInlineSize()) -
- box->BorderAndPaddingLogicalHeight())
- .ClampNegativeToZero());
+ box->SetOverrideContainingBlockContentLogicalHeight(
+ LayoutUnit::FromDoubleRound(options_.availableInlineSize()));
}
}
if (options_.hasFixedBlockSize()) {
if (is_parallel_writing_mode) {
- box->SetOverrideLogicalContentHeight(
- (LayoutUnit::FromDoubleRound(options_.fixedBlockSize()) -
- box->BorderAndPaddingLogicalHeight())
- .ClampNegativeToZero());
+ box->SetOverrideLogicalHeight(
+ LayoutUnit::FromDoubleRound(options_.fixedBlockSize()));
+ } else {
+ box->SetOverrideLogicalWidth(
+ LayoutUnit::FromDoubleRound(options_.fixedBlockSize()));
+ }
+ } else {
+ if (is_parallel_writing_mode) {
+ box->SetOverrideContainingBlockContentLogicalHeight(
+ LayoutUnit::FromDoubleRound(options_.availableBlockSize()));
} else {
- box->SetOverrideLogicalContentWidth(
- (LayoutUnit::FromDoubleRound(options_.fixedBlockSize()) -
- box->BorderAndPaddingLogicalWidth())
- .ClampNegativeToZero());
+ box->SetOverrideContainingBlockContentLogicalWidth(
+ LayoutUnit::FromDoubleRound(options_.availableBlockSize()));
}
}
box->ForceLayout();
- box->ClearContainingBlockOverrideSize();
+ box->ClearOverrideContainingBlockContentSize();
box->ClearOverrideSize();
LayoutUnit fragment_inline_size =
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.h b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.h
index 2c310e4ef4f..60353643e9c 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.h
+++ b/chromium/third_party/blink/renderer/core/layout/custom/custom_layout_fragment_request.h
@@ -23,7 +23,7 @@ class CustomLayoutFragmentRequest : public ScriptWrappable {
public:
CustomLayoutFragmentRequest(CustomLayoutChild*,
const CustomLayoutConstraintsOptions&);
- virtual ~CustomLayoutFragmentRequest() = default;
+ ~CustomLayoutFragmentRequest() override = default;
// Produces a CustomLayoutFragment from this CustomLayoutFragmentRequest. This
// may fail if the underlying LayoutBox represented by the CustomLayoutChild
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/layout_custom.cc b/chromium/third_party/blink/renderer/core/layout/custom/layout_custom.cc
index b194b7df0eb..cead5acc48f 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/layout_custom.cc
+++ b/chromium/third_party/blink/renderer/core/layout/custom/layout_custom.cc
@@ -18,7 +18,27 @@
namespace blink {
-LayoutCustom::LayoutCustom(Element* element) : LayoutBlockFlow(element) {
+// This scope should be added when about to perform a web-developer defined
+// layout. This sets the phase_ flag which changes how children are sized.
+class LayoutCustomPhaseScope {
+ STACK_ALLOCATED();
+
+ public:
+ explicit LayoutCustomPhaseScope(LayoutCustom& layout_custom)
+ : layout_custom_(layout_custom) {
+ layout_custom_.phase_ = LayoutCustomPhase::kCustom;
+ }
+
+ ~LayoutCustomPhaseScope() {
+ layout_custom_.phase_ = LayoutCustomPhase::kFallback;
+ }
+
+ private:
+ LayoutCustom& layout_custom_;
+};
+
+LayoutCustom::LayoutCustom(Element* element)
+ : LayoutBlockFlow(element), phase_(LayoutCustomPhase::kFallback) {
DCHECK(element);
}
@@ -96,6 +116,8 @@ void LayoutCustom::UpdateBlockLayout(bool relayout_children) {
bool LayoutCustom::PerformLayout(bool relayout_children,
SubtreeLayoutScope* layout_scope) {
+ LayoutCustomPhaseScope phase_scope(*this);
+
// We need to fallback to block layout if we don't have a registered
// definition yet.
if (state_ == kUnloaded)
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/layout_custom.h b/chromium/third_party/blink/renderer/core/layout/custom/layout_custom.h
index 0f8e0f8ca6b..16ac0499d45 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/layout_custom.h
+++ b/chromium/third_party/blink/renderer/core/layout/custom/layout_custom.h
@@ -10,11 +10,18 @@
namespace blink {
+class LayoutCustomPhaseScope;
+
// NOTE: In the future there may be a third state "normal", this will mean that
// not everything is blockified, (e.g. root inline boxes, so that line-by-line
// layout can be performed).
enum LayoutCustomState { kUnloaded, kBlock };
+// This enum is used to determine if the current layout is under control of web
+// developer defined script, or during a fallback layout pass.
+// Sizing of children is different between these two phases.
+enum LayoutCustomPhase { kCustom, kFallback };
+
// The LayoutObject for elements which have "display: layout(foo);" specified.
// https://drafts.css-houdini.org/css-layout-api/
//
@@ -27,6 +34,7 @@ class LayoutCustom final : public LayoutBlockFlow {
const char* GetName() const override { return "LayoutCustom"; }
LayoutCustomState State() const { return state_; }
+ LayoutCustomPhase Phase() const { return phase_; }
bool CreatesNewFormattingContext() const override { return true; }
@@ -37,6 +45,8 @@ class LayoutCustom final : public LayoutBlockFlow {
void UpdateBlockLayout(bool relayout_children) override;
private:
+ friend class LayoutCustomPhaseScope;
+
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectLayoutCustom || LayoutBlockFlow::IsOfType(type);
}
@@ -44,6 +54,7 @@ class LayoutCustom final : public LayoutBlockFlow {
bool PerformLayout(bool relayout_children, SubtreeLayoutScope*);
LayoutCustomState state_;
+ LayoutCustomPhase phase_;
Persistent<CSSLayoutDefinition::Instance> instance_;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc b/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc
index 44d03820b1b..06874831cc0 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc
+++ b/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.cc
@@ -163,7 +163,7 @@ void LayoutWorkletGlobalScope::Trace(blink::Visitor* visitor) {
}
void LayoutWorkletGlobalScope::TraceWrappers(
- const ScriptWrappableVisitor* visitor) const {
+ ScriptWrappableVisitor* visitor) const {
for (auto definition : layout_definitions_)
visitor->TraceWrappers(definition.value);
MainThreadWorkletGlobalScope::TraceWrappers(visitor);
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h b/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h
index 6645721c900..a8e7fe0510c 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h
+++ b/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h
@@ -42,7 +42,7 @@ class CORE_EXPORT LayoutWorkletGlobalScope final
CSSLayoutDefinition* FindDefinition(const AtomicString& name);
void Trace(blink::Visitor*) override;
- void TraceWrappers(const ScriptWrappableVisitor*) const override;
+ void TraceWrappers(ScriptWrappableVisitor*) const override;
private:
LayoutWorkletGlobalScope(LocalFrame*,
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.cc b/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.cc
index 95a832de401..dad9635a1b0 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.cc
+++ b/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.cc
@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
+#include "third_party/blink/renderer/core/script/script.h"
#include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
#include "third_party/blink/renderer/core/workers/worklet_module_responses_map.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
@@ -32,7 +33,7 @@ LayoutWorkletGlobalScopeProxy::LayoutWorkletGlobalScopeProxy(
std::make_unique<MainThreadWorkletReportingProxy>(document);
auto creation_params = std::make_unique<GlobalScopeCreationParams>(
- document->Url(), document->UserAgent(),
+ document->Url(), ScriptType::kModule, document->UserAgent(),
document->GetContentSecurityPolicy()->Headers().get(),
document->GetReferrerPolicy(), document->GetSecurityOrigin(),
document->IsSecureContext(), nullptr /* worker_clients */,
diff --git a/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.h b/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.h
index 376eab411d9..a4d1f72a375 100644
--- a/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.h
+++ b/chromium/third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope_proxy.h
@@ -5,6 +5,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_CUSTOM_LAYOUT_WORKLET_GLOBAL_SCOPE_PROXY_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_CUSTOM_LAYOUT_WORKLET_GLOBAL_SCOPE_PROXY_H_
+#include "base/single_thread_task_runner.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/custom/layout_worklet_global_scope.h"
#include "third_party/blink/renderer/core/workers/main_thread_worklet_reporting_proxy.h"
diff --git a/chromium/third_party/blink/renderer/core/layout/grid_baseline_alignment.cc b/chromium/third_party/blink/renderer/core/layout/grid_baseline_alignment.cc
index afef423888f..7161b41cf78 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid_baseline_alignment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/grid_baseline_alignment.cc
@@ -168,14 +168,14 @@ LayoutUnit GridBaselineAlignment::BaselineOffsetForChild(
return LayoutUnit();
}
-Optional<LayoutUnit> GridBaselineAlignment::ExtentForBaselineAlignment(
+base::Optional<LayoutUnit> GridBaselineAlignment::ExtentForBaselineAlignment(
ItemPosition preference,
unsigned shared_context,
const LayoutBox& child,
GridAxis baseline_axis) const {
DCHECK(IsBaselinePosition(preference));
if (!IsBaselineContextComputed(baseline_axis))
- return WTF::nullopt;
+ return base::nullopt;
auto& group = GetBaselineGroupForChild(preference, shared_context, child,
baseline_axis);
diff --git a/chromium/third_party/blink/renderer/core/layout/grid_baseline_alignment.h b/chromium/third_party/blink/renderer/core/layout/grid_baseline_alignment.h
index 58cd74e61c9..a585074e82b 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid_baseline_alignment.h
+++ b/chromium/third_party/blink/renderer/core/layout/grid_baseline_alignment.h
@@ -156,10 +156,10 @@ class GridBaselineAlignment {
// Returns the sum of the 'max-ascent' and 'max-descent' of a particular
// item's baseline-sharing group.
- Optional<LayoutUnit> ExtentForBaselineAlignment(ItemPosition,
- unsigned shared_context,
- const LayoutBox&,
- GridAxis) const;
+ base::Optional<LayoutUnit> ExtentForBaselineAlignment(ItemPosition,
+ unsigned shared_context,
+ const LayoutBox&,
+ GridAxis) const;
// Determines whether baseline algnment may affect the intrinsic
// size of the grid container.
diff --git a/chromium/third_party/blink/renderer/core/layout/grid_layout_utils.cc b/chromium/third_party/blink/renderer/core/layout/grid_layout_utils.cc
index a3a4494622d..016f9c577a3 100644
--- a/chromium/third_party/blink/renderer/core/layout/grid_layout_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/grid_layout_utils.cc
@@ -112,8 +112,8 @@ bool GridLayoutUtils::HasOverrideContainingBlockContentSizeForChild(
const LayoutBox& child,
GridTrackSizingDirection direction) {
return direction == kForColumns
- ? child.HasOverrideContainingBlockLogicalWidth()
- : child.HasOverrideContainingBlockLogicalHeight();
+ ? child.HasOverrideContainingBlockContentLogicalWidth()
+ : child.HasOverrideContainingBlockContentLogicalHeight();
}
LayoutUnit GridLayoutUtils::OverrideContainingBlockContentSizeForChild(
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 19ca6991f23..950974a81c5 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
@@ -64,7 +64,7 @@ void GridTrack::SetInfinitelyGrowable(bool infinitely_growable) {
infinitely_growable_ = infinitely_growable;
}
-void GridTrack::SetGrowthLimitCap(Optional<LayoutUnit> growth_limit_cap) {
+void GridTrack::SetGrowthLimitCap(base::Optional<LayoutUnit> growth_limit_cap) {
DCHECK(!growth_limit_cap || *growth_limit_cap >= 0);
growth_limit_cap_ = growth_limit_cap;
}
@@ -88,16 +88,19 @@ class IndefiniteSizeStrategy final : public GridTrackSizingAlgorithmStrategy {
LayoutBox&,
bool override_size_has_changed) const override;
void MaximizeTracks(Vector<GridTrack>&,
- Optional<LayoutUnit>& free_space) override;
- double FindUsedFlexFraction(Vector<size_t>& flexible_sized_tracks_index,
- GridTrackSizingDirection,
- Optional<LayoutUnit> free_space) const override;
+ base::Optional<LayoutUnit>& free_space) override;
+ double FindUsedFlexFraction(
+ Vector<size_t>& flexible_sized_tracks_index,
+ GridTrackSizingDirection,
+ base::Optional<LayoutUnit> free_space) const override;
bool RecomputeUsedFlexFractionIfNeeded(
Vector<size_t>& flexible_sized_tracks_index,
double& flex_fraction,
Vector<LayoutUnit>& increments,
LayoutUnit& total_growth) const override;
LayoutUnit FreeSpaceForStretchAutoTracksStep() const override;
+ LayoutUnit MinContentForChild(LayoutBox&) const override;
+ LayoutUnit MaxContentForChild(LayoutBox&) const override;
};
class DefiniteSizeStrategy final : public GridTrackSizingAlgorithmStrategy {
@@ -110,10 +113,11 @@ class DefiniteSizeStrategy final : public GridTrackSizingAlgorithmStrategy {
LayoutBox&,
bool override_size_has_changed) const override;
void MaximizeTracks(Vector<GridTrack>&,
- Optional<LayoutUnit>& free_space) override;
- double FindUsedFlexFraction(Vector<size_t>& flexible_sized_tracks_index,
- GridTrackSizingDirection,
- Optional<LayoutUnit> free_space) const override;
+ base::Optional<LayoutUnit>& free_space) override;
+ double FindUsedFlexFraction(
+ Vector<size_t>& flexible_sized_tracks_index,
+ GridTrackSizingDirection,
+ base::Optional<LayoutUnit> free_space) const override;
bool RecomputeUsedFlexFractionIfNeeded(
Vector<size_t>& flexible_sized_tracks_index,
double& flex_fraction,
@@ -124,13 +128,6 @@ class DefiniteSizeStrategy final : public GridTrackSizingAlgorithmStrategy {
LayoutUnit FreeSpaceForStretchAutoTracksStep() const override;
};
-void GridTrackSizingAlgorithmStrategy::SetNeedsLayoutForChild(
- LayoutBox& child) const {
- if (algorithm_.is_in_perform_layout_) {
- child.SetNeedsLayout(LayoutInvalidationReason::kGridChanged, kMarkOnlyThis);
- }
-}
-
GridTrackSizingAlgorithmStrategy::~GridTrackSizingAlgorithmStrategy() = default;
bool GridTrackSizingAlgorithmStrategy::
@@ -159,40 +156,14 @@ void GridTrackSizingAlgorithmStrategy::
child.SetOverrideContainingBlockContentLogicalHeight(size);
}
-LayoutUnit GridTrackSizingAlgorithm::AssumedRowsSizeForOrthogonalChild(
- const LayoutBox& child) const {
- DCHECK(GridLayoutUtils::IsOrthogonalChild(*layout_grid_, child));
- const GridSpan& span = grid_.GridItemSpan(child, kForRows);
- LayoutUnit grid_area_size;
- bool grid_area_is_indefinite = false;
- LayoutUnit containing_block_available_size =
- layout_grid_->ContainingBlockLogicalHeightForContent(
- kExcludeMarginBorderPadding);
- for (auto track_position : span) {
- GridLength max_track_size =
- GetGridTrackSize(kForRows, track_position).MaxTrackBreadth();
- if (max_track_size.IsContentSized() || max_track_size.IsFlex()) {
- grid_area_is_indefinite = true;
- } else {
- grid_area_size += ValueForLength(max_track_size.length(),
- containing_block_available_size);
- }
- }
-
- grid_area_size +=
- layout_grid_->GuttersSize(grid_, kForRows, span.StartLine(),
- span.IntegerSpan(), AvailableSpace(kForRows));
-
- return grid_area_is_indefinite
- ? std::max(child.MaxPreferredLogicalWidth(), grid_area_size)
- : grid_area_size;
-}
-
LayoutUnit GridTrackSizingAlgorithm::GridAreaBreadthForChild(
const LayoutBox& child,
GridTrackSizingDirection direction) {
- if (direction == kForRows && sizing_state_ == kColumnSizingFirstIteration)
- return AssumedRowsSizeForOrthogonalChild(child);
+ if (direction == kForRows && sizing_state_ == kColumnSizingFirstIteration) {
+ DCHECK(GridLayoutUtils::IsOrthogonalChild(*layout_grid_, child));
+ return layout_grid_->EstimatedGridAreaBreadthForChild(grid_, child,
+ kForRows);
+ }
Vector<GridTrack>& all_tracks = Tracks(direction);
const GridSpan& span = grid_.GridItemSpan(child, direction);
@@ -211,12 +182,10 @@ bool GridTrackSizingAlgorithmStrategy::
UpdateOverrideContainingBlockContentSizeForChild(
LayoutBox& child,
GridTrackSizingDirection direction,
- Optional<LayoutUnit> override_size) const {
+ base::Optional<LayoutUnit> override_size) const {
if (!override_size)
override_size = algorithm_.GridAreaBreadthForChild(child, direction);
- if (GridLayoutUtils::HasOverrideContainingBlockContentSizeForChild(
- child, direction) &&
- GridLayoutUtils::OverrideContainingBlockContentSizeForChild(
+ if (GridLayoutUtils::OverrideContainingBlockContentSizeForChild(
child, direction) == override_size.value())
return false;
@@ -225,7 +194,7 @@ bool GridTrackSizingAlgorithmStrategy::
return true;
}
-Optional<LayoutUnit>
+base::Optional<LayoutUnit>
GridTrackSizingAlgorithmStrategy::ExtentForBaselineAlignment(
const LayoutBox& child) const {
const LayoutGrid& layout_grid = *GetLayoutGrid();
@@ -234,7 +203,7 @@ GridTrackSizingAlgorithmStrategy::ExtentForBaselineAlignment(
? kGridRowAxis
: kGridColumnAxis;
if (!layout_grid.IsBaselineAlignmentForChild(child, baseline_axis))
- return WTF::nullopt;
+ return base::nullopt;
ItemPosition align =
layout_grid.SelfAlignmentForChild(baseline_axis, child).GetPosition();
@@ -260,7 +229,7 @@ LayoutUnit GridTrackSizingAlgorithmStrategy::LogicalHeightForChild(
*GetLayoutGrid(), child, child_block_direction)) {
SetOverrideContainingBlockContentSizeForChild(child, child_block_direction,
LayoutUnit(-1));
- SetNeedsLayoutForChild(child);
+ child.SetNeedsLayout(LayoutInvalidationReason::kGridChanged, kMarkOnlyThis);
}
child.LayoutIfNeeded();
@@ -294,7 +263,7 @@ LayoutUnit GridTrackSizingAlgorithmStrategy::MinContentForChild(
if (UpdateOverrideContainingBlockContentSizeForChild(
child, child_inline_direction)) {
- SetNeedsLayoutForChild(child);
+ child.SetNeedsLayout(LayoutInvalidationReason::kGridChanged, kMarkOnlyThis);
}
return LogicalHeightForChild(child);
}
@@ -315,7 +284,7 @@ LayoutUnit GridTrackSizingAlgorithmStrategy::MaxContentForChild(
if (UpdateOverrideContainingBlockContentSizeForChild(
child, child_inline_direction)) {
- SetNeedsLayoutForChild(child);
+ child.SetNeedsLayout(LayoutInvalidationReason::kGridChanged, kMarkOnlyThis);
}
return LogicalHeightForChild(child);
}
@@ -444,13 +413,15 @@ LayoutUnit GridTrackSizingAlgorithmStrategy::MinLogicalWidthForChild(
void DefiniteSizeStrategy::LayoutGridItemForMinSizeComputation(
LayoutBox& child,
bool override_size_has_changed) const {
- if (override_size_has_changed)
- SetNeedsLayoutForChild(child);
- child.LayoutIfNeeded();
+ if (override_size_has_changed) {
+ child.SetNeedsLayout(LayoutInvalidationReason::kGridChanged, kMarkOnlyThis);
+ child.LayoutIfNeeded();
+ }
}
-void DefiniteSizeStrategy::MaximizeTracks(Vector<GridTrack>& tracks,
- Optional<LayoutUnit>& free_space) {
+void DefiniteSizeStrategy::MaximizeTracks(
+ Vector<GridTrack>& tracks,
+ base::Optional<LayoutUnit>& free_space) {
size_t tracks_size = tracks.size();
Vector<GridTrack*> tracks_for_distribution(tracks_size);
for (size_t i = 0; i < tracks_size; ++i) {
@@ -469,7 +440,7 @@ void DefiniteSizeStrategy::MaximizeTracks(Vector<GridTrack>& tracks,
double DefiniteSizeStrategy::FindUsedFlexFraction(
Vector<size_t>& flexible_sized_tracks_index,
GridTrackSizingDirection direction,
- Optional<LayoutUnit> free_space) const {
+ base::Optional<LayoutUnit> free_space) const {
GridSpan all_tracks_span = GridSpan::TranslatedDefiniteGridSpan(
0, algorithm_.Tracks(direction).size());
DCHECK(free_space);
@@ -484,13 +455,14 @@ LayoutUnit DefiniteSizeStrategy::FreeSpaceForStretchAutoTracksStep() const {
void IndefiniteSizeStrategy::LayoutGridItemForMinSizeComputation(
LayoutBox& child,
bool override_size_has_changed) const {
- if (override_size_has_changed && Direction() != kForColumns)
- SetNeedsLayoutForChild(child);
- child.LayoutIfNeeded();
+ if (override_size_has_changed && Direction() != kForColumns) {
+ child.SetNeedsLayout(LayoutInvalidationReason::kGridChanged, kMarkOnlyThis);
+ child.LayoutIfNeeded();
+ }
}
void IndefiniteSizeStrategy::MaximizeTracks(Vector<GridTrack>& tracks,
- Optional<LayoutUnit>&) {
+ base::Optional<LayoutUnit>&) {
for (auto& track : tracks)
track.SetBaseSize(track.GrowthLimit());
}
@@ -503,7 +475,7 @@ static inline double NormalizedFlexFraction(const GridTrack& track,
double IndefiniteSizeStrategy::FindUsedFlexFraction(
Vector<size_t>& flexible_sized_tracks_index,
GridTrackSizingDirection direction,
- Optional<LayoutUnit>) const {
+ base::Optional<LayoutUnit>) const {
auto all_tracks = algorithm_.Tracks(direction);
double flex_fraction = 0;
@@ -593,24 +565,61 @@ LayoutUnit IndefiniteSizeStrategy::FreeSpaceForStretchAutoTracksStep() const {
return min_size - ComputeTrackBasedSize();
}
-Optional<LayoutUnit> GridTrackSizingAlgorithm::FreeSpace(
+DISABLE_CFI_PERF
+LayoutUnit IndefiniteSizeStrategy::MinContentForChild(LayoutBox& child) const {
+ GridTrackSizingDirection child_inline_direction =
+ GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
+ kForColumns);
+ if (Direction() == child_inline_direction || Direction() == kForRows)
+ return GridTrackSizingAlgorithmStrategy::MinContentForChild(child);
+
+ // This code is executed only when computing the grid's intrinsic
+ // width based on an orthogonal child. We rely on the pre-layout
+ // performed in LayoutGrid::LayoutOrthogonalWritingModeRoots.
+ DCHECK(GridLayoutUtils::IsOrthogonalChild(*GetLayoutGrid(), child));
+
+ if (auto baseline_extent = ExtentForBaselineAlignment(child))
+ return baseline_extent.value();
+
+ return child.LogicalHeight() +
+ GridLayoutUtils::MarginLogicalHeightForChild(*GetLayoutGrid(), child);
+}
+
+DISABLE_CFI_PERF
+LayoutUnit IndefiniteSizeStrategy::MaxContentForChild(LayoutBox& child) const {
+ GridTrackSizingDirection child_inline_direction =
+ GridLayoutUtils::FlowAwareDirectionForChild(*GetLayoutGrid(), child,
+ kForColumns);
+ if (Direction() == child_inline_direction || Direction() == kForRows)
+ return GridTrackSizingAlgorithmStrategy::MaxContentForChild(child);
+
+ // This code is executed only when computing the grid's intrinsic
+ // width based on an orthogonal child. We rely on the pre-layout
+ // performed in LayoutGrid::LayoutOrthogonalWritingModeRoots.
+ DCHECK(GridLayoutUtils::IsOrthogonalChild(*GetLayoutGrid(), child));
+
+ return child.LogicalHeight() +
+ GridLayoutUtils::MarginLogicalHeightForChild(*GetLayoutGrid(), child);
+}
+
+base::Optional<LayoutUnit> GridTrackSizingAlgorithm::FreeSpace(
GridTrackSizingDirection direction) const {
return direction == kForRows ? free_space_rows_ : free_space_columns_;
}
-Optional<LayoutUnit> GridTrackSizingAlgorithm::AvailableSpace(
+base::Optional<LayoutUnit> GridTrackSizingAlgorithm::AvailableSpace(
GridTrackSizingDirection direction) const {
return direction == kForRows ? available_space_rows_
: available_space_columns_;
}
-Optional<LayoutUnit> GridTrackSizingAlgorithm::AvailableSpace() const {
+base::Optional<LayoutUnit> GridTrackSizingAlgorithm::AvailableSpace() const {
return AvailableSpace(direction_);
}
void GridTrackSizingAlgorithm::SetAvailableSpace(
GridTrackSizingDirection direction,
- Optional<LayoutUnit> available_space) {
+ base::Optional<LayoutUnit> available_space) {
if (direction == kForColumns)
available_space_columns_ = available_space;
else
@@ -627,8 +636,9 @@ const Vector<GridTrack>& GridTrackSizingAlgorithm::Tracks(
return direction == kForColumns ? columns_ : rows_;
}
-void GridTrackSizingAlgorithm::SetFreeSpace(GridTrackSizingDirection direction,
- Optional<LayoutUnit> free_space) {
+void GridTrackSizingAlgorithm::SetFreeSpace(
+ GridTrackSizingDirection direction,
+ base::Optional<LayoutUnit> free_space) {
if (direction == kForColumns)
free_space_columns_ = free_space;
else
@@ -1242,7 +1252,7 @@ void GridTrackSizingAlgorithm::ComputeGridContainerIntrinsicSizes() {
max_content_size_ += track.GrowthLimit();
// The growth limit caps must be cleared now in order to properly sort
// tracks by growth potential on an eventual "Maximize Tracks".
- track.SetGrowthLimitCap(WTF::nullopt);
+ track.SetGrowthLimitCap(base::nullopt);
}
}
@@ -1351,7 +1361,7 @@ void GridTrackSizingAlgorithm::ComputeFlexSizedTracksGrowth(
}
void GridTrackSizingAlgorithm::StretchFlexibleTracks(
- Optional<LayoutUnit> free_space) {
+ base::Optional<LayoutUnit> free_space) {
if (flexible_sized_tracks_index_.IsEmpty())
return;
@@ -1434,22 +1444,20 @@ bool GridTrackSizingAlgorithm::IsValidTransition() const {
return false;
}
-void GridTrackSizingAlgorithm::Setup(GridTrackSizingDirection direction,
- size_t num_tracks,
- Optional<LayoutUnit> available_space) {
+void GridTrackSizingAlgorithm::Setup(
+ GridTrackSizingDirection direction,
+ size_t num_tracks,
+ base::Optional<LayoutUnit> available_space) {
DCHECK(needs_setup_);
direction_ = direction;
SetAvailableSpace(
direction, available_space ? available_space.value().ClampNegativeToZero()
: available_space);
- if (available_space) {
+ if (available_space)
strategy_ = std::make_unique<DefiniteSizeStrategy>(*this);
- } else {
+ else
strategy_ = std::make_unique<IndefiniteSizeStrategy>(*this);
- is_in_perform_layout_ =
- layout_grid_->GetDocument().View()->IsInPerformLayout();
- }
content_sized_tracks_index_.Shrink(0);
flexible_sized_tracks_index_.Shrink(0);
@@ -1460,7 +1468,7 @@ void GridTrackSizingAlgorithm::Setup(GridTrackSizingDirection direction,
grid_, direction, 0, grid_.NumTracks(direction), available_space);
SetFreeSpace(direction, available_space.value() - gutters_size);
} else {
- SetFreeSpace(direction, WTF::nullopt);
+ SetFreeSpace(direction, base::nullopt);
}
Tracks(direction).resize(num_tracks);
@@ -1474,7 +1482,7 @@ void GridTrackSizingAlgorithm::Run() {
StateMachine state_machine(*this);
// Step 1.
- Optional<LayoutUnit> initial_free_space = FreeSpace(direction_);
+ base::Optional<LayoutUnit> initial_free_space = FreeSpace(direction_);
InitializeTrackSizes();
// Step 2.
@@ -1514,8 +1522,8 @@ void GridTrackSizingAlgorithm::Reset() {
content_sized_tracks_index_.Shrink(0);
flexible_sized_tracks_index_.Shrink(0);
auto_sized_tracks_for_stretch_index_.Shrink(0);
- SetAvailableSpace(kForRows, WTF::nullopt);
- SetAvailableSpace(kForColumns, WTF::nullopt);
+ SetAvailableSpace(kForRows, base::nullopt);
+ SetAvailableSpace(kForColumns, base::nullopt);
}
#if DCHECK_IS_ON()
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 0b471f6eb70..07622f71df3 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
@@ -7,13 +7,13 @@
#include <memory>
#include "base/macros.h"
+#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/grid_baseline_alignment.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/style/grid_positions_resolver.h"
#include "third_party/blink/renderer/core/style/grid_track_size.h"
#include "third_party/blink/renderer/platform/layout_unit.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink {
@@ -58,8 +58,10 @@ class GridTrack {
bool InfinitelyGrowable() const { return infinitely_growable_; }
void SetInfinitelyGrowable(bool);
- Optional<LayoutUnit> GrowthLimitCap() const { return growth_limit_cap_; }
- void SetGrowthLimitCap(Optional<LayoutUnit>);
+ base::Optional<LayoutUnit> GrowthLimitCap() const {
+ return growth_limit_cap_;
+ }
+ void SetGrowthLimitCap(base::Optional<LayoutUnit>);
private:
bool IsGrowthLimitBiggerThanBaseSize() const;
@@ -69,7 +71,7 @@ class GridTrack {
LayoutUnit growth_limit_;
LayoutUnit planned_size_;
LayoutUnit size_during_distribution_;
- Optional<LayoutUnit> growth_limit_cap_;
+ base::Optional<LayoutUnit> growth_limit_cap_;
bool infinitely_growable_;
};
@@ -86,7 +88,7 @@ class GridTrackSizingAlgorithm final {
// the algorithm.
void Setup(GridTrackSizingDirection,
size_t num_tracks,
- Optional<LayoutUnit> available_space);
+ base::Optional<LayoutUnit> available_space);
void Run();
void Reset();
@@ -108,21 +110,20 @@ class GridTrackSizingAlgorithm final {
Vector<GridTrack>& Tracks(GridTrackSizingDirection);
const Vector<GridTrack>& Tracks(GridTrackSizingDirection) const;
- Optional<LayoutUnit> FreeSpace(GridTrackSizingDirection) const;
- void SetFreeSpace(GridTrackSizingDirection, Optional<LayoutUnit>);
+ base::Optional<LayoutUnit> FreeSpace(GridTrackSizingDirection) const;
+ void SetFreeSpace(GridTrackSizingDirection, base::Optional<LayoutUnit>);
- Optional<LayoutUnit> AvailableSpace(GridTrackSizingDirection) const;
- void SetAvailableSpace(GridTrackSizingDirection, Optional<LayoutUnit>);
+ base::Optional<LayoutUnit> AvailableSpace(GridTrackSizingDirection) const;
+ void SetAvailableSpace(GridTrackSizingDirection, base::Optional<LayoutUnit>);
#if DCHECK_IS_ON()
bool TracksAreWiderThanMinTrackBreadth() const;
#endif
private:
- Optional<LayoutUnit> AvailableSpace() const;
+ base::Optional<LayoutUnit> AvailableSpace() const;
GridTrackSize RawGridTrackSize(GridTrackSizingDirection,
size_t translated_index) const;
- LayoutUnit AssumedRowsSizeForOrthogonalChild(const LayoutBox&) const;
LayoutUnit ComputeTrackBasedSize() const;
// Helper methods for step 1. initializeTrackSizes().
@@ -174,7 +175,7 @@ class GridTrackSizingAlgorithm final {
// method at thise level.
void InitializeTrackSizes();
void ResolveIntrinsicTrackSizes();
- void StretchFlexibleTracks(Optional<LayoutUnit> free_space);
+ void StretchFlexibleTracks(base::Optional<LayoutUnit> free_space);
void StretchAutoTracks();
// State machine.
@@ -183,12 +184,11 @@ class GridTrackSizingAlgorithm final {
// Data.
bool needs_setup_{true};
- bool is_in_perform_layout_{true};
- Optional<LayoutUnit> available_space_columns_;
- Optional<LayoutUnit> available_space_rows_;
+ base::Optional<LayoutUnit> available_space_columns_;
+ base::Optional<LayoutUnit> available_space_rows_;
- Optional<LayoutUnit> free_space_columns_;
- Optional<LayoutUnit> free_space_rows_;
+ base::Optional<LayoutUnit> free_space_columns_;
+ base::Optional<LayoutUnit> free_space_rows_;
// We need to keep both alive in order to properly size grids with orthogonal
// writing modes.
@@ -243,16 +243,16 @@ class GridTrackSizingAlgorithmStrategy {
public:
virtual ~GridTrackSizingAlgorithmStrategy();
- LayoutUnit MinContentForChild(LayoutBox&) const;
- LayoutUnit MaxContentForChild(LayoutBox&) const;
+ virtual LayoutUnit MinContentForChild(LayoutBox&) const;
+ virtual LayoutUnit MaxContentForChild(LayoutBox&) const;
LayoutUnit MinSizeForChild(LayoutBox&) const;
virtual void MaximizeTracks(Vector<GridTrack>&,
- Optional<LayoutUnit>& free_space) = 0;
+ base::Optional<LayoutUnit>& free_space) = 0;
virtual double FindUsedFlexFraction(
Vector<size_t>& flexible_sized_tracks_index,
GridTrackSizingDirection,
- Optional<LayoutUnit> initial_free_space) const = 0;
+ base::Optional<LayoutUnit> initial_free_space) const = 0;
virtual bool RecomputeUsedFlexFractionIfNeeded(
Vector<size_t>& flexible_sized_tracks_index,
double& flex_fraction,
@@ -276,10 +276,11 @@ class GridTrackSizingAlgorithmStrategy {
bool UpdateOverrideContainingBlockContentSizeForChild(
LayoutBox&,
GridTrackSizingDirection,
- Optional<LayoutUnit> = WTF::nullopt) const;
+ base::Optional<LayoutUnit> = base::nullopt) const;
LayoutUnit ComputeTrackBasedSize() const;
- Optional<LayoutUnit> ExtentForBaselineAlignment(const LayoutBox& child) const;
+ base::Optional<LayoutUnit> ExtentForBaselineAlignment(
+ const LayoutBox& child) const;
GridTrackSizingDirection Direction() const { return algorithm_.direction_; }
double FindFrUnitSize(const GridSpan& tracks_span,
@@ -287,18 +288,11 @@ class GridTrackSizingAlgorithmStrategy {
void DistributeSpaceToTracks(Vector<GridTrack*>& tracks,
LayoutUnit& available_logical_space) const;
const LayoutGrid* GetLayoutGrid() const { return algorithm_.layout_grid_; }
- Optional<LayoutUnit> AvailableSpace() const {
+ base::Optional<LayoutUnit> AvailableSpace() const {
return algorithm_.AvailableSpace();
}
- void SetNeedsLayoutForChild(LayoutBox&) const;
// Helper functions
- static bool HasOverrideContainingBlockContentSizeForChild(
- const LayoutBox& child,
- GridTrackSizingDirection);
- static LayoutUnit OverrideContainingBlockContentSizeForChild(
- const LayoutBox& child,
- GridTrackSizingDirection);
static bool ShouldClearOverrideContainingBlockContentSizeForChild(
const LayoutGrid&,
const LayoutBox& child,
@@ -307,10 +301,6 @@ class GridTrackSizingAlgorithmStrategy {
LayoutBox& child,
GridTrackSizingDirection,
LayoutUnit size);
- static GridTrackSizingDirection FlowAwareDirectionForChild(
- const LayoutGrid*,
- const LayoutBox& child,
- GridTrackSizingDirection);
GridTrackSizingAlgorithm& algorithm_;
diff --git a/chromium/third_party/blink/renderer/core/layout/hit_test_request.h b/chromium/third_party/blink/renderer/core/layout/hit_test_request.h
index b7b41677e1f..e7626ce8bb2 100644
--- a/chromium/third_party/blink/renderer/core/layout/hit_test_request.h
+++ b/chromium/third_party/blink/renderer/core/layout/hit_test_request.h
@@ -28,6 +28,8 @@
namespace blink {
+class LayoutObject;
+
class HitTestRequest {
DISALLOW_NEW();
@@ -54,8 +56,9 @@ class HitTestRequest {
typedef unsigned HitTestRequestType;
- HitTestRequest(HitTestRequestType request_type)
- : request_type_(request_type) {
+ HitTestRequest(HitTestRequestType request_type,
+ const LayoutObject* stop_node = nullptr)
+ : request_type_(request_type), stop_node_(stop_node) {
// Penetrating lists should also be list-based.
DCHECK(!(request_type & kPenetratingList) || (request_type & kListBased));
}
@@ -84,6 +87,7 @@ class HitTestRequest {
bool TouchMove() const { return Move() && TouchEvent(); }
HitTestRequestType GetType() const { return request_type_; }
+ const LayoutObject* GetStopNode() const { return stop_node_; }
// The Cacheability bits don't affect hit testing computation.
// TODO(dtapuska): These bits really shouldn't be fields on the HitTestRequest
@@ -93,11 +97,14 @@ class HitTestRequest {
kReadOnly | kActive | kMove | kRelease | kTouchEvent;
bool EqualForCacheability(const HitTestRequest& value) const {
return (request_type_ | kCacheabilityBits) ==
- (value.request_type_ | kCacheabilityBits);
+ (value.request_type_ | kCacheabilityBits) &&
+ stop_node_ == value.stop_node_;
}
private:
HitTestRequestType request_type_;
+ // If non-null, do not hit test the children of this object.
+ const LayoutObject* stop_node_;
};
} // namespace blink
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 3a3d4859ffd..2a15d5471d7 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
@@ -252,7 +252,7 @@ String HitTestResult::Title(TextDirection& dir) const {
// For <area> tags in image maps, walk the tree for the <area>, not the <img>
// using it.
if (inner_node_.Get())
- inner_node_->UpdateDistribution();
+ inner_node_->UpdateDistributionForFlatTreeTraversal();
for (Node* title_node = inner_node_.Get(); title_node;
title_node = FlatTreeTraversal::Parent(*title_node)) {
if (title_node->IsElementNode()) {
diff --git a/chromium/third_party/blink/renderer/core/layout/intersection_geometry.cc b/chromium/third_party/blink/renderer/core/layout/intersection_geometry.cc
index 71e2985900e..c1e890d17fc 100644
--- a/chromium/third_party/blink/renderer/core/layout/intersection_geometry.cc
+++ b/chromium/third_party/blink/renderer/core/layout/intersection_geometry.cc
@@ -113,14 +113,9 @@ void IntersectionGeometry::InitializeTargetRect() {
}
void IntersectionGeometry::InitializeRootRect() {
- if (root_->IsLayoutView() &&
- !RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
- root_rect_ = LayoutRect(root_->GetFrameView()->VisibleContentRect());
- root_->MapToVisualRectInAncestorSpace(nullptr, root_rect_);
- } else if (root_->IsLayoutView() && root_->GetDocument().IsInMainFrame()) {
- // The main frame is a bit special (even after RLS) as the scrolling
- // viewport can differ in size from the LayoutView itself. There's two
- // situations this occurs in:
+ if (root_->IsLayoutView() && root_->GetDocument().IsInMainFrame()) {
+ // The main frame is a bit special as the scrolling viewport can differ in
+ // size from the LayoutView itself. There's two situations this occurs in:
// 1) The ForceZeroLayoutHeight quirk setting is used in Android WebView for
// compatibility and sets the initial-containing-block's (a.k.a.
// LayoutView) height to 0. Thus, we can't use its size for intersection
@@ -160,8 +155,12 @@ void IntersectionGeometry::ClipToRoot() {
LayoutBox* local_ancestor = nullptr;
if (!RootIsImplicit() || root_->GetDocument().IsInMainFrame())
local_ancestor = ToLayoutBox(root_);
+ VisualRectFlags flags = static_cast<VisualRectFlags>(
+ RuntimeEnabledFeatures::IntersectionObserverGeometryMapperEnabled()
+ ? (kUseGeometryMapper | kEdgeInclusive)
+ : kEdgeInclusive);
does_intersect_ = target_->MapToVisualRectInAncestorSpace(
- local_ancestor, intersection_rect_, kEdgeInclusive);
+ local_ancestor, intersection_rect_, flags);
if (!does_intersect_ || !local_ancestor)
return;
if (local_ancestor->HasOverflowClip())
diff --git a/chromium/third_party/blink/renderer/core/layout/jank_tracker.cc b/chromium/third_party/blink/renderer/core/layout/jank_tracker.cc
new file mode 100644
index 00000000000..3bb95502bab
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/jank_tracker.cc
@@ -0,0 +1,161 @@
+// 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/jank_tracker.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/location.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
+#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
+
+namespace blink {
+
+static const float kTimerDelay = 3.0;
+
+static FloatPoint LogicalStart(const FloatRect& rect,
+ const LayoutObject& object) {
+ const ComputedStyle* style = object.Style();
+ DCHECK(style);
+ auto logical =
+ PhysicalToLogical<float>(style->GetWritingMode(), style->Direction(),
+ rect.Y(), rect.MaxX(), rect.MaxY(), rect.X());
+ return FloatPoint(logical.InlineStart(), logical.BlockStart());
+}
+
+static 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()));
+}
+
+JankTracker::JankTracker(LocalFrameView* frame_view)
+ : frame_view_(frame_view),
+ score_(0.0),
+ timer_(frame_view->GetFrame().GetTaskRunner(TaskType::kInternalDefault),
+ this,
+ &JankTracker::TimerFired),
+ has_fired_(false),
+ max_distance_(0.0) {}
+
+void JankTracker::NotifyObjectPrePaint(const LayoutObject& object,
+ const LayoutRect& old_visual_rect,
+ const PaintLayer& painting_layer) {
+ if (!IsActive())
+ return;
+
+ LayoutRect new_visual_rect = object.FirstFragment().VisualRect();
+ if (old_visual_rect.IsEmpty() || new_visual_rect.IsEmpty())
+ return;
+
+ if (LogicalStart(FloatRect(old_visual_rect), object) ==
+ LogicalStart(FloatRect(new_visual_rect), object))
+ return;
+
+ const auto* local_transform = painting_layer.GetLayoutObject()
+ .FirstFragment()
+ .LocalBorderBoxProperties()
+ .Transform();
+ const auto* ancestor_transform = painting_layer.GetLayoutObject()
+ .View()
+ ->FirstFragment()
+ .LocalBorderBoxProperties()
+ .Transform();
+
+ FloatRect old_visual_rect_abs = FloatRect(old_visual_rect);
+ GeometryMapper::SourceToDestinationRect(local_transform, ancestor_transform,
+ old_visual_rect_abs);
+
+ FloatRect new_visual_rect_abs = FloatRect(new_visual_rect);
+ GeometryMapper::SourceToDestinationRect(local_transform, ancestor_transform,
+ new_visual_rect_abs);
+
+ // TOOD(crbug.com/842282): Consider tracking a separate jank score for each
+ // transform space to avoid these local-to-absolute conversions, once we have
+ // a better idea of how to aggregate multiple scores for a page.
+ // See review thread of http://crrev.com/c/1046155 for more details.
+
+ IntRect viewport = frame_view_->GetScrollableArea()->VisibleContentRect();
+ if (!old_visual_rect_abs.Intersects(viewport) &&
+ !new_visual_rect_abs.Intersects(viewport))
+ return;
+
+ DVLOG(2) << object.DebugName() << " moved from "
+ << old_visual_rect_abs.ToString() << " to "
+ << new_visual_rect_abs.ToString();
+
+ max_distance_ = std::max(
+ max_distance_,
+ GetMoveDistance(old_visual_rect_abs, new_visual_rect_abs, object));
+
+ IntRect visible_old_visual_rect = RoundedIntRect(old_visual_rect_abs);
+ visible_old_visual_rect.Intersect(viewport);
+
+ IntRect visible_new_visual_rect = RoundedIntRect(new_visual_rect_abs);
+ visible_new_visual_rect.Intersect(viewport);
+
+ region_.Unite(Region(visible_old_visual_rect));
+ region_.Unite(Region(visible_new_visual_rect));
+}
+
+void JankTracker::NotifyPrePaintFinished() {
+ if (!IsActive())
+ return;
+
+ if (region_.IsEmpty()) {
+ if (!timer_.IsActive())
+ timer_.StartOneShot(kTimerDelay, FROM_HERE);
+ return;
+ }
+
+ IntRect viewport = frame_view_->GetScrollableArea()->VisibleContentRect();
+ double viewport_area = double(viewport.Width()) * double(viewport.Height());
+
+ double jank_fraction = region_.Area() / viewport_area;
+ score_ += jank_fraction;
+
+ DVLOG(1) << "viewport " << (jank_fraction * 100)
+ << "% janked, raising score to " << score_;
+
+ TRACE_EVENT_INSTANT1("blink", "FrameLayoutJank", TRACE_EVENT_SCOPE_THREAD,
+ "viewportFraction", jank_fraction);
+
+ region_ = Region();
+
+ // This cancels any previously scheduled task from the same timer.
+ timer_.StartOneShot(kTimerDelay, FROM_HERE);
+}
+
+bool JankTracker::IsActive() {
+ // This eliminates noise from the private Page object created by
+ // SVGImage::DataChanged.
+ if (frame_view_->GetFrame().GetChromeClient().IsSVGImageChromeClient())
+ return false;
+
+ if (has_fired_)
+ return false;
+ return true;
+}
+
+void JankTracker::TimerFired(TimerBase* timer) {
+ has_fired_ = true;
+
+ // TODO(skobes): Aggregate jank scores from iframes.
+ if (!frame_view_->GetFrame().IsMainFrame())
+ return;
+
+ DVLOG(1) << "final jank score for "
+ << frame_view_->GetFrame().DomWindow()->location()->toString()
+ << " is " << score_ << " with max move distance of "
+ << max_distance_;
+
+ TRACE_EVENT_INSTANT2("blink", "TotalLayoutJank", TRACE_EVENT_SCOPE_THREAD,
+ "score", score_, "maxDistance", max_distance_);
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/jank_tracker.h b/chromium/third_party/blink/renderer/core/layout/jank_tracker.h
new file mode 100644
index 00000000000..ee8a533d9a5
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/jank_tracker.h
@@ -0,0 +1,58 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_JANK_TRACKER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_JANK_TRACKER_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/geometry/region.h"
+#include "third_party/blink/renderer/platform/timer.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+
+namespace blink {
+
+class LayoutObject;
+class LayoutRect;
+class LocalFrameView;
+class PaintLayer;
+
+// Tracks "jank" from layout objects changing their visual location between
+// animation frames.
+class CORE_EXPORT JankTracker {
+ DISALLOW_NEW();
+
+ public:
+ JankTracker(LocalFrameView*);
+ ~JankTracker() {}
+ void NotifyObjectPrePaint(const LayoutObject& object,
+ const LayoutRect& old_visual_rect,
+ const PaintLayer& painting_layer);
+ void NotifyPrePaintFinished();
+ bool IsActive();
+ double Score() const { return score_; }
+ float MaxDistance() const { return max_distance_; }
+
+ private:
+ void TimerFired(TimerBase*);
+
+ // This owns us.
+ UntracedMember<LocalFrameView> frame_view_;
+
+ // The global jank score.
+ double score_;
+
+ // The per-frame jank region.
+ Region region_;
+
+ // Timer that fires the first time we've had no layout jank for a few seconds.
+ TaskRunnerTimer<JankTracker> timer_;
+ bool has_fired_;
+
+ // The maximum distance any layout object has moved in any frame.
+ float max_distance_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_JANK_TRACKER_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/jank_tracker_test.cc b/chromium/third_party/blink/renderer/core/layout/jank_tracker_test.cc
new file mode 100644
index 00000000000..bf258a2d320
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/jank_tracker_test.cc
@@ -0,0 +1,68 @@
+// 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/jank_tracker.h"
+
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+
+namespace blink {
+
+class JankTrackerTest : public RenderingTest {
+ protected:
+ LocalFrameView& GetFrameView() { return *GetFrame().View(); }
+ JankTracker& GetJankTracker() { return GetFrameView().GetJankTracker(); }
+};
+
+TEST_F(JankTrackerTest, SimpleBlockMovement) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #j { position: relative; width: 300px; height: 100px; }
+ </style>
+ <div id='j'></div>
+ )HTML");
+
+ EXPECT_EQ(0.0, GetJankTracker().Score());
+ EXPECT_EQ(0.0, GetJankTracker().MaxDistance());
+
+ GetDocument().getElementById("j")->setAttribute(HTMLNames::styleAttr,
+ AtomicString("top: 60px"));
+ GetFrameView().UpdateAllLifecyclePhases();
+ // 300 * (100 + 60) / (default viewport size 800 * 600)
+ EXPECT_FLOAT_EQ(0.1, GetJankTracker().Score());
+ EXPECT_FLOAT_EQ(60.0, GetJankTracker().MaxDistance());
+}
+
+TEST_F(JankTrackerTest, Transform) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body { margin: 0; }
+ #c { transform: translateX(-300px) translateY(-40px); }
+ #j { position: relative; width: 600px; height: 140px; }
+ </style>
+ <div id='c'>
+ <div id='j'></div>
+ </div>
+ )HTML");
+
+ GetDocument().getElementById("j")->setAttribute(HTMLNames::styleAttr,
+ AtomicString("top: 60px"));
+ GetFrameView().UpdateAllLifecyclePhases();
+ // (600 - 300) * (140 - 40 + 60) / (default viewport size 800 * 600)
+ EXPECT_FLOAT_EQ(0.1, GetJankTracker().Score());
+}
+
+TEST_F(JankTrackerTest, RtlDistance) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ #j { position: relative; width: 100px; height: 100px; direction: rtl; }
+ </style>
+ <div id='j'></div>
+ )HTML");
+ GetDocument().getElementById("j")->setAttribute(
+ HTMLNames::styleAttr, AtomicString("width: 70px; left: 10px"));
+ GetFrameView().UpdateAllLifecyclePhases();
+ EXPECT_FLOAT_EQ(20.0, GetJankTracker().MaxDistance());
+}
+
+} // namespace blink
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 3171762e48a..c39c3d143a4 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block.cc
@@ -36,6 +36,7 @@
#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"
+#include "third_party/blink/renderer/core/editing/text_affinity.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_marquee_element.h"
@@ -157,12 +158,12 @@ void LayoutBlock::StyleWillChange(StyleDifference diff,
if (old_style && Parent()) {
bool old_style_contains_fixed_position =
- old_style->CanContainFixedPositionObjects();
+ old_style->CanContainFixedPositionObjects(IsDocumentElement());
bool old_style_contains_absolute_position =
old_style_contains_fixed_position ||
old_style->CanContainAbsolutePositionObjects();
bool new_style_contains_fixed_position =
- new_style.CanContainFixedPositionObjects();
+ new_style.CanContainFixedPositionObjects(IsDocumentElement());
bool new_style_contains_absolute_position =
new_style_contains_fixed_position ||
new_style.CanContainAbsolutePositionObjects();
@@ -256,9 +257,9 @@ void LayoutBlock::StyleDidChange(StyleDifference diff,
// text control. So just make sure this is the case. Finally, computed style
// may turn us into a container of all things, e.g. if the element is
// transformed, or contain:paint is specified.
- SetCanContainFixedPositionObjects(IsLayoutView() || IsSVGForeignObject() ||
- IsTextControl() ||
- new_style.CanContainFixedPositionObjects());
+ SetCanContainFixedPositionObjects(
+ IsLayoutView() || IsSVGForeignObject() || IsTextControl() ||
+ new_style.CanContainFixedPositionObjects(IsDocumentElement()));
// It's possible for our border/padding to change, but for the overall logical
// width or height of the block to end up being the same. We keep track of
@@ -418,9 +419,6 @@ void LayoutBlock::RemoveLeftoverAnonymousBlock(LayoutBlock* child) {
void LayoutBlock::UpdateAfterLayout() {
InvalidateStickyConstraints();
- if (RuntimeEnabledFeatures::ImplicitRootScrollerEnabled() && GetNode())
- GetDocument().GetRootScrollerController().ConsiderForImplicit(*GetNode());
-
LayoutBox::UpdateAfterLayout();
}
@@ -928,7 +926,7 @@ void LayoutBlock::InsertPositionedObject(LayoutBox* o) {
DCHECK(!IsAnonymousBlock());
DCHECK_EQ(o->ContainingBlock(), this);
- o->ClearContainingBlockOverrideSize();
+ o->ClearOverrideContainingBlockContentSize();
if (g_positioned_container_map) {
auto container_map_it = g_positioned_container_map->find(o);
@@ -1257,10 +1255,15 @@ PositionWithAffinity LayoutBlock::PositionForPointIfOutsideAtomicInlineLevel(
LayoutUnit point_logical_top =
IsHorizontalWritingMode() ? point.Y() : point.X();
- if (point_logical_left < 0)
- return CreatePositionWithAffinity(CaretMinOffset());
- if (point_logical_left >= LogicalWidth())
- return CreatePositionWithAffinity(CaretMaxOffset());
+ const bool is_ltr = IsLtr(ResolvedDirection());
+ if (point_logical_left < 0) {
+ return CreatePositionWithAffinity(is_ltr ? CaretMinOffset()
+ : CaretMaxOffset());
+ }
+ if (point_logical_left >= LogicalWidth()) {
+ return CreatePositionWithAffinity(is_ltr ? CaretMaxOffset()
+ : CaretMinOffset());
+ }
if (point_logical_top < 0)
return CreatePositionWithAffinity(CaretMinOffset());
if (point_logical_top >= LogicalHeight())
@@ -1469,17 +1472,17 @@ void LayoutBlock::ComputeBlockPreferredLogicalWidths(
child->SetPreferredLogicalWidthsDirty();
}
- const ComputedStyle& child_style = child->StyleRef();
+ scoped_refptr<const ComputedStyle> child_style = child->Style();
if (child->IsFloating() ||
(child->IsBox() && ToLayoutBox(child)->AvoidsFloats())) {
LayoutUnit float_total_width = float_left_width + float_right_width;
- if (child_style.Clear() == EClear::kBoth ||
- child_style.Clear() == EClear::kLeft) {
+ if (child_style->Clear() == EClear::kBoth ||
+ child_style->Clear() == EClear::kLeft) {
max_logical_width = std::max(float_total_width, max_logical_width);
float_left_width = LayoutUnit();
}
- if (child_style.Clear() == EClear::kBoth ||
- child_style.Clear() == EClear::kRight) {
+ if (child_style->Clear() == EClear::kBoth ||
+ child_style->Clear() == EClear::kRight) {
max_logical_width = std::max(float_total_width, max_logical_width);
float_right_width = LayoutUnit();
}
@@ -1489,8 +1492,8 @@ void LayoutBlock::ComputeBlockPreferredLogicalWidths(
// (variable).
// Auto and percentage margins simply become 0 when computing min/max width.
// Fixed margins can be added in as is.
- Length start_margin_length = child_style.MarginStartUsing(style_to_use);
- Length end_margin_length = child_style.MarginEndUsing(style_to_use);
+ Length start_margin_length = child_style->MarginStartUsing(style_to_use);
+ Length end_margin_length = child_style->MarginEndUsing(style_to_use);
LayoutUnit margin;
LayoutUnit margin_start;
LayoutUnit margin_end;
@@ -1544,7 +1547,7 @@ void LayoutBlock::ComputeBlockPreferredLogicalWidths(
}
if (child->IsFloating()) {
- if (child_style.Floating() == EFloat::kLeft)
+ if (child_style->Floating() == EFloat::kLeft)
float_left_width += w;
else
float_right_width += w;
@@ -2145,15 +2148,15 @@ LayoutUnit LayoutBlock::AvailableLogicalHeightForPercentageComputation() const {
(!style.LogicalTop().IsAuto() && !style.LogicalBottom().IsAuto()));
LayoutUnit stretched_flex_height(-1);
- if (IsFlexItem())
- stretched_flex_height =
- ToLayoutFlexibleBox(Parent())
- ->ChildLogicalHeightForPercentageResolution(*this);
-
+ if (IsFlexItem()) {
+ const LayoutFlexibleBox* flex_box = ToLayoutFlexibleBox(Parent());
+ if (flex_box->UseOverrideLogicalHeightForPerentageResolution(*this))
+ stretched_flex_height = OverrideContentLogicalHeight();
+ }
if (stretched_flex_height != LayoutUnit(-1)) {
available_height = stretched_flex_height;
- } else if (IsGridItem() && HasOverrideLogicalContentHeight()) {
- available_height = OverrideLogicalContentHeight();
+ } else if (IsGridItem() && HasOverrideLogicalHeight()) {
+ available_height = OverrideContentLogicalHeight();
} else if (style.LogicalHeight().IsFixed()) {
LayoutUnit content_box_height = AdjustContentBoxLogicalHeightForBoxSizing(
style.LogicalHeight().Value());
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 6d0383c5579..b37858d572a 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_block.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_block.h
@@ -452,6 +452,11 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
bool NeedsPreferredWidthsRecalculation() const override;
+ bool IsInSelfHitTestingPhase(HitTestAction hit_test_action) const final {
+ return hit_test_action == kHitTestBlockBackground ||
+ hit_test_action == kHitTestChildBlockBackground;
+ }
+
private:
LayoutObjectChildList* VirtualChildren() final { return Children(); }
const LayoutObjectChildList* VirtualChildren() const final {
@@ -468,11 +473,6 @@ class CORE_EXPORT LayoutBlock : public LayoutBox {
// Returns true if the positioned movement-only layout succeeded.
bool TryLayoutDoingPositionedMovementOnly();
- bool IsInSelfHitTestingPhase(HitTestAction hit_test_action) const final {
- return hit_test_action == kHitTestBlockBackground ||
- hit_test_action == kHitTestChildBlockBackground;
- }
-
bool IsPointInOverflowControl(HitTestResult&,
const LayoutPoint& location_in_container,
const LayoutPoint& accumulated_offset) const;
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 3b53d9da415..4d707008deb 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
@@ -51,13 +51,17 @@
#include "third_party/blink/renderer/core/layout/line/inline_iterator.h"
#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
#include "third_party/blink/renderer/core/layout/line/line_width.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_box_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_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.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/paint/block_flow_paint_invalidator.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -2512,6 +2516,10 @@ scoped_refptr<NGLayoutResult> LayoutBlockFlow::CachedLayoutResult(
return nullptr;
}
+const NGConstraintSpace* LayoutBlockFlow::CachedConstraintSpace() const {
+ return nullptr;
+}
+
scoped_refptr<NGLayoutResult> LayoutBlockFlow::CachedLayoutResultForTesting() {
return nullptr;
}
@@ -2523,11 +2531,6 @@ void LayoutBlockFlow::SetCachedLayoutResult(const NGConstraintSpace&,
void LayoutBlockFlow::SetPaintFragment(
scoped_refptr<const NGPhysicalFragment>) {}
-Vector<NGPaintFragment*> LayoutBlockFlow::GetPaintFragments(
- const LayoutObject&) const {
- return Vector<NGPaintFragment*>();
-}
-
void LayoutBlockFlow::ComputeOverflow(LayoutUnit old_client_after_edge,
bool recompute_floats) {
LayoutBlock::ComputeOverflow(old_client_after_edge, recompute_floats);
@@ -2664,6 +2667,19 @@ LayoutUnit LayoutBlockFlow::FirstLineBoxBaseline() const {
return FirstLineBox()->LogicalTop() +
font_data->GetFontMetrics().Ascent(FirstRootBox()->BaselineType());
}
+ if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ if (const NGPaintFragment* paint_fragment = PaintFragment()) {
+ NGBoxFragment box_fragment(
+ StyleRef().GetWritingMode(),
+ ToNGPhysicalBoxFragment(paint_fragment->PhysicalFragment()));
+ NGLineHeightMetrics metrics =
+ box_fragment.BaselineMetricsWithoutSynthesize(
+ {NGBaselineAlgorithmType::kFirstLine,
+ StyleRef().GetFontBaseline()});
+ if (!metrics.IsEmpty())
+ return metrics.ascent;
+ }
+ }
return LayoutUnit(-1);
}
@@ -4767,10 +4783,12 @@ PositionWithAffinity LayoutBlockFlow::PositionForPoint(
// We hit this case for Mac behavior when the Y coordinate is below the last
// box.
DCHECK(move_caret_to_boundary);
- InlineBox* logically_last_box;
- if (last_root_box_with_children->GetLogicalEndBoxWithNode(
- logically_last_box))
- return PositionWithAffinity(PositionForBox(logically_last_box, false));
+ if (const InlineBox* logically_last_box =
+ last_root_box_with_children->GetLogicalEndNonPseudoBox()) {
+ // TODO(layout-dev): Change |PositionForBox()| to take |const InlineBox*|.
+ return PositionWithAffinity(
+ PositionForBox(const_cast<InlineBox*>(logically_last_box), false));
+ }
}
// Can't reach this. We have a root line box, but it has no kids.
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 5eeb9a9defd..6b0832a038b 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
@@ -450,14 +450,15 @@ class CORE_EXPORT LayoutBlockFlow : public LayoutBlock {
// still working on LayoutNG.
void AddOverflowFromFloats();
+ virtual NGInlineNodeData* TakeNGInlineNodeData() { return nullptr; }
virtual NGInlineNodeData* GetNGInlineNodeData() const { return nullptr; }
virtual void ResetNGInlineNodeData() {}
virtual bool HasNGInlineNodeData() const { return false; }
virtual NGPaintFragment* PaintFragment() const { return nullptr; }
- virtual Vector<NGPaintFragment*> GetPaintFragments(const LayoutObject&) const;
virtual scoped_refptr<NGLayoutResult> CachedLayoutResult(
const NGConstraintSpace&,
NGBreakToken*) const;
+ virtual const NGConstraintSpace* CachedConstraintSpace() const;
virtual scoped_refptr<NGLayoutResult> CachedLayoutResultForTesting();
virtual void SetCachedLayoutResult(const NGConstraintSpace&,
NGBreakToken*,
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 8516d623408..9d80ecffbf2 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/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"
#include "third_party/blink/renderer/platform/text/bidi_resolver.h"
#include "third_party/blink/renderer/platform/text/character.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -2654,6 +2655,8 @@ void LayoutBlockFlow::SetShouldDoFullPaintInvalidationForFirstLine() {
DCHECK(ChildrenInline());
if (RootInlineBox* first_root_box = FirstRootBox())
first_root_box->SetShouldDoFullPaintInvalidationRecursively();
+ else if (NGPaintFragment* paint_fragment = PaintFragment())
+ paint_fragment->SetShouldDoFullPaintInvalidationForFirstLine();
}
bool LayoutBlockFlow::PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
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 4f724b59448..d56be3429c1 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box.cc
@@ -66,10 +66,12 @@
#include "third_party/blink/renderer/core/page/scrolling/root_scroller_util.h"
#include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
#include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
+#include "third_party/blink/renderer/core/paint/adjust_paint_offset_scope.h"
#include "third_party/blink/renderer/core/paint/background_image_geometry.h"
#include "third_party/blink/renderer/core/paint/box_paint_invalidator.h"
#include "third_party/blink/renderer/core/paint/box_painter.h"
#include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/style/shadow_list.h"
#include "third_party/blink/renderer/platform/geometry/double_rect.h"
@@ -127,7 +129,7 @@ PaintLayerType LayoutBox::LayerTypeRequired() const {
void LayoutBox::WillBeDestroyed() {
ClearOverrideSize();
- ClearContainingBlockOverrideSize();
+ ClearOverrideContainingBlockContentSize();
if (IsOutOfFlowPositioned())
LayoutBlock::RemovePositionedObject(this);
@@ -198,10 +200,6 @@ void LayoutBox::StyleWillChange(StyleDifference diff,
if ((diff.NeedsFullPaintInvalidation() || diff.NeedsLayout()) &&
GetNode() && (IsDocumentElement() || IsHTMLBodyElement(*GetNode()))) {
View()->SetShouldDoFullPaintInvalidation();
-
- if (old_style->HasEntirelyFixedBackground() !=
- new_style.HasEntirelyFixedBackground())
- View()->Compositor()->SetNeedsUpdateFixedBackground();
}
// When a layout hint happens and an object's position style changes, we
@@ -686,7 +684,7 @@ LayoutRect LayoutBox::ScrollRectToVisibleRecursive(
// end of the IPC call.
HTMLFrameOwnerElement* owner_element = GetDocument().LocalOwner();
if (owner_element && owner_element->GetLayoutObject() &&
- GetFrameView()->SafeToPropagateScrollToParent()) {
+ AllowedToPropageRecursiveScrollToParentFrame(params)) {
parent_box = owner_element->GetLayoutObject()->EnclosingBox();
LayoutView* parent_view = owner_element->GetLayoutObject()->View();
absolute_rect_for_parent = EnclosingLayoutRect(
@@ -709,7 +707,7 @@ LayoutRect LayoutBox::ScrollRectToVisibleRecursive(
return parent_box->ScrollRectToVisibleRecursive(absolute_rect_for_parent,
params);
} else if (GetFrame()->IsLocalRoot() && !GetFrame()->IsMainFrame()) {
- if (GetFrameView()->SafeToPropagateScrollToParent()) {
+ if (AllowedToPropageRecursiveScrollToParentFrame(params)) {
GetFrameView()->ScrollRectToVisibleInRemoteParent(
absolute_rect_for_parent, params);
}
@@ -879,7 +877,7 @@ LayoutRect LayoutBox::BackgroundRect(BackgroundRectType rect_type) const {
const FillLayer* cur = current;
current = current->Next();
if (rect_type == kBackgroundKnownOpaqueRect) {
- if (cur->BlendMode() != WebBlendMode::kNormal ||
+ if (cur->GetBlendMode() != BlendMode::kNormal ||
cur->Composite() != kCompositeSourceOver)
continue;
@@ -998,17 +996,6 @@ LayoutUnit LayoutBox::VerticalScrollbarWidthClampedToContentBox() const {
return width;
}
-ScrollResult LayoutBox::Scroll(ScrollGranularity granularity,
- const FloatSize& delta) {
- // Presumably the same issue as in setScrollTop. See crbug.com/343132.
- DisableCompositingQueryAsserts disabler;
-
- if (!GetScrollableArea())
- return ScrollResult();
-
- return GetScrollableArea()->UserScroll(granularity, delta);
-}
-
bool LayoutBox::CanBeScrolledAndHasScrollableArea() const {
return CanBeProgramaticallyScrolled() &&
(PixelSnappedScrollHeight() != PixelSnappedClientHeight() ||
@@ -1070,19 +1057,12 @@ IntSize LayoutBox::CalculateAutoscrollDirection(
if (!frame_view)
return IntSize();
- LayoutRect absolute_scrolling_box;
+ LayoutRect absolute_scrolling_box = LayoutRect(AbsoluteBoundingBoxRect());
- if (!RuntimeEnabledFeatures::RootLayerScrollingEnabled() && IsLayoutView()) {
- absolute_scrolling_box =
- LayoutRect(frame_view->VisibleContentRect(kExcludeScrollbars));
- } else {
- absolute_scrolling_box = LayoutRect(AbsoluteBoundingBoxRect());
-
- // Exclude scrollbars so the border belt (activation area) starts from the
- // scrollbar-content edge rather than the window edge.
- ExcludeScrollbars(absolute_scrolling_box,
- kExcludeOverlayScrollbarSizeForHitTesting);
- }
+ // Exclude scrollbars so the border belt (activation area) starts from the
+ // scrollbar-content edge rather than the window edge.
+ ExcludeScrollbars(absolute_scrolling_box,
+ kExcludeOverlayScrollbarSizeForHitTesting);
IntRect belt_box = View()->GetFrameView()->AbsoluteToRootFrame(
PixelSnappedIntRect(absolute_scrolling_box));
@@ -1387,73 +1367,85 @@ LayoutUnit LayoutBox::MaxPreferredLogicalWidth() const {
return max_preferred_logical_width_;
}
-bool LayoutBox::HasOverrideLogicalContentHeight() const {
- return rare_data_ && rare_data_->override_logical_content_height_ != -1;
+LayoutUnit LayoutBox::OverrideLogicalWidth() const {
+ DCHECK(HasOverrideLogicalWidth());
+ return rare_data_->override_logical_width_;
+}
+
+LayoutUnit LayoutBox::OverrideLogicalHeight() const {
+ DCHECK(HasOverrideLogicalHeight());
+ return rare_data_->override_logical_height_;
+}
+
+bool LayoutBox::HasOverrideLogicalHeight() const {
+ return rare_data_ && rare_data_->override_logical_height_ != -1;
}
-bool LayoutBox::HasOverrideLogicalContentWidth() const {
- return rare_data_ && rare_data_->override_logical_content_width_ != -1;
+bool LayoutBox::HasOverrideLogicalWidth() const {
+ return rare_data_ && rare_data_->override_logical_width_ != -1;
}
-void LayoutBox::SetOverrideLogicalContentHeight(LayoutUnit height) {
+void LayoutBox::SetOverrideLogicalHeight(LayoutUnit height) {
DCHECK_GE(height, 0);
- EnsureRareData().override_logical_content_height_ = height;
+ EnsureRareData().override_logical_height_ = height;
}
-void LayoutBox::SetOverrideLogicalContentWidth(LayoutUnit width) {
+void LayoutBox::SetOverrideLogicalWidth(LayoutUnit width) {
DCHECK_GE(width, 0);
- EnsureRareData().override_logical_content_width_ = width;
+ EnsureRareData().override_logical_width_ = width;
}
-void LayoutBox::ClearOverrideLogicalContentHeight() {
+void LayoutBox::ClearOverrideLogicalHeight() {
if (rare_data_)
- rare_data_->override_logical_content_height_ = LayoutUnit(-1);
+ rare_data_->override_logical_height_ = LayoutUnit(-1);
}
-void LayoutBox::ClearOverrideLogicalContentWidth() {
+void LayoutBox::ClearOverrideLogicalWidth() {
if (rare_data_)
- rare_data_->override_logical_content_width_ = LayoutUnit(-1);
+ rare_data_->override_logical_width_ = LayoutUnit(-1);
}
void LayoutBox::ClearOverrideSize() {
- ClearOverrideLogicalContentHeight();
- ClearOverrideLogicalContentWidth();
+ ClearOverrideLogicalHeight();
+ ClearOverrideLogicalWidth();
}
-LayoutUnit LayoutBox::OverrideLogicalContentWidth() const {
- DCHECK(HasOverrideLogicalContentWidth());
- return rare_data_->override_logical_content_width_;
+LayoutUnit LayoutBox::OverrideContentLogicalWidth() const {
+ return (OverrideLogicalWidth() - BorderAndPaddingLogicalWidth() -
+ ScrollbarLogicalWidth())
+ .ClampNegativeToZero();
}
-LayoutUnit LayoutBox::OverrideLogicalContentHeight() const {
- DCHECK(HasOverrideLogicalContentHeight());
- return rare_data_->override_logical_content_height_;
+LayoutUnit LayoutBox::OverrideContentLogicalHeight() const {
+ return (OverrideLogicalHeight() - BorderAndPaddingLogicalHeight() -
+ ScrollbarLogicalHeight())
+ .ClampNegativeToZero();
}
// TODO (lajava) Shouldn't we implement these functions based on physical
// direction ?.
LayoutUnit LayoutBox::OverrideContainingBlockContentLogicalWidth() const {
- DCHECK(HasOverrideContainingBlockLogicalWidth());
+ DCHECK(HasOverrideContainingBlockContentLogicalWidth());
return rare_data_->override_containing_block_content_logical_width_;
}
// TODO (lajava) Shouldn't we implement these functions based on physical
// direction ?.
LayoutUnit LayoutBox::OverrideContainingBlockContentLogicalHeight() const {
- DCHECK(HasOverrideContainingBlockLogicalHeight());
+ DCHECK(HasOverrideContainingBlockContentLogicalHeight());
return rare_data_->override_containing_block_content_logical_height_;
}
// TODO (lajava) Shouldn't we implement these functions based on physical
// direction ?.
-bool LayoutBox::HasOverrideContainingBlockLogicalWidth() const {
+bool LayoutBox::HasOverrideContainingBlockContentLogicalWidth() const {
return rare_data_ &&
rare_data_->has_override_containing_block_content_logical_width_;
}
// TODO (lajava) Shouldn't we implement these functions based on physical
// direction ?.
-bool LayoutBox::HasOverrideContainingBlockLogicalHeight() const {
+bool LayoutBox::HasOverrideContainingBlockContentLogicalHeight() const {
return rare_data_ &&
rare_data_->has_override_containing_block_content_logical_height_;
}
@@ -1480,7 +1472,7 @@ void LayoutBox::SetOverrideContainingBlockContentLogicalHeight(
// TODO (lajava) Shouldn't we implement these functions based on physical
// direction ?.
-void LayoutBox::ClearContainingBlockOverrideSize() {
+void LayoutBox::ClearOverrideContainingBlockContentSize() {
if (!rare_data_)
return;
EnsureRareData().has_override_containing_block_content_logical_width_ = false;
@@ -1488,15 +1480,6 @@ void LayoutBox::ClearContainingBlockOverrideSize() {
false;
}
-// TODO (lajava) Shouldn't we implement these functions based on physical
-// direction ?.
-void LayoutBox::ClearOverrideContainingBlockContentLogicalHeight() {
- if (!rare_data_)
- return;
- EnsureRareData().has_override_containing_block_content_logical_height_ =
- false;
-}
-
LayoutUnit LayoutBox::AdjustBorderBoxLogicalWidthForBoxSizing(
float width) const {
LayoutUnit borders_plus_padding = CollapsedBorderAndCSSPaddingLogicalWidth();
@@ -1540,8 +1523,9 @@ bool LayoutBox::HitTestAllPhases(HitTestResult& result,
// If we have clipping, then we can't have any spillout.
// TODO(pdr): Why is this optimization not valid for the effective root?
if (!RootScrollerUtil::IsEffective(*this)) {
- LayoutRect overflow_box =
- HasOverflowClip() ? BorderBoxRect() : VisualOverflowRect();
+ LayoutRect overflow_box = (HasOverflowClip() || Style()->ContainsPaint())
+ ? BorderBoxRect()
+ : VisualOverflowRect();
FlipForWritingMode(overflow_box);
LayoutPoint adjusted_location = accumulated_offset + Location();
overflow_box.MoveBy(adjusted_location);
@@ -1564,8 +1548,8 @@ bool LayoutBox::NodeAtPoint(HitTestResult& result,
HitTestOverflowControl(result, location_in_container, adjusted_location))
return true;
- bool skip_children = false;
- if (ShouldClipOverflow()) {
+ bool skip_children = (result.GetHitTestRequest().GetStopNode() == this);
+ if (!skip_children && ShouldClipOverflow()) {
// PaintLayer::HitTestContentsForFragments checked the fragments'
// foreground rect for intersection if a layer is self painting,
// so only do the overflow clip check here for non-self-painting layers.
@@ -1942,16 +1926,24 @@ PaintInvalidationReason LayoutBox::InvalidatePaint(
LayoutRect LayoutBox::OverflowClipRect(
const LayoutPoint& location,
OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
- if (RootScrollerUtil::IsEffective(*this))
- return View()->ViewRect();
-
- // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
- // here.
- LayoutRect clip_rect = BorderBoxRect();
- clip_rect.SetLocation(location + clip_rect.Location() +
- LayoutSize(BorderLeft(), BorderTop()));
- clip_rect.SetSize(clip_rect.Size() -
- LayoutSize(BorderWidth(), BorderHeight()));
+ LayoutRect clip_rect;
+
+ if (RootScrollerUtil::IsEffective(*this)) {
+ // If this box is the effective root scroller, use the viewport clipping
+ // rect since it will account for the URL bar correctly which the border
+ // box does not. We can do this because the effective root scroller is
+ // restricted such that it exactly fills the viewport. See
+ // RootScrollerController::IsValidRootScroller()
+ clip_rect = LayoutRect(location, View()->ViewRect().Size());
+ } else {
+ // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the
+ // property here.
+ clip_rect = BorderBoxRect();
+ clip_rect.SetLocation(location + clip_rect.Location() +
+ LayoutSize(BorderLeft(), BorderTop()));
+ clip_rect.SetSize(clip_rect.Size() -
+ LayoutSize(BorderWidth(), BorderHeight()));
+ }
if (HasOverflowClip())
ExcludeScrollbars(clip_rect, overlay_scrollbar_clip_behavior);
@@ -2066,7 +2058,7 @@ LayoutUnit LayoutBox::ShrinkLogicalWidthToAvoidFloats(
}
LayoutUnit LayoutBox::ContainingBlockLogicalHeightForGetComputedStyle() const {
- if (HasOverrideContainingBlockLogicalHeight())
+ if (HasOverrideContainingBlockContentLogicalHeight())
return OverrideContainingBlockContentLogicalHeight();
if (!IsPositioned())
@@ -2080,7 +2072,7 @@ LayoutUnit LayoutBox::ContainingBlockLogicalHeightForGetComputedStyle() const {
}
LayoutUnit LayoutBox::ContainingBlockLogicalWidthForContent() const {
- if (HasOverrideContainingBlockLogicalWidth())
+ if (HasOverrideContainingBlockContentLogicalWidth())
return OverrideContainingBlockContentLogicalWidth();
LayoutBlock* cb = ContainingBlock();
@@ -2091,7 +2083,7 @@ LayoutUnit LayoutBox::ContainingBlockLogicalWidthForContent() const {
LayoutUnit LayoutBox::ContainingBlockLogicalHeightForContent(
AvailableLogicalHeightType height_type) const {
- if (HasOverrideContainingBlockLogicalHeight())
+ if (HasOverrideContainingBlockContentLogicalHeight())
return OverrideContainingBlockContentLogicalHeight();
LayoutBlock* cb = ContainingBlock();
@@ -2108,12 +2100,12 @@ LayoutUnit LayoutBox::ContainingBlockAvailableLineWidth() const {
}
LayoutUnit LayoutBox::PerpendicularContainingBlockLogicalHeight() const {
- if (HasOverrideContainingBlockLogicalHeight())
+ if (HasOverrideContainingBlockContentLogicalHeight())
return OverrideContainingBlockContentLogicalHeight();
LayoutBlock* cb = ContainingBlock();
- if (cb->HasOverrideLogicalContentHeight())
- return cb->OverrideLogicalContentHeight();
+ if (cb->HasOverrideLogicalHeight())
+ return cb->OverrideContentLogicalHeight();
const ComputedStyle& containing_block_style = cb->StyleRef();
Length logical_height_length = containing_block_style.LogicalHeight();
@@ -2172,7 +2164,9 @@ void LayoutBox::MapAncestorToLocal(const LayoutBoxModelObject* ancestor,
LayoutBoxModelObject::MapAncestorToLocal(ancestor, transform_state, mode);
}
-LayoutSize LayoutBox::OffsetFromContainer(const LayoutObject* o) const {
+LayoutSize LayoutBox::OffsetFromContainerInternal(
+ const LayoutObject* o,
+ bool ignore_scroll_offset) const {
DCHECK_EQ(o, Container());
LayoutSize offset;
@@ -2182,7 +2176,7 @@ LayoutSize LayoutBox::OffsetFromContainer(const LayoutObject* o) const {
offset += PhysicalLocationOffset();
if (o->HasOverflowClip())
- offset -= ToLayoutBox(o)->ScrolledContentOffset();
+ offset += OffsetFromScrollableContainer(o, ignore_scroll_offset);
if (IsOutOfFlowPositioned() && o->IsLayoutInline() &&
o->CanContainOutOfFlowPositionedElement(Style()->GetPosition())) {
@@ -2538,26 +2532,12 @@ bool LayoutBox::MapToVisualRectInAncestorSpaceInternal(
LayoutSize container_offset =
ancestor->OffsetFromAncestorContainer(container);
transform_state.Move(-container_offset, accumulation);
-
- if (!RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
- // If the ancestor is fixed, then the rect is already in its coordinates
- // so doesn't need viewport-adjusting.
- if (ancestor->Style()->GetPosition() != EPosition::kFixed &&
- container->IsLayoutView() && position == EPosition::kFixed) {
- transform_state.Move(
- ToLayoutView(container)->OffsetForFixedPosition(true),
- accumulation);
- }
- }
-
return true;
}
if (container->IsLayoutView()) {
bool use_fixed_position_adjustment =
- position == EPosition::kFixed &&
- (!RuntimeEnabledFeatures::RootLayerScrollingEnabled() ||
- container == ancestor);
+ position == EPosition::kFixed && container == ancestor;
return ToLayoutView(container)->MapToVisualRectInAncestorSpaceInternal(
ancestor, transform_state, use_fixed_position_adjustment ? kIsFixed : 0,
visual_rect_flags);
@@ -2671,9 +2651,8 @@ void LayoutBox::ComputeLogicalWidth(
// The parent box is flexing us, so it has increased or decreased our
// width. Use the width from the style context.
- if (HasOverrideLogicalContentWidth()) {
- computed_values.extent_ =
- OverrideLogicalContentWidth() + BorderAndPaddingLogicalWidth();
+ if (HasOverrideLogicalWidth()) {
+ computed_values.extent_ = OverrideLogicalWidth();
return;
}
@@ -2721,9 +2700,13 @@ void LayoutBox::ComputeLogicalWidth(
}
LayoutUnit container_width_in_inline_direction = container_logical_width;
- if (has_perpendicular_containing_block)
+ if (has_perpendicular_containing_block) {
+ // PerpendicularContainingBlockLogicalHeight() can return -1 in some
+ // situations but we cannot have a negative width, that's why we clamp it to
+ // zero.
container_width_in_inline_direction =
- PerpendicularContainingBlockLogicalHeight();
+ PerpendicularContainingBlockLogicalHeight().ClampNegativeToZero();
+ }
// Width calculations
if (treat_as_replaced) {
@@ -2987,6 +2970,9 @@ bool LayoutBox::SizesLogicalWidthToFitContent(
if (IsHorizontalWritingMode() != ContainingBlock()->IsHorizontalWritingMode())
return true;
+ if (IsCustomItem())
+ return IsCustomItemShrinkToFit();
+
return false;
}
@@ -3152,10 +3138,8 @@ void LayoutBox::ComputeLogicalHeight(
Length h;
if (IsOutOfFlowPositioned()) {
ComputePositionedLogicalHeight(computed_values);
- if (HasOverrideLogicalContentHeight()) {
- computed_values.extent_ =
- OverrideLogicalContentHeight() + BorderAndPaddingLogicalHeight();
- }
+ if (HasOverrideLogicalHeight())
+ computed_values.extent_ = OverrideLogicalHeight();
} else {
LayoutBlock* cb = ContainingBlock();
@@ -3195,10 +3179,12 @@ void LayoutBox::ComputeLogicalHeight(
// The parent box is flexing us, so it has increased or decreased our
// height. We have to grab our cached flexible height.
- if (HasOverrideLogicalContentHeight()) {
- h = Length(OverrideLogicalContentHeight(), kFixed);
+ if (HasOverrideLogicalHeight()) {
+ h = Length(OverrideLogicalHeight(), kFixed);
} else if (treat_as_replaced) {
- h = Length(ComputeReplacedLogicalHeight(), kFixed);
+ h = Length(
+ ComputeReplacedLogicalHeight() + BorderAndPaddingLogicalHeight(),
+ kFixed);
} else {
h = Style()->LogicalHeight();
check_min_max_height = true;
@@ -3209,9 +3195,9 @@ void LayoutBox::ComputeLogicalHeight(
// https://bugs.webkit.org/show_bug.cgi?id=46418
if (h.IsAuto() && in_horizontal_box &&
ToLayoutDeprecatedFlexibleBox(Parent())->IsStretchingChildren()) {
- h = Length(ParentBox()->ContentLogicalHeight() - MarginBefore() -
- MarginAfter() - BorderAndPaddingLogicalHeight(),
- kFixed);
+ h = Length(
+ ParentBox()->ContentLogicalHeight() - MarginBefore() - MarginAfter(),
+ kFixed);
check_min_max_height = false;
}
@@ -3226,11 +3212,8 @@ void LayoutBox::ComputeLogicalHeight(
height_result,
computed_values.extent_ - BorderAndPaddingLogicalHeight());
} else {
- // The only times we don't check min/max height are when a fixed length
- // has been given as an override. Just use that. The value has already
- // been adjusted for box-sizing.
DCHECK(h.IsFixed());
- height_result = LayoutUnit(h.Value()) + BorderAndPaddingLogicalHeight();
+ height_result = LayoutUnit(h.Value());
}
computed_values.extent_ = height_result;
@@ -3417,7 +3400,7 @@ LayoutUnit LayoutBox::ComputePercentageLogicalHeight(
if (IsHorizontalWritingMode() != cb->IsHorizontalWritingMode()) {
available_height =
containing_block_child->ContainingBlockLogicalWidthForContent();
- } else if (HasOverrideContainingBlockLogicalHeight()) {
+ } else if (HasOverrideContainingBlockContentLogicalHeight()) {
available_height = OverrideContainingBlockContentLogicalHeight();
} else if (cb->IsTableCell()) {
if (!skipped_auto_height_containing_block) {
@@ -3425,7 +3408,7 @@ LayoutUnit LayoutBox::ComputePercentageLogicalHeight(
// Basically we don't care if the cell specified a height or not. We just
// always make ourselves be a percentage of the cell's current content
// height.
- if (!cb->HasOverrideLogicalContentHeight()) {
+ if (!cb->HasOverrideLogicalHeight()) {
// https://drafts.csswg.org/css-tables-3/#row-layout:
// For the purpose of calculating [the minimum height of a row],
// descendants of table cells whose height depends on percentages
@@ -3441,7 +3424,9 @@ LayoutUnit LayoutBox::ComputePercentageLogicalHeight(
return LayoutUnit();
return LayoutUnit(-1);
}
- available_height = cb->OverrideLogicalContentHeight();
+ available_height = cb->OverrideLogicalHeight() -
+ cb->CollapsedBorderAndCSSPaddingLogicalHeight() -
+ cb->ScrollbarLogicalHeight();
}
} else {
available_height = cb->AvailableLogicalHeightForPercentageComputation();
@@ -3456,16 +3441,16 @@ LayoutUnit LayoutBox::ComputePercentageLogicalHeight(
available_height += cb->PaddingLogicalHeight();
LayoutUnit result = ValueForLength(height, available_height);
- // |overrideLogicalContentHeight| is the maximum height made available by the
+ // |OverrideLogicalHeight| is the maximum height made available by the
// cell to its percent height children when we decide they can determine the
// height of the cell. If the percent height child is box-sizing:content-box
// then we must subtract the border and padding from the cell's
- // |availableHeight| (given by |overrideLogicalContentHeight|) to arrive
+ // |available_height| (given by |OverrideLogicalHeight|) to arrive
// at the child's computed height.
bool subtract_border_and_padding =
IsTable() ||
(cb->IsTableCell() && !skipped_auto_height_containing_block &&
- cb->HasOverrideLogicalContentHeight() &&
+ cb->HasOverrideLogicalHeight() &&
Style()->BoxSizing() == EBoxSizing::kContentBox);
if (subtract_border_and_padding) {
result -= BorderAndPaddingLogicalHeight();
@@ -3526,13 +3511,16 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalWidthUsing(
case kFillAvailable:
case kPercent:
case kCalculated: {
- // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced
- // element's writing-mode is perpendicular to the containing block's
- // writing-mode. https://bugs.webkit.org/show_bug.cgi?id=46496
- const LayoutUnit cw = IsOutOfFlowPositioned()
- ? ContainingBlockLogicalWidthForPositioned(
- ToLayoutBoxModelObject(Container()))
- : ContainingBlockLogicalWidthForContent();
+ LayoutUnit cw;
+ if (IsOutOfFlowPositioned()) {
+ cw = ContainingBlockLogicalWidthForPositioned(
+ ToLayoutBoxModelObject(Container()));
+ } else {
+ cw = IsHorizontalWritingMode() ==
+ ContainingBlock()->IsHorizontalWritingMode()
+ ? ContainingBlockLogicalWidthForContent()
+ : PerpendicularContainingBlockLogicalHeight();
+ }
Length container_logical_width =
ContainingBlock()->Style()->LogicalWidth();
// FIXME: Handle cases when containing block width is calculated or
@@ -3621,17 +3609,21 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalHeightUsing(
IsOutOfFlowPositioned() ? Container() : ContainingBlock();
while (cb->IsAnonymous())
cb = cb->ContainingBlock();
+ bool has_perpendicular_containing_block =
+ cb->IsHorizontalWritingMode() != IsHorizontalWritingMode();
LayoutUnit stretched_height(-1);
if (cb->IsLayoutBlock()) {
LayoutBlock* block = ToLayoutBlock(cb);
block->AddPercentHeightDescendant(const_cast<LayoutBox*>(this));
- if (block->IsFlexItem())
- stretched_height =
- ToLayoutFlexibleBox(block->Parent())
- ->ChildLogicalHeightForPercentageResolution(*block);
- else if (block->IsGridItem() &&
- block->HasOverrideLogicalContentHeight())
- stretched_height = block->OverrideLogicalContentHeight();
+ if (block->IsFlexItem()) {
+ const LayoutFlexibleBox* flex_box =
+ ToLayoutFlexibleBox(block->Parent());
+ if (flex_box->UseOverrideLogicalHeightForPerentageResolution(*block))
+ stretched_height = block->OverrideContentLogicalHeight();
+ } else if (block->IsGridItem() && block->HasOverrideLogicalHeight() &&
+ !has_perpendicular_containing_block) {
+ stretched_height = block->OverrideContentLogicalHeight();
+ }
}
if (cb->IsOutOfFlowPositioned() && cb->Style()->Height().IsAuto() &&
@@ -3648,20 +3640,17 @@ LayoutUnit LayoutBox::ComputeReplacedLogicalHeightUsing(
ValueForLength(logical_height, new_content_height));
}
- // FIXME: availableLogicalHeight() is wrong if the replaced element's
- // writing-mode is perpendicular to the containing block's writing-mode.
- // https://bugs.webkit.org/show_bug.cgi?id=46496
LayoutUnit available_height;
if (IsOutOfFlowPositioned()) {
available_height = ContainingBlockLogicalHeightForPositioned(
ToLayoutBoxModelObject(cb));
} else if (stretched_height != -1) {
available_height = stretched_height;
- } else if (HasOverrideContainingBlockLogicalHeight()) {
- available_height = OverrideContainingBlockContentLogicalHeight();
} else {
- available_height =
- ContainingBlockLogicalHeightForContent(kIncludeMarginBorderPadding);
+ available_height = has_perpendicular_containing_block
+ ? ContainingBlockLogicalWidthForContent()
+ : ContainingBlockLogicalHeightForContent(
+ kIncludeMarginBorderPadding);
// It is necessary to use the border-box to match WinIE's broken
// box model. This is essential for sizing inside
// table cells using percentage heights.
@@ -3726,17 +3715,18 @@ LayoutUnit LayoutBox::AvailableLogicalHeightUsing(
// some new height, and then when we lay out again we'll use the calculation
// below.
if (IsTableCell() && (h.IsAuto() || h.IsPercentOrCalc())) {
- if (HasOverrideLogicalContentHeight())
- return OverrideLogicalContentHeight();
+ if (HasOverrideLogicalHeight()) {
+ return OverrideLogicalHeight() -
+ CollapsedBorderAndCSSPaddingLogicalHeight() -
+ ScrollbarLogicalHeight();
+ }
return LogicalHeight() - BorderAndPaddingLogicalHeight();
}
if (IsFlexItem()) {
- LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
- LayoutUnit stretched_height =
- flex_box.ChildLogicalHeightForPercentageResolution(*this);
- if (stretched_height != LayoutUnit(-1))
- return stretched_height;
+ const LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
+ if (flex_box.UseOverrideLogicalHeightForPerentageResolution(*this))
+ return OverrideContentLogicalHeight();
}
if (h.IsPercentOrCalc() && IsOutOfFlowPositioned()) {
@@ -3825,7 +3815,7 @@ LayoutUnit LayoutBox::ContainingBlockLogicalWidthForPositioned(
}
}
- if (HasOverrideContainingBlockLogicalWidth())
+ if (HasOverrideContainingBlockContentLogicalWidth())
return OverrideContainingBlockContentLogicalWidth();
// Ensure we compute our width based on the width of our rel-pos inline
@@ -3889,7 +3879,7 @@ LayoutUnit LayoutBox::ContainingBlockLogicalHeightForPositioned(
}
}
- if (HasOverrideContainingBlockLogicalHeight())
+ if (HasOverrideContainingBlockContentLogicalHeight())
return OverrideContainingBlockContentLogicalHeight();
if (containing_block->IsBox())
@@ -3998,6 +3988,12 @@ void LayoutBox::ComputeInlineStaticDistance(
LayoutUnit static_position = child->Layer()->StaticInlinePosition() +
container_logical_width +
container_block->BorderLogicalLeft();
+ if (container_block->IsBox() &&
+ ToLayoutBox(container_block)
+ ->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft()) {
+ static_position +=
+ ToLayoutBox(container_block)->OriginAdjustmentForScrollbars().Width();
+ }
for (LayoutObject* curr = child->Parent(); curr; curr = curr->Container()) {
if (curr->IsBox()) {
if (curr == enclosing_box)
@@ -5065,6 +5061,13 @@ bool LayoutBox::IsCustomItem() const {
ToLayoutCustom(Parent())->State() == LayoutCustomState::kBlock;
}
+// LayoutCustom items are only shrink-to-fit during the web-developer defined
+// layout phase (not during fallback).
+bool LayoutBox::IsCustomItemShrinkToFit() const {
+ DCHECK(IsCustomItem());
+ return ToLayoutCustom(Parent())->Phase() == LayoutCustomPhase::kCustom;
+}
+
bool LayoutBox::IsRenderedLegend() const {
if (!IsHTMLLegendElement(GetNode()))
return false;
@@ -5486,6 +5489,20 @@ LayoutPoint LayoutBox::FlipForWritingModeForChild(
point.Y());
}
+LayoutPoint LayoutBox::FlipForWritingModeForChildForPaint(
+ const LayoutBox* child,
+ const LayoutPoint& point) const {
+ // Do nothing unless in FlippedBlocks(). Fast path optimization
+ if (!Style()->IsFlippedBlocksWritingMode())
+ return point;
+ // If child will be painted by LayoutNG, and will use fragment.Offset(),
+ // flip is not needed.
+ if (!AdjustPaintOffsetScope::WillUseLegacyLocation(child))
+ return point;
+
+ return FlipForWritingModeForChild(child, point);
+}
+
LayoutBox* LayoutBox::LocationContainer() const {
// Location of a non-root SVG object derived from LayoutBox should not be
// affected by writing-mode of the containing box (SVGRoot).
@@ -5953,6 +5970,22 @@ void LayoutBox::RemoveSnapArea(const LayoutBox& snap_area) {
}
}
+bool LayoutBox::AllowedToPropageRecursiveScrollToParentFrame(
+ const WebScrollIntoViewParams& params) {
+ if (!GetFrameView()->SafeToPropagateScrollToParent())
+ return false;
+
+ if (params.GetScrollType() != kProgrammaticScroll)
+ return true;
+
+ if (!IsSupportedInFeaturePolicy(
+ mojom::FeaturePolicyFeature::kVerticalScroll)) {
+ return true;
+ }
+ return GetFrame()->IsFeatureEnabled(
+ mojom::FeaturePolicyFeature::kVerticalScroll);
+}
+
SnapAreaSet* LayoutBox::SnapAreas() const {
return rare_data_ ? rare_data_->snap_areas_.get() : nullptr;
}
@@ -6026,4 +6059,19 @@ float LayoutBox::VisualRectOutsetForRasterEffects() const {
return overflow_ && overflow_->HasSubpixelVisualEffectOutsets() ? 1 : 0;
}
+TextDirection LayoutBox::ResolvedDirection() const {
+ if (IsInline() && IsAtomicInlineLevel()) {
+ const auto fragments = NGPaintFragment::InlineFragmentsFor(this);
+ if (fragments.IsInLayoutNGInlineFormattingContext()) {
+ DCHECK(*fragments.begin()) << this;
+ const NGPaintFragment* fragment = *fragments.begin();
+ return fragment->PhysicalFragment().ResolvedDirection();
+ }
+
+ if (InlineBoxWrapper())
+ return InlineBoxWrapper()->Direction();
+ }
+ return Style()->Direction();
+}
+
} // 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 ff4159964b4..924dcac603a 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_box.h
@@ -65,8 +65,8 @@ struct LayoutBoxRareData {
public:
LayoutBoxRareData()
: spanner_placeholder_(nullptr),
- override_logical_content_width_(-1),
- override_logical_content_height_(-1),
+ override_logical_width_(-1),
+ override_logical_height_(-1),
has_override_containing_block_content_logical_width_(false),
has_override_containing_block_content_logical_height_(false),
has_previous_content_box_size_and_layout_overflow_rect_(false),
@@ -78,8 +78,8 @@ struct LayoutBoxRareData {
// container.
LayoutMultiColumnSpannerPlaceholder* spanner_placeholder_;
- LayoutUnit override_logical_content_width_;
- LayoutUnit override_logical_content_height_;
+ LayoutUnit override_logical_width_;
+ LayoutUnit override_logical_height_;
bool has_override_containing_block_content_logical_width_ : 1;
bool has_override_containing_block_content_logical_height_ : 1;
@@ -689,30 +689,26 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LayoutUnit MinPreferredLogicalWidth() const override;
LayoutUnit MaxPreferredLogicalWidth() const override;
- // FIXME: We should rename these back to overrideLogicalHeight/Width and have
- // them store the border-box height/width like the regular height/width
- // accessors on LayoutBox. Right now, these are different than contentHeight/
- // contentWidth because they still include the scrollbar height/width.
- LayoutUnit OverrideLogicalContentWidth() const;
- LayoutUnit OverrideLogicalContentHeight() const;
- bool HasOverrideLogicalContentHeight() const;
- bool HasOverrideLogicalContentWidth() const;
- void SetOverrideLogicalContentHeight(LayoutUnit);
- void SetOverrideLogicalContentWidth(LayoutUnit);
+ LayoutUnit OverrideLogicalHeight() const;
+ LayoutUnit OverrideLogicalWidth() const;
+ bool HasOverrideLogicalHeight() const;
+ bool HasOverrideLogicalWidth() const;
+ void SetOverrideLogicalHeight(LayoutUnit);
+ void SetOverrideLogicalWidth(LayoutUnit);
+ void ClearOverrideLogicalHeight();
+ void ClearOverrideLogicalWidth();
void ClearOverrideSize();
- void ClearOverrideLogicalContentHeight();
- void ClearOverrideLogicalContentWidth();
+
+ LayoutUnit OverrideContentLogicalWidth() const;
+ LayoutUnit OverrideContentLogicalHeight() const;
LayoutUnit OverrideContainingBlockContentLogicalWidth() const;
LayoutUnit OverrideContainingBlockContentLogicalHeight() const;
- bool HasOverrideContainingBlockLogicalWidth() const;
- bool HasOverrideContainingBlockLogicalHeight() const;
+ bool HasOverrideContainingBlockContentLogicalWidth() const;
+ bool HasOverrideContainingBlockContentLogicalHeight() const;
void SetOverrideContainingBlockContentLogicalWidth(LayoutUnit);
void SetOverrideContainingBlockContentLogicalHeight(LayoutUnit);
- void ClearContainingBlockOverrideSize();
- void ClearOverrideContainingBlockContentLogicalHeight();
-
- LayoutSize OffsetFromContainer(const LayoutObject*) const override;
+ void ClearOverrideContainingBlockContentSize();
LayoutUnit AdjustBorderBoxLogicalWidthForBoxSizing(float width) const;
LayoutUnit AdjustBorderBoxLogicalHeightForBoxSizing(float height) const;
@@ -998,7 +994,6 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
// scrollWidth. For the full story, visit crbug.com/724255
LayoutUnit VerticalScrollbarWidthClampedToContentBox() const;
- virtual ScrollResult Scroll(ScrollGranularity, const FloatSize&);
bool CanBeScrolledAndHasScrollableArea() const;
virtual bool CanBeProgramaticallyScrolled() const;
virtual void Autoscroll(const IntPoint&);
@@ -1120,6 +1115,7 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
void UnmarkOrthogonalWritingModeRoot();
bool IsCustomItem() const;
+ bool IsCustomItemShrinkToFit() const;
bool IsDeprecatedFlexItem() const {
return !IsInline() && !IsFloatingOrOutOfFlowPositioned() && Parent() &&
@@ -1157,6 +1153,12 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LayoutPoint FlipForWritingModeForChild(const LayoutBox* child,
const LayoutPoint&) const;
+
+ // NG: Like FlipForWritingModeForChild, except that it will not flip
+ // if LayoutBox will be painted by NG using fragment.Offset.
+ LayoutPoint FlipForWritingModeForChildForPaint(const LayoutBox* child,
+ const LayoutPoint&) const;
+
WARN_UNUSED_RESULT LayoutUnit FlipForWritingMode(LayoutUnit position) const {
// The offset is in the block direction (y for horizontal writing modes, x
// for vertical writing modes).
@@ -1529,6 +1531,15 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
LayoutRect LocalVisualRectIgnoringVisibility() const override;
+ LayoutSize OffsetFromContainerInternal(
+ const LayoutObject*,
+ bool ignore_scroll_offset) const override;
+
+ // For atomic inlines, returns its resolved direction in text flow. Not to be
+ // confused with the CSS property 'direction'.
+ // Returns the CSS 'direction' property value when it is not atomic inline.
+ TextDirection ResolvedDirection() const;
+
private:
void UpdateShapeOutsideInfoAfterStyleChange(const ComputedStyle&,
const ComputedStyle* old_style);
@@ -1629,6 +1640,11 @@ class CORE_EXPORT LayoutBox : public LayoutBoxModelObject {
void AddSnapArea(const LayoutBox&);
void RemoveSnapArea(const LayoutBox&);
+ // Returns true when the current recursive scroll into visible could propagate
+ // to parent frame.
+ bool AllowedToPropageRecursiveScrollToParentFrame(
+ const WebScrollIntoViewParams&);
+
LayoutRect DebugRect() const override;
float VisualRectOutsetForRasterEffects() const override;
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 3fc35e5d67b..9cedc31e5c3 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
@@ -38,9 +38,9 @@
#include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/style/shadow_list.h"
-#include "third_party/blink/renderer/platform/geometry/transform_state.h"
#include "third_party/blink/renderer/platform/length_functions.h"
#include "third_party/blink/renderer/platform/scroll/main_thread_scrolling_reason.h"
+#include "third_party/blink/renderer/platform/transforms/transform_state.h"
namespace blink {
@@ -306,10 +306,11 @@ void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
}
}
- if (old_style && (old_style->CanContainFixedPositionObjects() !=
- StyleRef().CanContainFixedPositionObjects() ||
- old_style->GetPosition() != StyleRef().GetPosition() ||
- had_layer != HasLayer())) {
+ if (old_style &&
+ (old_style->CanContainFixedPositionObjects(IsDocumentElement()) !=
+ StyleRef().CanContainFixedPositionObjects(IsDocumentElement()) ||
+ old_style->GetPosition() != StyleRef().GetPosition() ||
+ had_layer != HasLayer())) {
// This may affect paint properties of the current object, and descendants
// even if paint properties of the current object won't change. E.g. the
// stacking context and/or containing block of descendants may change.
@@ -430,11 +431,30 @@ void LayoutBoxModelObject::StyleDidChange(StyleDifference diff,
}
if (old_style && RuntimeEnabledFeatures::SlimmingPaintV175Enabled() &&
- old_style->BackfaceVisibility() != StyleRef().BackfaceVisibility() &&
- HasLayer()) {
- // We need to repaint the layer to update the backface visibility value of
- // the paint chunk.
- Layer()->SetNeedsRepaint();
+ HasLayer() && !Layer()->NeedsRepaint()) {
+ if (old_style->BackfaceVisibility() != StyleRef().BackfaceVisibility()) {
+ // We need to repaint the layer to update the backface visibility value of
+ // the paint chunk.
+ Layer()->SetNeedsRepaint();
+ } else if (diff.TransformChanged() &&
+ (RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
+ !Layer()->HasStyleDeterminedDirectCompositingReasons())) {
+ // PaintLayerPainter::PaintLayerWithAdjustedRoot skips painting of a layer
+ // whose transform is not invertible, so we need to repaint the layer when
+ // invertible status changes.
+ TransformationMatrix old_transform;
+ TransformationMatrix new_transform;
+ old_style->ApplyTransform(
+ old_transform, LayoutSize(), ComputedStyle::kExcludeTransformOrigin,
+ ComputedStyle::kExcludeMotionPath,
+ ComputedStyle::kIncludeIndependentTransformProperties);
+ StyleRef().ApplyTransform(
+ new_transform, LayoutSize(), ComputedStyle::kExcludeTransformOrigin,
+ ComputedStyle::kExcludeMotionPath,
+ ComputedStyle::kIncludeIndependentTransformProperties);
+ if (old_transform.IsInvertible() != new_transform.IsInvertible())
+ Layer()->SetNeedsRepaint();
+ }
}
}
@@ -677,13 +697,12 @@ bool LayoutBoxModelObject::HasAutoHeightOrContainingBlockWithAutoHeight()
if (logical_height_length.IsPercentOrCalc() && cb && IsBox())
cb->AddPercentHeightDescendant(const_cast<LayoutBox*>(ToLayoutBox(this)));
if (this_box && this_box->IsFlexItem()) {
- LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
- if (flex_box.ChildLogicalHeightForPercentageResolution(*this_box) !=
- LayoutUnit(-1))
+ const LayoutFlexibleBox& flex_box = ToLayoutFlexibleBox(*Parent());
+ if (flex_box.UseOverrideLogicalHeightForPerentageResolution(*this_box))
return false;
}
if (this_box && this_box->IsGridItem() &&
- this_box->HasOverrideContainingBlockLogicalHeight())
+ this_box->HasOverrideContainingBlockContentLogicalHeight())
return false;
if (logical_height_length.IsAuto() &&
!IsOutOfFlowPositionedWithImplicitHeight(this))
@@ -711,8 +730,8 @@ LayoutSize LayoutBoxModelObject::RelativePositionOffset() const {
// don't use containingBlockLogicalWidthForContent() here, but instead
// explicitly call availableWidth on our containing block.
// https://drafts.csswg.org/css-position-3/#rel-pos
- Optional<LayoutUnit> left;
- Optional<LayoutUnit> right;
+ base::Optional<LayoutUnit> left;
+ base::Optional<LayoutUnit> right;
if (!Style()->Left().IsAuto())
left = ValueForLength(Style()->Left(), containing_block->AvailableWidth());
if (!Style()->Right().IsAuto())
@@ -753,8 +772,8 @@ LayoutSize LayoutBoxModelObject::RelativePositionOffset() const {
// the percent offset based on this height.
// See <https://bugs.webkit.org/show_bug.cgi?id=26396>.
- Optional<LayoutUnit> top;
- Optional<LayoutUnit> bottom;
+ base::Optional<LayoutUnit> top;
+ base::Optional<LayoutUnit> bottom;
if (!Style()->Top().IsAuto() &&
(!containing_block->HasAutoHeightOrContainingBlockWithAutoHeight() ||
!Style()->Top().IsPercentOrCalc() ||
@@ -812,18 +831,19 @@ void LayoutBoxModelObject::UpdateStickyPositionConstraints() const {
while (containing_block->IsAnonymous()) {
containing_block = containing_block->ContainingBlock();
}
- MapCoordinatesFlags flags = kIgnoreStickyOffset;
+
+ // The sticky position constraint rects should be independent of the current
+ // scroll position therefore we should ignore the scroll offset when
+ // calculating the quad.
+ MapCoordinatesFlags flags = kIgnoreScrollOffset | kIgnoreStickyOffset;
skipped_containers_offset =
ToFloatSize(location_container
->LocalToAncestorQuadWithoutTransforms(
FloatQuad(), containing_block, flags)
.BoundingBox()
.Location());
- LayoutBox* scroll_ancestor =
- Layer()->AncestorOverflowLayer()->IsRootLayer() &&
- !RuntimeEnabledFeatures::RootLayerScrollingEnabled()
- ? nullptr
- : &ToLayoutBox(Layer()->AncestorOverflowLayer()->GetLayoutObject());
+ LayoutBox& scroll_ancestor =
+ ToLayoutBox(Layer()->AncestorOverflowLayer()->GetLayoutObject());
LayoutUnit max_container_width =
containing_block->IsLayoutView()
@@ -840,29 +860,15 @@ void LayoutBoxModelObject::UpdateStickyPositionConstraints() const {
// transforms.
FloatRect scroll_container_relative_padding_box_rect(
containing_block->LayoutOverflowRect());
- FloatSize scroll_container_border_offset;
- if (scroll_ancestor) {
- scroll_container_border_offset =
- FloatSize(scroll_ancestor->BorderLeft(), scroll_ancestor->BorderTop());
- }
- if (containing_block != scroll_ancestor) {
+ FloatSize scroll_container_border_offset =
+ FloatSize(scroll_ancestor.BorderLeft(), scroll_ancestor.BorderTop());
+ if (containing_block != &scroll_ancestor) {
FloatQuad local_quad(FloatRect(containing_block->PaddingBoxRect()));
scroll_container_relative_padding_box_rect =
containing_block
- ->LocalToAncestorQuadWithoutTransforms(local_quad, scroll_ancestor,
+ ->LocalToAncestorQuadWithoutTransforms(local_quad, &scroll_ancestor,
flags)
.BoundingBox();
-
- // The sticky position constraint rects should be independent of the current
- // scroll position, so after mapping we add in the scroll position to get
- // the container's position within the ancestor scroller's unscrolled layout
- // overflow.
- ScrollOffset scroll_offset(
- scroll_ancestor
- ? ToFloatSize(
- scroll_ancestor->GetScrollableArea()->ScrollPosition())
- : FloatSize());
- scroll_container_relative_padding_box_rect.Move(scroll_offset);
}
// Remove top-left border offset from overflow scroller.
scroll_container_relative_padding_box_rect.Move(
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 2805438d13f..ed71dfef77d 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
@@ -118,6 +118,115 @@ TEST_F(LayoutBoxModelObjectTest, StickyPositionVerticalRLConstraints) {
EnclosingIntRect(sticky->ComputeStickyConstrainingRect()));
}
+// Verifies that the sticky constraints are correctly computed for inline.
+TEST_F(LayoutBoxModelObjectTest, StickyPositionInlineConstraints) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body { margin: 0; }
+ .scroller { overflow: scroll; width: 100px; height: 100px; top: 100px;
+ position: absolute; }
+ .container { position: relative; top: 100px; height: 400px;
+ width: 200px; }
+ .sticky_box { width: 10px; height: 10px; top: 10px; position: sticky; }
+ .inline { display: inline-block; }
+ .spacer { height: 2000px; }
+ </style>
+ <div class='scroller' id='scroller'>
+ <div class='container'>
+ <div class='inline sticky_box' id='sticky'></div>
+ </div>
+ <div class='spacer'></div>
+ </div>
+ )HTML");
+
+ LayoutBoxModelObject* scroller =
+ ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"));
+ PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
+ scrollable_area->ScrollToAbsolutePosition(
+ FloatPoint(scrollable_area->ScrollOffsetInt().Width(), 50));
+ EXPECT_EQ(50.f, scrollable_area->ScrollPosition().Y());
+ LayoutBoxModelObject* sticky =
+ ToLayoutBoxModelObject(GetLayoutObjectByElementId("sticky"));
+
+ sticky->UpdateStickyPositionConstraints();
+
+ EXPECT_EQ(scroller->Layer(), sticky->Layer()->AncestorOverflowLayer());
+
+ const StickyPositionScrollingConstraints& constraints =
+ scrollable_area->GetStickyConstraintsMap().at(sticky->Layer());
+
+ EXPECT_EQ(10.f, constraints.TopOffset());
+
+ // The coordinates of the constraint rects should all be with respect to the
+ // unscrolled scroller.
+ EXPECT_EQ(IntRect(0, 100, 200, 400),
+ EnclosingIntRect(
+ GetScrollContainerRelativeContainingBlockRect(constraints)));
+ EXPECT_EQ(
+ IntRect(0, 100, 10, 10),
+ EnclosingIntRect(GetScrollContainerRelativeStickyBoxRect(constraints)));
+ EXPECT_EQ(IntRect(0, 50, 100, 100), sticky->ComputeStickyConstrainingRect());
+}
+
+// Verifies that the sticky constraints are correctly computed for sticky with
+// writing mode.
+TEST_F(LayoutBoxModelObjectTest, StickyPositionVerticalRLInlineConstraints) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body { margin: 0; }
+ .scroller { writing-mode: vertical-rl; overflow: scroll; width: 100px;
+ height: 100px; top: 100px; position: absolute; }
+ .container { position: relative; top: 100px; height: 400px;
+ width: 200px; }
+ .sticky_box { width: 10px; height: 10px; top: 10px; position: sticky; }
+ .inline { display: inline-block; }
+ .spacer { width: 2000px; height: 2000px; }
+ </style>
+ <div class='scroller' id='scroller'>
+ <div class='container'>
+ <div class='inline sticky_box' id='sticky'></div>
+ </div>
+ <div class='spacer'></div>
+ </div>
+ )HTML");
+ // Initial layout:
+ // 0---------------2000----2200
+ // -----spacer-----
+ // container---
+ // ----2100----
+ // scroller
+ // ----2190
+ // sticky
+ LayoutBoxModelObject* scroller =
+ ToLayoutBoxModelObject(GetLayoutObjectByElementId("scroller"));
+ PaintLayerScrollableArea* scrollable_area = scroller->GetScrollableArea();
+ scrollable_area->ScrollToAbsolutePosition(
+ FloatPoint(scrollable_area->ScrollPosition().X(), 50));
+ EXPECT_EQ(50.f, scrollable_area->ScrollPosition().Y());
+ LayoutBoxModelObject* sticky =
+ ToLayoutBoxModelObject(GetLayoutObjectByElementId("sticky"));
+
+ sticky->UpdateStickyPositionConstraints();
+
+ EXPECT_EQ(scroller->Layer(), sticky->Layer()->AncestorOverflowLayer());
+
+ const StickyPositionScrollingConstraints& constraints =
+ scrollable_area->GetStickyConstraintsMap().at(sticky->Layer());
+
+ EXPECT_EQ(10.f, constraints.TopOffset());
+
+ // The coordinates of the constraint rects should all be with respect to the
+ // unscrolled scroller.
+ EXPECT_EQ(IntRect(2000, 100, 200, 400),
+ EnclosingIntRect(
+ GetScrollContainerRelativeContainingBlockRect(constraints)));
+ EXPECT_EQ(
+ IntRect(2190, 100, 10, 10),
+ EnclosingIntRect(GetScrollContainerRelativeStickyBoxRect(constraints)));
+ EXPECT_EQ(IntRect(2100, 50, 100, 100),
+ sticky->ComputeStickyConstrainingRect());
+}
+
// Verifies that the sticky constraints are not affected by transforms
TEST_F(LayoutBoxModelObjectTest, StickyPositionTransforms) {
SetBodyInnerHTML(R"HTML(
@@ -950,12 +1059,11 @@ TEST_F(LayoutBoxModelObjectTest, StickyPositionNestedFixedPos) {
FloatPoint(scrollable_area->ScrollPosition().X(), 100));
ASSERT_EQ(100.0, scrollable_area->ScrollPosition().Y());
- // TODO(smcgruer): Until http://crbug.com/686164 is fixed, we need to update
+ // TODO(smcgruer): Until http://crbug.com/686164 is fixed, the sticky position
+ // offset of the inner sticky stays 75 instead of 25.
// the constraints here before calculations will be correct.
- inner_sticky->UpdateStickyPositionConstraints();
-
EXPECT_EQ(LayoutSize(0, 100), outer_sticky->StickyPositionOffset());
- EXPECT_EQ(LayoutSize(0, 25), inner_sticky->StickyPositionOffset());
+ EXPECT_EQ(LayoutSize(0, 75), inner_sticky->StickyPositionOffset());
}
TEST_F(LayoutBoxModelObjectTest, NoCrashStackingContextChangeNonRooted) {
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 1ddb6e110ad..30156c6b95e 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
@@ -6,6 +6,7 @@
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/html/html_body_element.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/layout/layout_image.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
@@ -433,6 +434,20 @@ TEST_F(LayoutBoxTest, ContentsVisualOverflowPropagation) {
EXPECT_EQ(LayoutRect(-70, 0, 230, 210), a->VisualOverflowRect());
}
+TEST_F(LayoutBoxTest, HitTestContainPaint) {
+ SetBodyInnerHTML(R"HTML(
+ <div id='container' style='width: 100px; height: 200px; contain: paint'>
+ <div id='child' style='width: 300px; height: 400px;'></div>
+ </div>
+ )HTML");
+
+ auto* child = GetDocument().getElementById("child");
+ EXPECT_EQ(GetDocument().documentElement(), HitTest(1, 1));
+ EXPECT_EQ(child, HitTest(10, 10));
+ EXPECT_EQ(GetDocument().FirstBodyElement(), HitTest(150, 10));
+ EXPECT_EQ(GetDocument().documentElement(), HitTest(10, 250));
+}
+
class AnimatedImage : public StubImage {
public:
bool MaybeAnimated() override { return true; }
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_br.cc b/chromium/third_party/blink/renderer/core/layout/layout_br.cc
index 9d390cbb251..094d44a8e54 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_br.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_br.cc
@@ -60,4 +60,19 @@ PositionWithAffinity LayoutBR::PositionForPoint(const LayoutPoint&) const {
return CreatePositionWithAffinity(0);
}
+Position LayoutBR::PositionForCaretOffset(unsigned offset) const {
+ DCHECK_LE(offset, 1u);
+ DCHECK(GetNode());
+ return offset ? Position::AfterNode(*GetNode())
+ : Position::BeforeNode(*GetNode());
+}
+
+base::Optional<unsigned> LayoutBR::CaretOffsetForPosition(
+ const Position& position) const {
+ if (position.IsNull() || position.AnchorNode() != GetNode())
+ return base::nullopt;
+ DCHECK(position.IsBeforeAnchor() || position.IsAfterAnchor()) << position;
+ return position.IsBeforeAnchor() ? 0 : 1;
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_br.h b/chromium/third_party/blink/renderer/core/layout/layout_br.h
index cfafddccd6b..0c11848d9c3 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_br.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_br.h
@@ -70,6 +70,9 @@ class LayoutBR final : public LayoutText {
PositionWithAffinity PositionForPoint(const LayoutPoint&) const final;
+ Position PositionForCaretOffset(unsigned) const final;
+ base::Optional<unsigned> CaretOffsetForPosition(const Position&) const final;
+
protected:
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_count_test.cc b/chromium/third_party/blink/renderer/core/layout/layout_count_test.cc
index 84dbe96284a..f6500919773 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_count_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_count_test.cc
@@ -5,7 +5,6 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink {
@@ -13,7 +12,6 @@ class LayoutCountTest : public RenderingTest {};
TEST_F(LayoutCountTest, SimpleBlockLayoutIsOnePass) {
ScopedTrackLayoutPassesPerBlockForTest track_layout_passes_per_block(true);
- ScopedRootLayerScrollingForTest root_layer_scrolling(true);
SetBodyInnerHTML(
"<!DOCTYPE html>"
" <div id='block' style='height:1000px'>Item</div>");
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 72b845650c2..e9ef81e07e7 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
@@ -318,16 +318,28 @@ static bool ChildDoesNotAffectWidthOrFlexing(LayoutObject* child) {
child->Style()->Visibility() == EVisibility::kCollapse;
}
+static LayoutUnit WidthForChild(LayoutBox* child) {
+ if (child->HasOverrideLogicalWidth())
+ return child->OverrideLogicalWidth();
+ return child->LogicalWidth();
+}
+
static LayoutUnit ContentWidthForChild(LayoutBox* child) {
- if (child->HasOverrideLogicalContentWidth())
- return child->OverrideLogicalContentWidth();
- return child->LogicalWidth() - child->BorderAndPaddingLogicalWidth();
+ // 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();
+ return child->LogicalHeight();
}
static LayoutUnit ContentHeightForChild(LayoutBox* child) {
- if (child->HasOverrideLogicalContentHeight())
- return child->OverrideLogicalContentHeight();
- return child->LogicalHeight() - child->BorderAndPaddingLogicalHeight();
+ // TODO(rego): Shouldn't we subtract the scrollbar height too?
+ return (HeightForChild(child) - child->BorderAndPaddingLogicalHeight())
+ .ClampNegativeToZero();
}
void LayoutDeprecatedFlexibleBox::StyleWillChange(
@@ -712,8 +724,7 @@ void LayoutDeprecatedFlexibleBox::LayoutHorizontalBox(bool relayout_children) {
LayoutUnit(space_available_this_pass *
(child->Style()->BoxFlex() / total_flex));
if (space_add) {
- child->SetOverrideLogicalContentWidth(
- ContentWidthForChild(child) + space_add);
+ child->SetOverrideLogicalWidth(WidthForChild(child) + space_add);
flexing_children = true;
relayout_children = true;
}
@@ -731,8 +742,7 @@ void LayoutDeprecatedFlexibleBox::LayoutHorizontalBox(bool relayout_children) {
for (LayoutBox* child = iterator.First(); child && remaining_space;
child = iterator.Next()) {
if (AllowedChildFlex(child, expanding)) {
- child->SetOverrideLogicalContentWidth(
- ContentWidthForChild(child) + space_add);
+ child->SetOverrideLogicalWidth(WidthForChild(child) + space_add);
flexing_children = true;
relayout_children = true;
remaining_space -= space_add;
@@ -998,8 +1008,8 @@ void LayoutDeprecatedFlexibleBox::LayoutVerticalBox(bool relayout_children) {
space_available_this_pass *
(child->Style()->BoxFlex() / total_flex));
if (space_add) {
- child->SetOverrideLogicalContentHeight(
- ContentHeightForChild(child) + space_add);
+ child->SetOverrideLogicalHeight(HeightForChild(child) +
+ space_add);
flexing_children = true;
relayout_children = true;
}
@@ -1017,8 +1027,8 @@ void LayoutDeprecatedFlexibleBox::LayoutVerticalBox(bool relayout_children) {
for (LayoutBox* child = iterator.First(); child && remaining_space;
child = iterator.Next()) {
if (AllowedChildFlex(child, expanding)) {
- child->SetOverrideLogicalContentHeight(
- ContentHeightForChild(child) + space_add);
+ child->SetOverrideLogicalHeight(HeightForChild(child) +
+ space_add);
flexing_children = true;
relayout_children = true;
remaining_space -= space_add;
@@ -1162,8 +1172,7 @@ void LayoutDeprecatedFlexibleBox::ApplyLineClamp(FlexBoxIterator& iterator,
if (new_height == child->Size().Height())
continue;
- child->SetOverrideLogicalContentHeight(new_height -
- child->BorderAndPaddingHeight());
+ child->SetOverrideLogicalHeight(new_height);
child->ForceChildLayout();
// FIXME: For now don't support RTL.
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 da2f38366ed..ce2fcd590c5 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
@@ -124,7 +124,7 @@ bool LayoutEmbeddedContent::RequiresAcceleratedCompositing() const {
// Second, if this is a LayoutObject with a contentDocument and that document
// needs a layer, then we need a layer.
WebPluginContainerImpl* plugin_view = Plugin();
- if (plugin_view && plugin_view->PlatformLayer())
+ if (plugin_view && plugin_view->CcLayer())
return true;
if (!GetNode() || !GetNode()->IsFrameOwnerElement())
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_embedded_object.cc b/chromium/third_party/blink/renderer/core/layout/layout_embedded_object.cc
index 9ee0e68fd40..df7644aec9a 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_embedded_object.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_embedded_object.cc
@@ -142,17 +142,28 @@ void LayoutEmbeddedObject::UpdateLayout() {
ClearNeedsLayout();
}
-ScrollResult LayoutEmbeddedObject::Scroll(ScrollGranularity granularity,
- const FloatSize&) {
- return ScrollResult();
-}
-
CompositingReasons LayoutEmbeddedObject::AdditionalCompositingReasons() const {
if (RequiresAcceleratedCompositing())
return CompositingReason::kPlugin;
return CompositingReason::kNone;
}
+void LayoutEmbeddedObject::ComputeIntrinsicSizingInfo(
+ IntrinsicSizingInfo& intrinsic_sizing_info) const {
+ FrameView* frame_view = ChildFrameView();
+ if (frame_view && frame_view->GetIntrinsicSizingInfo(intrinsic_sizing_info)) {
+ // Handle zoom & vertical writing modes here, as the embedded document
+ // doesn't know about them.
+ intrinsic_sizing_info.size.Scale(Style()->EffectiveZoom());
+
+ if (!IsHorizontalWritingMode())
+ intrinsic_sizing_info.Transpose();
+ return;
+ }
+
+ LayoutEmbeddedContent::ComputeIntrinsicSizingInfo(intrinsic_sizing_info);
+}
+
bool LayoutEmbeddedObject::NeedsPreferredWidthsRecalculation() const {
if (LayoutEmbeddedContent::NeedsPreferredWidthsRecalculation())
return true;
@@ -160,11 +171,4 @@ bool LayoutEmbeddedObject::NeedsPreferredWidthsRecalculation() const {
return frame_view && frame_view->HasIntrinsicSizingInfo();
}
-bool LayoutEmbeddedObject::GetNestedIntrinsicSizingInfo(
- IntrinsicSizingInfo& intrinsic_sizing_info) const {
- if (FrameView* frame_view = ChildFrameView())
- return frame_view->GetIntrinsicSizingInfo(intrinsic_sizing_info);
- return false;
-}
-
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_embedded_object.h b/chromium/third_party/blink/renderer/core/layout/layout_embedded_object.h
index 180fb40684d..8b196e9db68 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_embedded_object.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_embedded_object.h
@@ -62,13 +62,11 @@ class LayoutEmbeddedObject final : public LayoutEmbeddedContent {
return type == kLayoutObjectEmbeddedObject ||
LayoutEmbeddedContent::IsOfType(type);
}
+ void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
bool NeedsPreferredWidthsRecalculation() const override;
- bool GetNestedIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
PaintLayerType LayerTypeRequired() const final;
- ScrollResult Scroll(ScrollGranularity, const FloatSize&) final;
-
CompositingReasons AdditionalCompositingReasons() const override;
PluginAvailability plugin_availability_ = kPluginAvailable;
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 c80e8f984a1..baf3a07f6f0 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
@@ -31,17 +31,19 @@
#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
#include <limits>
+#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/frame/use_counter.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_view.h"
#include "third_party/blink/renderer/core/layout/min_max_size.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"
#include "third_party/blink/renderer/core/paint/block_painter.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/length_functions.h"
-#include "third_party/blink/renderer/platform/wtf/auto_reset.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
namespace blink {
@@ -370,7 +372,7 @@ void LayoutFlexibleBox::UpdateBlockLayout(bool relayout_children) {
return;
relaid_out_children_.clear();
- WTF::AutoReset<bool> reset1(&in_layout_, true);
+ base::AutoReset<bool> reset1(&in_layout_, true);
DCHECK_EQ(has_definite_height_, SizeDefiniteness::kUnknown);
if (UpdateLogicalWidthAndColumnWidth())
@@ -825,6 +827,30 @@ void LayoutFlexibleBox::ClearCachedMainSizeForChild(const LayoutBox& child) {
intrinsic_size_along_main_axis_.erase(&child);
}
+bool LayoutFlexibleBox::ShouldForceLayoutForNGChild(
+ const LayoutBlockFlow& child) const {
+ // If the last layout was done with a different override size,
+ // or different definite-ness, we need to force-relayout so
+ // that percentage sizes are resolved correctly.
+ const NGConstraintSpace* old_space = child.CachedConstraintSpace();
+ if (!old_space)
+ return true;
+ if (old_space->IsFixedSizeInline() != child.HasOverrideLogicalWidth())
+ return true;
+ if (old_space->IsFixedSizeBlock() != child.HasOverrideLogicalHeight())
+ return true;
+ if (old_space->FixedSizeBlockIsDefinite() !=
+ UseOverrideLogicalHeightForPerentageResolution(child))
+ return true;
+ if (child.HasOverrideLogicalWidth() &&
+ old_space->AvailableSize().inline_size != child.OverrideLogicalWidth())
+ return true;
+ if (child.HasOverrideLogicalHeight() &&
+ old_space->AvailableSize().block_size != child.OverrideLogicalHeight())
+ return true;
+ return false;
+}
+
DISABLE_CFI_PERF
LayoutUnit LayoutFlexibleBox::ComputeInnerFlexBaseSizeForChild(
LayoutBox& child,
@@ -1119,19 +1145,17 @@ MinMaxSize LayoutFlexibleBox::ComputeMinAndMaxSizesForChild(
return sizes;
}
-LayoutUnit LayoutFlexibleBox::CrossSizeForPercentageResolution(
- const LayoutBox& child) {
+bool LayoutFlexibleBox::CrossSizeIsDefiniteForPercentageResolution(
+ const LayoutBox& child) const {
if (FlexLayoutAlgorithm::AlignmentForChild(StyleRef(), child.StyleRef()) !=
ItemPosition::kStretch)
- return LayoutUnit(-1);
+ return false;
// Here we implement https://drafts.csswg.org/css-flexbox/#algo-stretch
- if (HasOrthogonalFlow(child) && child.HasOverrideLogicalContentWidth())
- return child.OverrideLogicalContentWidth() - child.ScrollbarLogicalWidth();
- if (!HasOrthogonalFlow(child) && child.HasOverrideLogicalContentHeight()) {
- return child.OverrideLogicalContentHeight() -
- child.ScrollbarLogicalHeight();
- }
+ if (HasOrthogonalFlow(child) && child.HasOverrideLogicalWidth())
+ return true;
+ if (!HasOrthogonalFlow(child) && child.HasOverrideLogicalHeight())
+ return true;
// We don't currently implement the optimization from
// https://drafts.csswg.org/css-flexbox/#definite-sizes case 1. While that
@@ -1139,42 +1163,36 @@ LayoutUnit LayoutFlexibleBox::CrossSizeForPercentageResolution(
// definite size, which itself is not cheap. We can consider implementing it
// at a later time. (The correctness is ensured by redoing layout in
// applyStretchAlignmentToChild)
- return LayoutUnit(-1);
+ return false;
}
-LayoutUnit LayoutFlexibleBox::MainSizeForPercentageResolution(
- const LayoutBox& child) {
+bool LayoutFlexibleBox::MainSizeIsDefiniteForPercentageResolution(
+ const LayoutBox& child) const {
// This function implements section 9.8. Definite and Indefinite Sizes, case
// 2) of the flexbox spec.
// We need to check for the flexbox to have a definite main size, and for the
// flex item to have a definite flex basis.
const Length& flex_basis = FlexBasisForChild(child);
if (!MainAxisLengthIsDefinite(child, flex_basis))
- return LayoutUnit(-1);
+ return false;
if (!flex_basis.IsPercentOrCalc()) {
// If flex basis had a percentage, our size is guaranteed to be definite or
// the flex item's size could not be definite. Otherwise, we make up a
// percentage to check whether we have a definite size.
if (!MainAxisLengthIsDefinite(child, Length(0, kPercent)))
- return LayoutUnit(-1);
+ return false;
}
if (HasOrthogonalFlow(child))
- return child.HasOverrideLogicalContentHeight()
- ? child.OverrideLogicalContentHeight() -
- child.ScrollbarLogicalHeight()
- : LayoutUnit(-1);
- return child.HasOverrideLogicalContentWidth()
- ? child.OverrideLogicalContentWidth() -
- child.ScrollbarLogicalWidth()
- : LayoutUnit(-1);
+ return child.HasOverrideLogicalHeight();
+ return child.HasOverrideLogicalWidth();
}
-LayoutUnit LayoutFlexibleBox::ChildLogicalHeightForPercentageResolution(
- const LayoutBox& child) {
+bool LayoutFlexibleBox::UseOverrideLogicalHeightForPerentageResolution(
+ const LayoutBox& child) const {
if (!HasOrthogonalFlow(child))
- return CrossSizeForPercentageResolution(child);
- return MainSizeForPercentageResolution(child);
+ return CrossSizeIsDefiniteForPercentageResolution(child);
+ return MainSizeIsDefiniteForPercentageResolution(child);
}
LayoutUnit LayoutFlexibleBox::AdjustChildSizeForAspectRatioCrossAxisMinAndMax(
@@ -1283,10 +1301,15 @@ static LayoutUnit AlignmentOffset(LayoutUnit available_free_space,
void LayoutFlexibleBox::SetOverrideMainAxisContentSizeForChild(
LayoutBox& child,
LayoutUnit child_preferred_size) {
- if (HasOrthogonalFlow(child))
- child.SetOverrideLogicalContentHeight(child_preferred_size);
- else
- child.SetOverrideLogicalContentWidth(child_preferred_size);
+ if (HasOrthogonalFlow(child)) {
+ // TODO(rego): Shouldn't we add the scrollbar height too?
+ child.SetOverrideLogicalHeight(child_preferred_size +
+ child.BorderAndPaddingLogicalHeight());
+ } else {
+ // TODO(rego): Shouldn't we add the scrollbar width too?
+ child.SetOverrideLogicalWidth(child_preferred_size +
+ child.BorderAndPaddingLogicalWidth());
+ }
}
LayoutUnit LayoutFlexibleBox::StaticMainAxisPositionForPositionedChild(
@@ -1457,7 +1480,6 @@ void LayoutFlexibleBox::LayoutLineItems(FlexLine* current_line,
flex_item.flexed_content_size);
// The flexed content size and the override size include the scrollbar
// width, so we need to compare to the size including the scrollbar.
- // TODO(cbiesinger): Should it include the scrollbar?
if (flex_item.flexed_content_size !=
MainAxisContentExtentForChildIncludingScrollbar(*child)) {
child->SetChildNeedsLayout(kMarkOnlyThis);
@@ -1470,8 +1492,12 @@ void LayoutFlexibleBox::LayoutLineItems(FlexLine* current_line,
// computeInnerFlexBaseSizeForChild.
bool force_child_relayout =
relayout_children && !relaid_out_children_.Contains(child);
- if (child->IsLayoutBlock() &&
- ToLayoutBlock(*child).HasPercentHeightDescendants()) {
+ // TODO(dgrogan): Broaden the NG part of this check once NG types other
+ // than Mixin derivatives are cached.
+ if ((child->IsLayoutNGMixin() &&
+ ShouldForceLayoutForNGChild(ToLayoutBlockFlow(*child))) ||
+ (child->IsLayoutBlock() &&
+ ToLayoutBlock(*child).HasPercentHeightDescendants())) {
// Have to force another relayout even though the child is sized
// correctly, because its descendants are not sized correctly yet. Our
// previous layout of the child was done without an override height set.
@@ -1713,9 +1739,8 @@ void LayoutFlexibleBox::ApplyStretchAlignmentToChild(
// So, redo it here.
child_needs_relayout = true;
}
- if (child_needs_relayout || !child.HasOverrideLogicalContentHeight())
- child.SetOverrideLogicalContentHeight(
- desired_logical_height - child.BorderAndPaddingLogicalHeight());
+ if (child_needs_relayout || !child.HasOverrideLogicalHeight())
+ child.SetOverrideLogicalHeight(desired_logical_height);
if (child_needs_relayout) {
child.SetLogicalHeight(LayoutUnit());
// We cache the child's intrinsic content logical height to avoid it being
@@ -1739,8 +1764,7 @@ void LayoutFlexibleBox::ApplyStretchAlignmentToChild(
flex_item.cross_axis_size = child_width;
if (child_width != child.LogicalWidth()) {
- child.SetOverrideLogicalContentWidth(
- child_width - child.BorderAndPaddingLogicalWidth());
+ child.SetOverrideLogicalWidth(child_width);
child.ForceChildLayout();
}
}
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 9e783233ce4..def9538873b 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
@@ -75,9 +75,14 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
const OrderIterator& GetOrderIterator() const { return order_iterator_; }
- LayoutUnit CrossSizeForPercentageResolution(const LayoutBox& child);
- LayoutUnit MainSizeForPercentageResolution(const LayoutBox& child);
- LayoutUnit ChildLogicalHeightForPercentageResolution(const LayoutBox& child);
+ // These three functions are used when resolving percentages against a
+ // flex item's logical height. In flexbox, sometimes a logical height
+ // should be considered definite even though it normally shouldn't be,
+ // and these functions implement that logic.
+ bool CrossSizeIsDefiniteForPercentageResolution(const LayoutBox& child) const;
+ bool MainSizeIsDefiniteForPercentageResolution(const LayoutBox& child) const;
+ bool UseOverrideLogicalHeightForPerentageResolution(
+ const LayoutBox& child) const;
void ClearCachedMainSizeForChild(const LayoutBox& child);
@@ -153,6 +158,7 @@ class CORE_EXPORT LayoutFlexibleBox : public LayoutBlock {
EOverflow MainAxisOverflowForChild(const LayoutBox& child) const;
EOverflow CrossAxisOverflowForChild(const LayoutBox& child) const;
void CacheChildMainSize(const LayoutBox& child);
+ bool ShouldForceLayoutForNGChild(const LayoutBlockFlow& child) const;
void LayoutFlexItems(bool relayout_children, SubtreeLayoutScope&);
LayoutUnit AutoMarginOffsetInMainAxis(const Vector<FlexItem>&,
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_full_screen.cc b/chromium/third_party/blink/renderer/core/layout/layout_full_screen.cc
index 8a1f7b6fde6..a90fabbc6e6 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_full_screen.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_full_screen.cc
@@ -25,13 +25,12 @@
#include "third_party/blink/renderer/core/layout/layout_full_screen.h"
+#include "third_party/blink/public/platform/web_screen_info.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/fullscreen/fullscreen.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/public/platform/web_screen_info.h"
-
namespace blink {
namespace {
@@ -43,9 +42,11 @@ class LayoutFullScreenPlaceholder final : public LayoutBlockFlow {
SetDocumentForAnonymous(&owner->GetDocument());
}
- // Must call setStyleWithWritingModeOfParent() instead.
+ // Must call SetStyleWithWritingModeOfParent() instead.
void SetStyle(scoped_refptr<ComputedStyle>) = delete;
+ bool CreatesNewFormattingContext() const override { return true; }
+
private:
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectLayoutFullScreenPlaceholder ||
@@ -54,6 +55,7 @@ class LayoutFullScreenPlaceholder final : public LayoutBlockFlow {
bool AnonymousHasStylePropagationOverride() override { return true; }
void WillBeDestroyed() override;
+
LayoutFullScreen* owner_;
};
@@ -95,7 +97,7 @@ void LayoutFullScreen::WillBeDestroyed() {
LayoutFlexibleBox::WillBeDestroyed();
}
-void LayoutFullScreen::UpdateStyle(LayoutObject* parent) {
+scoped_refptr<ComputedStyle> LayoutFullScreen::CreateAnonymousStyle() {
scoped_refptr<ComputedStyle> fullscreen_style = ComputedStyle::Create();
// Create a stacking context:
@@ -121,19 +123,19 @@ void LayoutFullScreen::UpdateStyle(LayoutObject* parent) {
fullscreen_style->SetHeight(Length(viewport_size.Height(), blink::kFixed));
fullscreen_style->SetBackgroundColor(StyleColor(Color::kBlack));
-
- SetStyleWithWritingModeOf(fullscreen_style, parent);
+ return fullscreen_style;
}
void LayoutFullScreen::UpdateStyle() {
- UpdateStyle(Parent());
+ scoped_refptr<ComputedStyle> style = CreateAnonymousStyle();
+ SetStyleWithWritingModeOf(style, Parent());
}
LayoutObject* LayoutFullScreen::WrapLayoutObject(LayoutObject* object,
LayoutObject* parent,
Document* document) {
- // FIXME: We should not modify the structure of the layout tree during
- // layout. crbug.com/370459
+ // TODO: We should not modify the structure of the layout tree during layout.
+ // crbug.com/370459
DeprecatedDisableModifyLayoutTreeStructureAsserts disabler;
// A fullscreen <html> element should not be wrapped (see crbug.com/676432).
@@ -141,37 +143,41 @@ LayoutObject* LayoutFullScreen::WrapLayoutObject(LayoutObject* object,
LayoutFullScreen* fullscreen_layout_object =
LayoutFullScreen::CreateAnonymous(document);
- fullscreen_layout_object->UpdateStyle(parent);
- if (parent && !parent->IsChildAllowed(fullscreen_layout_object,
- fullscreen_layout_object->StyleRef())) {
+ scoped_refptr<ComputedStyle> fullscreen_style =
+ fullscreen_layout_object->CreateAnonymousStyle();
+
+ if (parent &&
+ !parent->IsChildAllowed(fullscreen_layout_object, *fullscreen_style)) {
fullscreen_layout_object->Destroy();
return nullptr;
}
+ parent = object ? object->Parent() : nullptr;
+ fullscreen_layout_object->SetStyleWithWritingModeOf(fullscreen_style, parent);
+
+ // |object->Parent()| can be null if the object is not yet attached
+ // to |parent|.
+ if (parent) {
+ LayoutBlock* containing_block = object->ContainingBlock();
+ DCHECK(containing_block);
+ // Since we are moving the |object| to a new parent
+ // |fullscreen_layout_object|, the line box tree underneath our
+ // |containing_block| is not longer valid.
+ if (containing_block->IsLayoutBlockFlow())
+ ToLayoutBlockFlow(containing_block)->DeleteLineBoxTree();
+
+ parent->AddChild(fullscreen_layout_object, object);
+ object->Remove();
+
+ // Always just do a full layout to ensure that line boxes get deleted
+ // properly.
+ // Because objects moved from |parent| to |fullscreen_layout_object|, we
+ // want to make new line boxes instead of leaving the old ones around.
+ parent->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ LayoutInvalidationReason::kFullscreen);
+ containing_block->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ LayoutInvalidationReason::kFullscreen);
+ }
if (object) {
- // |object->parent()| can be null if the object is not yet attached
- // to |parent|.
- if (LayoutObject* parent = object->Parent()) {
- LayoutBlock* containing_block = object->ContainingBlock();
- DCHECK(containing_block);
- // Since we are moving the |object| to a new parent
- // |fullscreenLayoutObject|, the line box tree underneath our
- // |containingBlock| is not longer valid.
- if (containing_block->IsLayoutBlockFlow())
- ToLayoutBlockFlow(containing_block)->DeleteLineBoxTree();
-
- parent->AddChildWithWritingModeOfParent(fullscreen_layout_object, object);
- object->Remove();
-
- // Always just do a full layout to ensure that line boxes get deleted
- // properly.
- // Because objects moved from |parent| to |fullscreenLayoutObject|, we
- // want to make new line boxes instead of leaving the old ones around.
- parent->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
- LayoutInvalidationReason::kFullscreen);
- containing_block
- ->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
- LayoutInvalidationReason::kFullscreen);
- }
fullscreen_layout_object->AddChild(object);
fullscreen_layout_object
->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
@@ -215,17 +221,17 @@ void LayoutFullScreen::CreatePlaceholder(scoped_refptr<ComputedStyle> style,
if (style->Height().IsAuto())
style->SetHeight(Length(frame_rect.Height(), kFixed));
- if (!placeholder_) {
- placeholder_ = new LayoutFullScreenPlaceholder(this);
- placeholder_->SetStyleWithWritingModeOfParent(std::move(style));
- if (Parent()) {
- Parent()->AddChildWithWritingModeOfParent(placeholder_, this);
- Parent()->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
- LayoutInvalidationReason::kFullscreen);
- }
- } else {
- placeholder_->SetStyle(std::move(style));
+ if (placeholder_) {
placeholder_->SetStyleWithWritingModeOfParent(std::move(style));
+ return;
+ }
+
+ placeholder_ = new LayoutFullScreenPlaceholder(this);
+ placeholder_->SetStyleWithWritingModeOf(std::move(style), Parent());
+ if (Parent()) {
+ Parent()->AddChild(placeholder_, this);
+ Parent()->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ LayoutInvalidationReason::kFullscreen);
}
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_full_screen.h b/chromium/third_party/blink/renderer/core/layout/layout_full_screen.h
index c1056940301..63534f4f06b 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_full_screen.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_full_screen.h
@@ -54,7 +54,6 @@ class CORE_EXPORT LayoutFullScreen final : public LayoutFlexibleBox {
void UnwrapLayoutObject();
void UpdateStyle();
- void UpdateStyle(LayoutObject* parent);
bool AnonymousHasStylePropagationOverride() override { return true; }
// Must call setStyleWithWritingModeOfParent() instead.
@@ -63,6 +62,7 @@ class CORE_EXPORT LayoutFullScreen final : public LayoutFlexibleBox {
private:
LayoutFullScreen();
void WillBeDestroyed() override;
+ scoped_refptr<ComputedStyle> CreateAnonymousStyle();
protected:
LayoutBlockFlow* placeholder_;
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 176f44d4312..c9948bff78c 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
@@ -25,10 +25,10 @@
#include "third_party/blink/renderer/core/layout/layout_geometry_map.h"
+#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/platform/geometry/transform_state.h"
-#include "third_party/blink/renderer/platform/wtf/auto_reset.h"
+#include "third_party/blink/renderer/platform/transforms/transform_state.h"
#define LAYOUT_GEOMETRY_MAP_LOGGING 0
@@ -196,7 +196,8 @@ void LayoutGeometryMap::PushMappingsToAncestor(
const LayoutBoxModelObject* ancestor_layout_object) {
// We need to push mappings in reverse order here, so do insertions rather
// than appends.
- AutoReset<size_t> position_change(&insertion_position_, mapping_.size());
+ base::AutoReset<size_t> position_change(&insertion_position_,
+ mapping_.size());
do {
layout_object =
layout_object->PushMappingToContainer(ancestor_layout_object, *this);
@@ -265,7 +266,8 @@ void LayoutGeometryMap::PushMappingsToAncestor(
PushMappingsToAncestor(&ancestor_layer->GetLayoutObject(), nullptr);
}
- AutoReset<size_t> position_change(&insertion_position_, mapping_.size());
+ base::AutoReset<size_t> position_change(&insertion_position_,
+ mapping_.size());
bool accumulating_transform =
layout_object.Style()->Preserves3D() ||
ancestor_layer->GetLayoutObject().Style()->Preserves3D();
@@ -398,7 +400,7 @@ bool LayoutGeometryMap::IsTopmostLayoutView(
if (!(map_coordinates_flags_ & kTraverseDocumentBoundaries))
return true;
- return layout_object->GetFrame()->IsMainFrame();
+ return layout_object->GetFrame()->IsLocalRoot();
}
#endif
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 894ebba5615..c5d0da335da 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
@@ -42,21 +42,14 @@
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/unit_test_helpers.h"
#include "third_party/blink/renderer/platform/testing/url_test_helpers.h"
namespace blink {
-typedef bool TestParamRootLayerScrolling;
-class LayoutGeometryMapTest
- : public testing::Test,
- public testing::WithParamInterface<TestParamRootLayerScrolling>,
- private ScopedRootLayerScrollingForTest {
+class LayoutGeometryMapTest : public testing::Test {
public:
- LayoutGeometryMapTest()
- : ScopedRootLayerScrollingForTest(GetParam()),
- base_url_("http://www.test.com/") {}
+ LayoutGeometryMapTest() : base_url_("http://www.test.com/") {}
void TearDown() override {
Platform::Current()
@@ -171,9 +164,7 @@ class LayoutGeometryMapTest
const std::string base_url_;
};
-INSTANTIATE_TEST_CASE_P(All, LayoutGeometryMapTest, testing::Bool());
-
-TEST_P(LayoutGeometryMapTest, SimpleGeometryMapTest) {
+TEST_F(LayoutGeometryMapTest, SimpleGeometryMapTest) {
RegisterMockedHttpURLLoad("rgm_test.html");
FrameTestHelpers::WebViewHelper web_view_helper;
WebView* web_view =
@@ -213,9 +204,9 @@ TEST_P(LayoutGeometryMapTest, SimpleGeometryMapTest) {
// Fails on Windows due to crbug.com/391457. When run through the transform the
// position on windows differs by a pixel
#if defined(OS_WIN)
-TEST_P(LayoutGeometryMapTest, DISABLED_TransformedGeometryTest)
+TEST_F(LayoutGeometryMapTest, DISABLED_TransformedGeometryTest)
#else
-TEST_P(LayoutGeometryMapTest, TransformedGeometryTest)
+TEST_F(LayoutGeometryMapTest, TransformedGeometryTest)
#endif
{
RegisterMockedHttpURLLoad("rgm_transformed_test.html");
@@ -276,7 +267,7 @@ TEST_P(LayoutGeometryMapTest, TransformedGeometryTest)
rgm.MapToAncestor(rect, nullptr).BoundingBox());
}
-TEST_P(LayoutGeometryMapTest, FixedGeometryTest) {
+TEST_F(LayoutGeometryMapTest, FixedGeometryTest) {
RegisterMockedHttpURLLoad("rgm_fixed_position_test.html");
FrameTestHelpers::WebViewHelper web_view_helper;
WebView* web_view = web_view_helper.InitializeAndLoad(
@@ -314,7 +305,7 @@ TEST_P(LayoutGeometryMapTest, FixedGeometryTest) {
rgm.MapToAncestor(rect, nullptr));
}
-TEST_P(LayoutGeometryMapTest, ContainsFixedPositionTest) {
+TEST_F(LayoutGeometryMapTest, ContainsFixedPositionTest) {
RegisterMockedHttpURLLoad("rgm_contains_fixed_position_test.html");
FrameTestHelpers::WebViewHelper web_view_helper;
WebView* web_view = web_view_helper.InitializeAndLoad(
@@ -361,7 +352,7 @@ TEST_P(LayoutGeometryMapTest, ContainsFixedPositionTest) {
rgm.PopMappingsToAncestor(static_cast<PaintLayer*>(nullptr));
}
-TEST_P(LayoutGeometryMapTest, IframeTest) {
+TEST_F(LayoutGeometryMapTest, IframeTest) {
RegisterMockedHttpURLLoad("rgm_iframe_test.html");
RegisterMockedHttpURLLoad("rgm_test.html");
FrameTestHelpers::WebViewHelper web_view_helper;
@@ -458,7 +449,7 @@ TEST_P(LayoutGeometryMapTest, IframeTest) {
rgm_no_frame.MapToAncestor(rect, nullptr));
}
-TEST_P(LayoutGeometryMapTest, ColumnTest) {
+TEST_F(LayoutGeometryMapTest, ColumnTest) {
RegisterMockedHttpURLLoad("rgm_column_test.html");
FrameTestHelpers::WebViewHelper web_view_helper;
WebView* web_view =
@@ -507,7 +498,7 @@ TEST_P(LayoutGeometryMapTest, ColumnTest) {
EXPECT_EQ(3.0f, RectFromQuad(rgm.MapToAncestor(rect, nullptr)).Height());
}
-TEST_P(LayoutGeometryMapTest, FloatUnderInlineLayer) {
+TEST_F(LayoutGeometryMapTest, FloatUnderInlineLayer) {
RegisterMockedHttpURLLoad("rgm_float_under_inline.html");
FrameTestHelpers::WebViewHelper web_view_helper;
WebView* web_view = web_view_helper.InitializeAndLoad(
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 d2a17280639..20b0f690b67 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_grid.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_grid.cc
@@ -212,14 +212,14 @@ bool LayoutGrid::NamedGridLinesDefinitionDidChange(
// This method optimizes the gutters computation by skiping the available size
// call if gaps are fixed size (it's only needed for percentages).
-Optional<LayoutUnit> LayoutGrid::AvailableSpaceForGutters(
+base::Optional<LayoutUnit> LayoutGrid::AvailableSpaceForGutters(
GridTrackSizingDirection direction) const {
bool is_row_axis = direction == kForColumns;
const GapLength& gap =
is_row_axis ? StyleRef().ColumnGap() : StyleRef().RowGap();
if (!gap.IsNormal() && !gap.GetLength().IsPercent())
- return WTF::nullopt;
+ return base::nullopt;
return is_row_axis ? AvailableLogicalWidth()
: AvailableLogicalHeightForPercentageComputation();
@@ -319,15 +319,13 @@ void LayoutGrid::UpdateBlockLayout(bool relayout_children) {
LayoutSize previous_size = Size();
has_definite_logical_height_ = HasDefiniteLogicalHeight();
- // Grid's layout logic controls the grid item's override size, hence
- // we need to clear any override size set previously, so it doesn't
+ // Grid's layout logic controls the grid item's override height, hence
+ // we need to clear any override height set previously, so it doesn't
// interfere in current layout execution.
+ // Grid never uses the override width, that's why we don't need to clear it.
for (auto* child = FirstInFlowChildBox(); child;
- child = child->NextInFlowSiblingBox()) {
- child->ClearOverrideSize();
- child->SetOverrideContainingBlockContentLogicalWidth(LayoutUnit());
- child->SetOverrideContainingBlockContentLogicalHeight(LayoutUnit());
- }
+ child = child->NextInFlowSiblingBox())
+ child->ClearOverrideLogicalHeight();
UpdateLogicalWidth();
@@ -407,8 +405,9 @@ void LayoutGrid::UpdateBlockLayout(bool relayout_children) {
ClearNeedsLayout();
}
-LayoutUnit LayoutGrid::GridGap(GridTrackSizingDirection direction,
- Optional<LayoutUnit> available_size) const {
+LayoutUnit LayoutGrid::GridGap(
+ GridTrackSizingDirection direction,
+ base::Optional<LayoutUnit> available_size) const {
const GapLength& gap =
direction == kForColumns ? StyleRef().ColumnGap() : StyleRef().RowGap();
if (gap.IsNormal())
@@ -436,11 +435,12 @@ LayoutUnit LayoutGrid::GridGap(GridTrackSizingDirection direction) const {
return ValueForLength(gap.GetLength(), available_size);
}
-LayoutUnit LayoutGrid::GuttersSize(const Grid& grid,
- GridTrackSizingDirection direction,
- size_t start_line,
- size_t span,
- Optional<LayoutUnit> available_size) const {
+LayoutUnit LayoutGrid::GuttersSize(
+ const Grid& grid,
+ GridTrackSizingDirection direction,
+ size_t start_line,
+ size_t span,
+ base::Optional<LayoutUnit> available_size) const {
if (span <= 1)
return LayoutUnit();
@@ -520,7 +520,7 @@ void LayoutGrid::ComputeIntrinsicLogicalWidths(
LayoutUnit& min_logical_width,
LayoutUnit& max_logical_width) const {
Grid grid(this);
- PlaceItemsOnGrid(grid, WTF::nullopt);
+ PlaceItemsOnGrid(grid, base::nullopt);
GridTrackSizingAlgorithm algorithm(this, grid);
ComputeTrackSizesForIndefiniteSize(algorithm, kForColumns, grid,
@@ -537,7 +537,7 @@ void LayoutGrid::ComputeTrackSizesForIndefiniteSize(
Grid& grid,
LayoutUnit& min_intrinsic_size,
LayoutUnit& max_intrinsic_size) const {
- algo.Setup(direction, NumTracks(direction, grid), WTF::nullopt);
+ algo.Setup(direction, NumTracks(direction, grid), base::nullopt);
algo.Run();
min_intrinsic_size = algo.MinContentSize();
@@ -545,7 +545,7 @@ void LayoutGrid::ComputeTrackSizesForIndefiniteSize(
size_t number_of_tracks = algo.Tracks(direction).size();
LayoutUnit total_gutters_size =
- GuttersSize(grid, direction, 0, number_of_tracks, WTF::nullopt);
+ GuttersSize(grid, direction, 0, number_of_tracks, base::nullopt);
min_intrinsic_size += total_gutters_size;
max_intrinsic_size += total_gutters_size;
@@ -591,16 +591,16 @@ LayoutUnit LayoutGrid::OverrideContainingBlockContentSizeForChild(
}
// Unfortunately there are still many layout methods that return -1 for
-// non-resolvable sizes. We prefer to represent them with WTF::nullopt.
-static Optional<LayoutUnit> ConvertLayoutUnitToOptional(LayoutUnit size) {
+// non-resolvable sizes. We prefer to represent them with base::nullopt.
+static base::Optional<LayoutUnit> ConvertLayoutUnitToOptional(LayoutUnit size) {
if (size == -1)
- return WTF::nullopt;
+ return base::nullopt;
return size;
}
size_t LayoutGrid::ComputeAutoRepeatTracksCount(
GridTrackSizingDirection direction,
- Optional<LayoutUnit> available_size) const {
+ base::Optional<LayoutUnit> available_size) const {
DCHECK(!available_size || available_size.value() != -1);
bool is_row_axis = direction == kForColumns;
const auto& auto_repeat_tracks = is_row_axis
@@ -768,7 +768,7 @@ size_t LayoutGrid::ClampAutoRepeatTracks(GridTrackSizingDirection direction,
// does know whether the available logical width is indefinite or not.
void LayoutGrid::PlaceItemsOnGrid(
Grid& grid,
- Optional<LayoutUnit> available_logical_width) const {
+ base::Optional<LayoutUnit> available_logical_width) const {
size_t auto_repeat_rows = ComputeAutoRepeatTracksCount(
kForRows, ConvertLayoutUnitToOptional(
AvailableLogicalHeightForPercentageComputation()));
@@ -792,20 +792,27 @@ void LayoutGrid::PlaceItemsOnGrid(
Vector<LayoutBox*> auto_major_axis_auto_grid_items;
Vector<LayoutBox*> specified_major_axis_auto_grid_items;
+ Vector<LayoutBox*> orthogonal_grid_items;
#if DCHECK_IS_ON()
DCHECK(!grid.HasAnyGridItemPaintOrder());
#endif
DCHECK(!grid.HasAnyOrthogonalGridItem());
- bool has_any_orthogonal_grid_item = false;
size_t child_index = 0;
for (LayoutBox* child = grid.GetOrderIterator().First(); child;
child = grid.GetOrderIterator().Next()) {
if (child->IsOutOfFlowPositioned())
continue;
- has_any_orthogonal_grid_item =
- has_any_orthogonal_grid_item ||
- GridLayoutUtils::IsOrthogonalChild(*this, *child);
+ // Grid items should use the grid area sizes instead of the containing block
+ // (grid container) sizes, we initialize the overrides here if needed to
+ // ensure it.
+ if (!child->HasOverrideContainingBlockContentLogicalWidth())
+ child->SetOverrideContainingBlockContentLogicalWidth(LayoutUnit());
+ if (!child->HasOverrideContainingBlockContentLogicalHeight())
+ child->SetOverrideContainingBlockContentLogicalHeight(LayoutUnit(-1));
+
+ if (GridLayoutUtils::IsOrthogonalChild(*this, *child))
+ orthogonal_grid_items.push_back(child);
grid.SetGridItemPaintOrder(*child, child_index++);
GridArea area = grid.GridItemArea(*child);
@@ -827,7 +834,7 @@ void LayoutGrid::PlaceItemsOnGrid(
}
grid.insert(*child, area);
}
- grid.SetHasAnyOrthogonalGridItem(has_any_orthogonal_grid_item);
+ grid.SetHasAnyOrthogonalGridItem(!orthogonal_grid_items.IsEmpty());
#if DCHECK_IS_ON()
if (grid.HasGridItems()) {
@@ -851,6 +858,14 @@ void LayoutGrid::PlaceItemsOnGrid(
grid.SetNeedsItemsPlacement(false);
+ // Blink does a pre-layout of all the orthogonal boxes in the layout
+ // tree (see how LocalFrameView::PerformLayout calls its
+ // LayoutOrthogonalWritingModeRoots function). However, grid items
+ // don't participate in this process (see the function
+ // PrepareOrthogonalWritingModeRootForLayout) because it's useless
+ // and even wrong if they don't have their corresponding Grid Area.
+ LayoutOrthogonalWritingModeRoots(grid, orthogonal_grid_items);
+
#if DCHECK_IS_ON()
for (LayoutBox* child = grid.GetOrderIterator().First(); child;
child = grid.GetOrderIterator().Next()) {
@@ -864,6 +879,37 @@ void LayoutGrid::PlaceItemsOnGrid(
#endif
}
+// TODO(lajava): Consider rafactoring this code with
+// LocalFrameView::PrepareOrthogonalWritingModeRootForLayout
+static bool PrepareOrthogonalWritingModeRootForLayout(LayoutObject& root) {
+ DCHECK(root.IsBox() && ToLayoutBox(root).IsOrthogonalWritingModeRoot());
+ if (!root.NeedsLayout() || root.IsOutOfFlowPositioned() ||
+ root.IsColumnSpanAll() || root.IsTablePart())
+ return false;
+
+ return true;
+}
+
+// TODO(lajava): Consider rafactoring this code with
+// LocalFrameView::LayoutOrthogonalWritingModeRoots
+void LayoutGrid::LayoutOrthogonalWritingModeRoots(
+ const Grid& grid,
+ const Vector<LayoutBox*>& orthogonal_grid_items) const {
+ if (!GetDocument().View()->IsInPerformLayout())
+ return;
+
+ for (auto* root : orthogonal_grid_items) {
+ DCHECK(GridLayoutUtils::IsOrthogonalChild(*this, *root));
+ if (PrepareOrthogonalWritingModeRootForLayout(*root)) {
+ UpdateGridAreaLogicalSize(
+ *root,
+ LayoutSize(EstimatedGridAreaBreadthForChild(grid, *root, kForColumns),
+ EstimatedGridAreaBreadthForChild(grid, *root, kForRows)));
+ root->LayoutIfNeeded();
+ }
+ }
+}
+
void LayoutGrid::PopulateExplicitGridAndOrderIterator(Grid& grid) const {
OrderIteratorPopulator populator(grid.GetOrderIterator());
int smallest_row_start = 0;
@@ -1171,6 +1217,26 @@ const StyleContentAlignmentData& LayoutGrid::ContentAlignmentNormalBehavior() {
return kNormalBehavior;
}
+void LayoutGrid::UpdateGridAreaLogicalSize(
+ LayoutBox& child,
+ LayoutSize grid_area_logical_size) const {
+ // Because the grid area cannot be styled, we don't need to adjust
+ // the grid breadth to account for 'box-sizing'.
+ if (child.OverrideContainingBlockContentLogicalWidth() !=
+ grid_area_logical_size.Width() ||
+ (child.OverrideContainingBlockContentLogicalHeight() !=
+ grid_area_logical_size.Height() &&
+ (child.HasRelativeLogicalHeight() ||
+ GridLayoutUtils::IsOrthogonalChild(*this, child)))) {
+ child.SetNeedsLayout(LayoutInvalidationReason::kGridChanged, kMarkOnlyThis);
+ }
+
+ child.SetOverrideContainingBlockContentLogicalWidth(
+ grid_area_logical_size.Width());
+ child.SetOverrideContainingBlockContentLogicalHeight(
+ grid_area_logical_size.Height());
+}
+
void LayoutGrid::LayoutGridItems() {
PopulateGridPositionsForDirection(kForColumns);
PopulateGridPositionsForDirection(kForRows);
@@ -1183,24 +1249,14 @@ void LayoutGrid::LayoutGridItems() {
continue;
}
- // Because the grid area cannot be styled, we don't need to adjust
- // the grid breadth to account for 'box-sizing'.
- LayoutUnit override_containing_block_content_logical_width =
- GridAreaBreadthForChildIncludingAlignmentOffsets(*child, kForColumns);
- LayoutUnit override_containing_block_content_logical_height =
- GridAreaBreadthForChildIncludingAlignmentOffsets(*child, kForRows);
-
- if (child->OverrideContainingBlockContentLogicalWidth() !=
- override_containing_block_content_logical_width ||
- (child->OverrideContainingBlockContentLogicalHeight() !=
- override_containing_block_content_logical_height &&
- child->HasRelativeLogicalHeight()))
- child->SetNeedsLayout(LayoutInvalidationReason::kGridChanged);
-
- child->SetOverrideContainingBlockContentLogicalWidth(
- override_containing_block_content_logical_width);
- child->SetOverrideContainingBlockContentLogicalHeight(
- override_containing_block_content_logical_height);
+ // Setting the definite grid area's sizes. It may imply that the
+ // item must perform a layout if its area differs from the one
+ // used during the track sizing algorithm.
+ UpdateGridAreaLogicalSize(
+ *child, LayoutSize(GridAreaBreadthForChildIncludingAlignmentOffsets(
+ *child, kForColumns),
+ GridAreaBreadthForChildIncludingAlignmentOffsets(
+ *child, kForRows)));
// Stretching logic might force a child layout, so we need to run it before
// the layoutIfNeeded call to avoid unnecessary relayouts. This might imply
@@ -1229,12 +1285,12 @@ void LayoutGrid::LayoutGridItems() {
// dimensions for simplicity, so we can forget about orthogonalty.
LayoutUnit child_grid_area_height =
IsHorizontalWritingMode()
- ? override_containing_block_content_logical_height
- : override_containing_block_content_logical_width;
+ ? child->OverrideContainingBlockContentLogicalHeight()
+ : child->OverrideContainingBlockContentLogicalWidth();
LayoutUnit child_grid_area_width =
IsHorizontalWritingMode()
- ? override_containing_block_content_logical_width
- : override_containing_block_content_logical_height;
+ ? child->OverrideContainingBlockContentLogicalWidth()
+ : child->OverrideContainingBlockContentLogicalHeight();
LayoutRect grid_area_rect(
GridAreaLogicalPosition(area),
LayoutSize(child_grid_area_width, child_grid_area_height));
@@ -1295,6 +1351,40 @@ void LayoutGrid::LayoutPositionedObjects(bool relayout_children,
}
}
+LayoutUnit LayoutGrid::EstimatedGridAreaBreadthForChild(
+ const Grid& grid,
+ const LayoutBox& child,
+ GridTrackSizingDirection direction) const {
+ const GridSpan& span = grid.GridItemSpan(child, direction);
+ LayoutUnit grid_area_size;
+ bool grid_area_is_indefinite = false;
+ base::Optional<LayoutUnit> available_size =
+ track_sizing_algorithm_.AvailableSpace(direction);
+ for (auto track_position : span) {
+ GridLength max_track_size =
+ track_sizing_algorithm_.GetGridTrackSize(direction, track_position)
+ .MaxTrackBreadth();
+ if (max_track_size.IsContentSized() || max_track_size.IsFlex()) {
+ grid_area_is_indefinite = true;
+ } else {
+ grid_area_size += ValueForLength(max_track_size.length(),
+ available_size.value_or(LayoutUnit()));
+ }
+ }
+
+ grid_area_size += GuttersSize(grid_, direction, span.StartLine(),
+ span.IntegerSpan(), available_size);
+
+ GridTrackSizingDirection child_inline_direction =
+ GridLayoutUtils::FlowAwareDirectionForChild(*this, child, kForColumns);
+ if (grid_area_is_indefinite) {
+ return direction == child_inline_direction
+ ? std::max(child.MaxPreferredLogicalWidth(), grid_area_size)
+ : LayoutUnit(-1);
+ }
+ return grid_area_size;
+}
+
LayoutUnit LayoutGrid::GridAreaBreadthForChildIncludingAlignmentOffsets(
const LayoutBox& child,
GridTrackSizingDirection direction) const {
@@ -1453,9 +1543,7 @@ void LayoutGrid::ApplyStretchAlignmentToChildIfNeeded(LayoutBox& child) {
child);
LayoutUnit desired_logical_height = child.ConstrainLogicalHeightByMinMax(
stretched_logical_height, LayoutUnit(-1));
- child.SetOverrideLogicalContentHeight(
- (desired_logical_height - child.BorderAndPaddingLogicalHeight())
- .ClampNegativeToZero());
+ child.SetOverrideLogicalHeight(desired_logical_height);
if (desired_logical_height != child.LogicalHeight()) {
// TODO (lajava): Can avoid laying out here in some cases. See
// https://webkit.org/b/87905.
@@ -1976,7 +2064,7 @@ LayoutUnit LayoutGrid::GridAreaBreadthForOutOfFlowChild(
end = positions[end_line];
// These vectors store line positions including gaps, but we shouldn't
// consider them for the edges of the grid.
- Optional<LayoutUnit> available_size_for_gutters =
+ base::Optional<LayoutUnit> available_size_for_gutters =
AvailableSpaceForGutters(direction);
if (end_line > 0 && end_line < last_line) {
DCHECK(!grid_.NeedsItemsPlacement());
@@ -2030,7 +2118,7 @@ void LayoutGrid::GridAreaPositionForOutOfFlowChild(
auto& line_of_positioned_item =
is_row_axis ? column_of_positioned_item_ : row_of_positioned_item_;
start = is_row_axis ? BorderLogicalLeft() : BorderBefore();
- if (Optional<size_t> line = line_of_positioned_item.at(&child)) {
+ if (base::Optional<size_t> line = line_of_positioned_item.at(&child)) {
auto& positions = is_row_axis ? column_positions_ : row_positions_;
start = positions[line.value()];
}
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 4cdeaf6665b..929e6954470 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_grid.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_grid.h
@@ -95,7 +95,7 @@ class LayoutGrid final : public LayoutBlock {
GridTrackSizingDirection,
size_t start_line,
size_t span,
- Optional<LayoutUnit> available_size) const;
+ base::Optional<LayoutUnit> available_size) const;
bool CachedHasDefiniteLogicalHeight() const;
bool IsBaselineAlignmentForChild(const LayoutBox& child,
GridAxis = kGridColumnAxis) const;
@@ -108,6 +108,10 @@ class LayoutGrid final : public LayoutBlock {
LayoutUnit GridGap(GridTrackSizingDirection) const;
LayoutUnit GridItemOffset(GridTrackSizingDirection) const;
+ LayoutUnit EstimatedGridAreaBreadthForChild(const Grid&,
+ const LayoutBox&,
+ GridTrackSizingDirection) const;
+
StyleContentAlignmentData ContentAlignment(GridTrackSizingDirection) const;
protected:
@@ -144,14 +148,15 @@ class LayoutGrid final : public LayoutBlock {
const ComputedStyle& new_style) const;
void StyleDidChange(StyleDifference, const ComputedStyle*) override;
- Optional<LayoutUnit> AvailableSpaceForGutters(GridTrackSizingDirection) const;
+ base::Optional<LayoutUnit> AvailableSpaceForGutters(
+ GridTrackSizingDirection) const;
bool ExplicitGridDidResize(const ComputedStyle&) const;
bool NamedGridLinesDefinitionDidChange(const ComputedStyle&) const;
size_t ComputeAutoRepeatTracksCount(
GridTrackSizingDirection,
- Optional<LayoutUnit> available_size) const;
+ base::Optional<LayoutUnit> available_size) const;
size_t ClampAutoRepeatTracks(GridTrackSizingDirection,
size_t auto_repeat_tracks) const;
@@ -159,8 +164,12 @@ class LayoutGrid final : public LayoutBlock {
Grid&,
GridTrackSizingDirection) const;
- void PlaceItemsOnGrid(Grid&,
- Optional<LayoutUnit> available_logical_width) const;
+ void LayoutOrthogonalWritingModeRoots(const Grid&,
+ const Vector<LayoutBox*>&) const;
+
+ void PlaceItemsOnGrid(
+ Grid&,
+ base::Optional<LayoutUnit> available_logical_width) const;
void PopulateExplicitGridAndOrderIterator(Grid&) const;
std::unique_ptr<GridArea> CreateEmptyGridAreaAtSpecifiedPositionsOutsideGrid(
const Grid&,
@@ -189,6 +198,7 @@ class LayoutGrid final : public LayoutBlock {
void RepeatTracksSizingIfNeeded(LayoutUnit available_space_for_columns,
LayoutUnit available_space_for_rows);
+ void UpdateGridAreaLogicalSize(LayoutBox&, LayoutSize) const;
void LayoutGridItems();
void PrepareChildForPositionedLayout(LayoutBox&);
bool HasStaticPositionForChild(const LayoutBox&,
@@ -284,7 +294,7 @@ class LayoutGrid final : public LayoutBlock {
LayoutUnit RowAxisBaselineOffsetForChild(const LayoutBox&) const;
LayoutUnit GridGap(GridTrackSizingDirection,
- Optional<LayoutUnit> available_size) const;
+ base::Optional<LayoutUnit> available_size) const;
size_t GridItemSpan(const LayoutBox&, GridTrackSizingDirection);
@@ -308,14 +318,15 @@ class LayoutGrid final : public LayoutBlock {
LayoutUnit offset_between_rows_;
Vector<LayoutBox*> grid_items_overflowing_grid_area_;
- typedef HashMap<const LayoutBox*, Optional<size_t>> OutOfFlowPositionsMap;
+ typedef HashMap<const LayoutBox*, base::Optional<size_t>>
+ OutOfFlowPositionsMap;
OutOfFlowPositionsMap column_of_positioned_item_;
OutOfFlowPositionsMap row_of_positioned_item_;
LayoutUnit min_content_height_{-1};
LayoutUnit max_content_height_{-1};
- Optional<bool> has_definite_logical_height_;
+ base::Optional<bool> has_definite_logical_height_;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutGrid, IsLayoutGrid());
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 af913d3cc72..6de2e94ed6d 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
@@ -70,8 +70,8 @@ void LayoutHTMLCanvas::CanvasSizeChanged() {
LayoutSize old_size = Size();
UpdateLogicalWidth();
UpdateLogicalHeight();
- if (old_size == Size() && !HasOverrideLogicalContentWidth() &&
- !HasOverrideLogicalContentHeight()) {
+ 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
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_iframe.cc b/chromium/third_party/blink/renderer/core/layout/layout_iframe.cc
index 549a6576530..b0c1de439bb 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_iframe.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_iframe.cc
@@ -61,11 +61,4 @@ void LayoutIFrame::UpdateLayout() {
ClearNeedsLayout();
}
-void LayoutIFrame::UpdateAfterLayout() {
- if (RuntimeEnabledFeatures::ImplicitRootScrollerEnabled() && GetNode())
- GetDocument().GetRootScrollerController().ConsiderForImplicit(*GetNode());
-
- LayoutEmbeddedContent::UpdateAfterLayout();
-}
-
} // namespace blink
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 27a912413d9..33904fe895e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_iframe.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_iframe.h
@@ -41,7 +41,6 @@ class LayoutIFrame final : public LayoutEmbeddedContent {
bool IsInlineBlockOrInlineTable() const override;
void UpdateLayout() override;
- void UpdateAfterLayout() override;
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectLayoutIFrame ||
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 3b33eee410d..976366b60e1 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image.cc
@@ -39,17 +39,75 @@
#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_painter.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/svg/graphics/svg_image.h"
+#include "third_party/blink/renderer/platform/feature_policy/feature_policy.h"
namespace blink {
+namespace {
+constexpr float kmax_downscaling_ratio = 2.0f;
+
+bool CheckForOptimizedImagePolicy(const LocalFrame& frame,
+ LayoutImage* layout_image,
+ ImageResourceContent* new_image) {
+ // Invert the image if the document does not have the 'legacy-image-formats'
+ // feature enabled, and the image is not one of the allowed formats.
+ if (IsSupportedInFeaturePolicy(
+ mojom::FeaturePolicyFeature::kLegacyImageFormats) &&
+ !frame.IsFeatureEnabled(
+ mojom::FeaturePolicyFeature::kLegacyImageFormats)) {
+ if (!new_image->IsAcceptableContentType()) {
+ return true;
+ }
+ }
+ // Invert the image if the document does not have the image-compression'
+ // feature enabled and the image is not sufficiently-well-compressed.
+ if (IsSupportedInFeaturePolicy(
+ mojom::FeaturePolicyFeature::kImageCompression) &&
+ !frame.IsFeatureEnabled(mojom::FeaturePolicyFeature::kImageCompression)) {
+ if (!new_image->IsAcceptableCompressionRatio())
+ return true;
+ }
+ return false;
+}
+
+bool CheckForMaxDownscalingImagePolicy(const LocalFrame& frame,
+ HTMLImageElement* element,
+ LayoutImage* layout_image) {
+ if (!IsSupportedInFeaturePolicy(
+ mojom::FeaturePolicyFeature::kMaxDownscalingImage) ||
+ frame.IsFeatureEnabled(mojom::FeaturePolicyFeature::kMaxDownscalingImage))
+ return false;
+ // Invert the image if the image's size is more than 2 times bigger than the
+ // size it is being laid-out by.
+ LayoutUnit layout_width = layout_image->ContentBoxRect().Width();
+ LayoutUnit layout_height = layout_image->ContentBoxRect().Height();
+ auto image_width = element->naturalWidth();
+ auto image_height = element->naturalHeight();
+ if (layout_width > 0 && layout_height > 0 && image_width > 0 &&
+ image_height > 0) {
+ double device_pixel_ratio = frame.DevicePixelRatio();
+ if (LayoutUnit(image_width / kmax_downscaling_ratio * device_pixel_ratio) >
+ layout_width ||
+ LayoutUnit(image_height / kmax_downscaling_ratio * device_pixel_ratio) >
+ layout_height)
+ return true;
+ }
+ return false;
+}
+
+} // namespace
+
using namespace HTMLNames;
LayoutImage::LayoutImage(Element* element)
: LayoutReplaced(element, LayoutSize()),
did_increment_visually_non_empty_pixel_count_(false),
is_generated_content_(false),
- image_device_pixel_ratio_(1.0f) {}
+ image_device_pixel_ratio_(1.0f),
+ is_legacy_format_or_compressed_image_(false),
+ is_downscaled_image_(false) {}
LayoutImage* LayoutImage::CreateAnonymous(PseudoElement& pseudo) {
LayoutImage* image = new LayoutImage(nullptr);
@@ -197,6 +255,15 @@ void LayoutImage::ImageNotifyFinished(ImageResourceContent* new_image) {
InvalidateBackgroundObscurationStatus();
+ // Check for optimized image policies.
+ if (View() && View()->GetFrameView()) {
+ bool old_flag = ShouldInvertColor();
+ is_legacy_format_or_compressed_image_ = CheckForOptimizedImagePolicy(
+ View()->GetFrameView()->GetFrame(), this, new_image);
+ if (old_flag != ShouldInvertColor())
+ UpdateShouldInvertColor();
+ }
+
if (new_image == image_resource_->CachedImage()) {
// tell any potential compositing layers
// that the image is done and they can reference it directly.
@@ -297,6 +364,20 @@ bool LayoutImage::NodeAtPoint(HitTestResult& result,
void LayoutImage::ComputeIntrinsicSizingInfo(
IntrinsicSizingInfo& intrinsic_sizing_info) const {
+ if (SVGImage* svg_image = EmbeddedSVGImage()) {
+ svg_image->GetIntrinsicSizingInfo(intrinsic_sizing_info);
+
+ // Handle zoom & vertical writing modes here, as the embedded SVG document
+ // doesn't know about them.
+ intrinsic_sizing_info.size.Scale(Style()->EffectiveZoom());
+ if (Style()->GetObjectFit() != EObjectFit::kScaleDown)
+ intrinsic_sizing_info.size.Scale(ImageDevicePixelRatio());
+
+ if (!IsHorizontalWritingMode())
+ intrinsic_sizing_info.Transpose();
+ return;
+ }
+
LayoutReplaced::ComputeIntrinsicSizingInfo(intrinsic_sizing_info);
// Our intrinsicSize is empty if we're laying out generated images with
@@ -326,19 +407,11 @@ void LayoutImage::ComputeIntrinsicSizingInfo(
bool LayoutImage::NeedsPreferredWidthsRecalculation() const {
if (LayoutReplaced::NeedsPreferredWidthsRecalculation())
return true;
- return EmbeddedReplacedContent();
+ SVGImage* svg_image = EmbeddedSVGImage();
+ return svg_image && svg_image->HasIntrinsicSizingInfo();
}
-bool LayoutImage::GetNestedIntrinsicSizingInfo(
- IntrinsicSizingInfo& intrinsic_sizing_info) const {
- if (LayoutReplaced* content_layout_object = EmbeddedReplacedContent()) {
- content_layout_object->ComputeIntrinsicSizingInfo(intrinsic_sizing_info);
- return true;
- }
- return false;
-}
-
-LayoutReplaced* LayoutImage::EmbeddedReplacedContent() const {
+SVGImage* LayoutImage::EmbeddedSVGImage() const {
if (!image_resource_)
return nullptr;
ImageResourceContent* cached_image = image_resource_->CachedImage();
@@ -346,10 +419,37 @@ LayoutReplaced* LayoutImage::EmbeddedReplacedContent() const {
// https://crbug.com/761026
if (!cached_image || cached_image->IsCacheValidator())
return nullptr;
- Image* image = cached_image->GetImage();
- if (!image->IsSVGImage())
- return nullptr;
- return ToSVGImage(image)->EmbeddedReplacedContent();
+ return ToSVGImageOrNull(cached_image->GetImage());
+}
+
+bool LayoutImage::ShouldInvertColor() const {
+ return is_downscaled_image_ || is_legacy_format_or_compressed_image_;
+}
+
+void LayoutImage::UpdateShouldInvertColor() {
+ SetNeedsPaintPropertyUpdate();
+ // If composited image, update compositing layer.
+ if (Layer())
+ Layer()->SetNeedsCompositingInputsUpdate();
+}
+
+void LayoutImage::UpdateShouldInvertColorForTest(bool value) {
+ is_downscaled_image_ = value;
+ is_legacy_format_or_compressed_image_ = value;
+ UpdateShouldInvertColor();
+}
+
+void LayoutImage::UpdateAfterLayout() {
+ LayoutBox::UpdateAfterLayout();
+ Node* node = GetNode();
+ // Check for optimized image policies.
+ if (IsHTMLImageElement(node) && View() && View()->GetFrameView()) {
+ bool old_flag = ShouldInvertColor();
+ is_downscaled_image_ = CheckForMaxDownscalingImagePolicy(
+ View()->GetFrameView()->GetFrame(), ToHTMLImageElement(node), this);
+ if (old_flag != ShouldInvertColor())
+ UpdateShouldInvertColor();
+ }
}
} // namespace blink
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 e59f84ff12c..021c5035e57 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_image.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_image.h
@@ -35,6 +35,7 @@ namespace blink {
class HTMLAreaElement;
class HTMLMapElement;
+class SVGImage;
// LayoutImage is used to display any image type.
//
@@ -87,11 +88,19 @@ class CORE_EXPORT LayoutImage : public LayoutReplaced {
const char* GetName() const override { return "LayoutImage"; }
+ // When an image element violates feature policy optimized image policies, it
+ // should be rendered with inverted color.
+ // https://github.com/WICG/feature-policy/blob/gh-pages/policies/optimized-images.md
+ bool ShouldInvertColor() const;
+ void UpdateShouldInvertColor();
+ void UpdateShouldInvertColorForTest(bool);
+
+ void UpdateAfterLayout() override;
+
protected:
bool NeedsPreferredWidthsRecalculation() const final;
- LayoutReplaced* EmbeddedReplacedContent() const;
- void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const final;
- bool GetNestedIntrinsicSizingInfo(IntrinsicSizingInfo&) const;
+ SVGImage* EmbeddedSVGImage() const;
+ void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
void ImageChanged(WrappedImagePtr,
CanDeferInvalidation,
@@ -147,6 +156,12 @@ class CORE_EXPORT LayoutImage : public LayoutReplaced {
// This field stores whether this image is generated with 'content'.
bool is_generated_content_;
float image_device_pixel_ratio_;
+
+ // These flags indicate if the image violates one or more optimized image
+ // policies. When any policy is violated, the image should be rendered with
+ // inverted color.
+ bool is_legacy_format_or_compressed_image_;
+ bool is_downscaled_image_;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutImage, IsLayoutImage());
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 b79ce1d326d..278a1099131 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_inline.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_inline.cc
@@ -36,14 +36,16 @@
#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/paint/box_painter.h"
#include "third_party/blink/renderer/core/paint/inline_painter.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
#include "third_party/blink/renderer/core/paint/object_painter.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
#include "third_party/blink/renderer/platform/geometry/region.h"
-#include "third_party/blink/renderer/platform/geometry/transform_state.h"
+#include "third_party/blink/renderer/platform/transforms/transform_state.h"
namespace blink {
@@ -242,6 +244,9 @@ void LayoutInline::StyleDidChange(StyleDifference diff,
}
PropagateStyleToAnonymousChildren();
+
+ // Only filtered inlines can contain fixed position elements.
+ SetCanContainFixedPositionObjects(new_style.HasFilter());
}
void LayoutInline::UpdateAlwaysCreateLineBoxes(bool full_layout) {
@@ -902,6 +907,26 @@ bool LayoutInline::NodeAtPoint(HitTestResult& result,
const HitTestLocation& location_in_container,
const LayoutPoint& accumulated_offset,
HitTestAction hit_test_action) {
+ if (EnclosingNGBlockFlow()) {
+ // 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)) {
+ // NGBoxFragmentPainter::NodeAtPoint() takes an offset that is accumulated
+ // up to its parent fragment. Compute this offset.
+ LayoutPoint adjusted_location =
+ accumulated_offset +
+ fragment->Parent()->InlineOffsetToContainerBox().ToLayoutPoint();
+ if (NGBoxFragmentPainter(*fragment).NodeAtPoint(
+ result, location_in_container, adjusted_location,
+ accumulated_offset, hit_test_action))
+ return true;
+ }
+ return false;
+ }
+
return line_boxes_.HitTest(LineLayoutBoxModel(this), result,
location_in_container, accumulated_offset,
hit_test_action);
@@ -1318,8 +1343,9 @@ bool LayoutInline::MapToVisualRectInAncestorSpaceInternal(
ancestor, transform_state, visual_rect_flags);
}
-LayoutSize LayoutInline::OffsetFromContainer(
- const LayoutObject* container) const {
+LayoutSize LayoutInline::OffsetFromContainerInternal(
+ const LayoutObject* container,
+ bool ignore_scroll_offset) const {
DCHECK_EQ(container, Container());
LayoutSize offset;
@@ -1327,7 +1353,7 @@ LayoutSize LayoutInline::OffsetFromContainer(
offset += OffsetForInFlowPosition();
if (container->HasOverflowClip())
- offset -= ToLayoutBox(container)->ScrolledContentOffset();
+ offset += OffsetFromScrollableContainer(container, ignore_scroll_offset);
return offset;
}
@@ -1467,8 +1493,8 @@ LayoutSize LayoutInline::OffsetForInFlowPositionedInline(
const LayoutBox& child) const {
// FIXME: This function isn't right with mixed writing modes.
- DCHECK(IsInFlowPositioned());
- if (!IsInFlowPositioned())
+ DCHECK(IsInFlowPositioned() || StyleRef().HasFilter());
+ if (!IsInFlowPositioned() && !StyleRef().HasFilter())
return LayoutSize();
// When we have an enclosing relpositioned inline, we need to add in the
@@ -1618,9 +1644,6 @@ void LayoutInline::AddAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) {
void LayoutInline::InvalidateDisplayItemClients(
PaintInvalidationReason invalidation_reason) const {
- // TODO(yoichio): Cover other PaintInvalidateionReasons.
- DCHECK(invalidation_reason != PaintInvalidationReason::kSelection ||
- !EnclosingNGBlockFlow());
ObjectPaintInvalidator paint_invalidator(*this);
if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
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 269b95e832f..00c7f33a17f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_inline.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_inline.h
@@ -146,8 +146,6 @@ class CORE_EXPORT LayoutInline : public LayoutBoxModelObject {
const LayoutPoint& accumulated_offset) const final;
FloatRect LocalBoundingBoxRectForAccessibility() const final;
- LayoutSize OffsetFromContainer(const LayoutObject*) const final;
-
LayoutRect LinesBoundingBox() const;
LayoutRect VisualOverflowRect() const final;
@@ -230,6 +228,9 @@ class CORE_EXPORT LayoutInline : public LayoutBoxModelObject {
void AbsoluteQuadsForSelf(Vector<FloatQuad>& quads,
MapCoordinatesFlags mode = 0) const override;
+ LayoutSize OffsetFromContainerInternal(const LayoutObject*,
+ bool ignore_scroll_offset) const final;
+
private:
LayoutObjectChildList* VirtualChildren() final { return Children(); }
const LayoutObjectChildList* VirtualChildren() const final {
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 6fa072e7ae6..e71516b8509 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
@@ -119,4 +119,126 @@ TEST_F(LayoutInlineTest, RegionHitTest) {
EXPECT_TRUE(hit_outcome);
}
+// crbug.com/844746
+TEST_P(ParameterizedLayoutInlineTest, RelativePositionedHitTest) {
+ LoadAhem();
+ SetBodyInnerHTML(
+ "<div style='font: 10px/10px Ahem'>"
+ " <span style='position: relative'>XXX</span>"
+ "</div>");
+
+ HitTestRequest hit_request(HitTestRequest::kReadOnly |
+ HitTestRequest::kActive);
+ const LayoutPoint container_offset(8, 8);
+ const LayoutPoint hit_location(18, 15);
+
+ Element* div = GetDocument().QuerySelector("div");
+ Element* span = GetDocument().QuerySelector("span");
+ Node* text = span->firstChild();
+
+ // Shouldn't hit anything in SPAN as it's in another paint layer
+ {
+ LayoutObject* layout_div = div->GetLayoutObject();
+ HitTestResult hit_result(hit_request, hit_location);
+ bool hit_outcome = layout_div->HitTestAllPhases(hit_result, hit_location,
+ container_offset);
+ EXPECT_TRUE(hit_outcome);
+ EXPECT_EQ(div, hit_result.InnerNode());
+ }
+
+ // SPAN and its descendants can be hit only with a hit test that starts from
+ // the SPAN itself.
+ {
+ LayoutObject* layout_span = span->GetLayoutObject();
+ HitTestResult hit_result(hit_request, hit_location);
+ bool hit_outcome = layout_span->HitTestAllPhases(hit_result, hit_location,
+ container_offset);
+ EXPECT_TRUE(hit_outcome);
+ EXPECT_EQ(text, hit_result.InnerNode());
+ }
+
+ // Hit test from LayoutView to verify that everything works together.
+ {
+ HitTestResult hit_result(hit_request, hit_location);
+ bool hit_outcome = GetLayoutView().HitTest(hit_result);
+ EXPECT_TRUE(hit_outcome);
+ EXPECT_EQ(text, hit_result.InnerNode());
+ }
+}
+
+TEST_P(ParameterizedLayoutInlineTest, MultilineRelativePositionedHitTest) {
+ LoadAhem();
+ SetBodyInnerHTML(
+ "<div style='font: 10px/10px Ahem; width: 30px'>"
+ " <span id=span style='position: relative'>"
+ " XXX"
+ " <span id=line2 style='background-color: red'>YYY</span>"
+ " <img style='width: 10px; height: 10px; vertical-align: bottom'>"
+ " </span>"
+ "</div>");
+
+ LayoutObject* layout_span = GetLayoutObjectByElementId("span");
+ HitTestRequest hit_request(HitTestRequest::kReadOnly |
+ HitTestRequest::kActive |
+ HitTestRequest::kIgnorePointerEventsNone);
+ const LayoutPoint container_offset(8, 8);
+
+ // Hit test first line
+ {
+ LayoutPoint hit_location(13, 13);
+ Node* target = GetElementById("span")->firstChild();
+
+ HitTestResult hit_result(hit_request, hit_location);
+ bool hit_outcome = layout_span->HitTestAllPhases(hit_result, hit_location,
+ container_offset);
+ EXPECT_TRUE(hit_outcome);
+ EXPECT_EQ(target, hit_result.InnerNode());
+
+ // Initiate a hit test from LayoutView to verify the "natural" process.
+ HitTestResult layout_view_hit_result(hit_request, hit_location);
+ bool layout_view_hit_outcome =
+ GetLayoutView().HitTest(layout_view_hit_result);
+ EXPECT_TRUE(layout_view_hit_outcome);
+ EXPECT_EQ(target, layout_view_hit_result.InnerNode());
+ }
+
+ // Hit test second line
+ {
+ LayoutPoint hit_location(13, 23);
+ Node* target = GetElementById("line2")->firstChild();
+
+ HitTestResult hit_result(hit_request, hit_location);
+ bool hit_outcome = layout_span->HitTestAllPhases(hit_result, hit_location,
+ container_offset);
+ EXPECT_TRUE(hit_outcome);
+ EXPECT_EQ(target, hit_result.InnerNode());
+
+ // Initiate a hit test from LayoutView to verify the "natural" process.
+ HitTestResult layout_view_hit_result(hit_request, hit_location);
+ bool layout_view_hit_outcome =
+ GetLayoutView().HitTest(layout_view_hit_result);
+ EXPECT_TRUE(layout_view_hit_outcome);
+ EXPECT_EQ(target, layout_view_hit_result.InnerNode());
+ }
+
+ // Hit test image in third line
+ {
+ LayoutPoint hit_location(13, 33);
+ Node* target = GetDocument().QuerySelector("img");
+
+ HitTestResult hit_result(hit_request, hit_location);
+ bool hit_outcome = layout_span->HitTestAllPhases(hit_result, hit_location,
+ container_offset);
+ EXPECT_TRUE(hit_outcome);
+ EXPECT_EQ(target, hit_result.InnerNode());
+
+ // Initiate a hit test from LayoutView to verify the "natural" process.
+ HitTestResult layout_view_hit_result(hit_request, hit_location);
+ bool layout_view_hit_outcome =
+ GetLayoutView().HitTest(layout_view_hit_result);
+ EXPECT_TRUE(layout_view_hit_outcome);
+ EXPECT_EQ(target, layout_view_hit_result.InnerNode());
+ }
+}
+
} // namespace blink
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 c0b7c3b5b82..9be563b0552 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
@@ -118,8 +118,10 @@ bool LayoutListItem::IsEmpty() const {
return LastChild() == marker_;
}
-static LayoutObject* GetParentOfFirstLineBox(LayoutBlockFlow* curr,
- LayoutObject* marker) {
+namespace {
+
+LayoutObject* GetParentOfFirstLineBox(LayoutBlockFlow* curr,
+ LayoutObject* marker) {
LayoutObject* first_child = curr->FirstChild();
if (!first_child)
return nullptr;
@@ -159,31 +161,42 @@ static LayoutObject* GetParentOfFirstLineBox(LayoutBlockFlow* curr,
return nullptr;
}
-static LayoutObject* FirstNonMarkerChild(LayoutObject* parent) {
+LayoutObject* FirstNonMarkerChild(LayoutObject* parent) {
LayoutObject* result = parent->SlowFirstChild();
while (result && result->IsListMarker())
result = result->NextSibling();
return result;
}
+void ForceLogicalHeight(LayoutObject& layout_object, const Length& height) {
+ DCHECK(layout_object.IsAnonymous());
+ if (layout_object.StyleRef().LogicalHeight() == height)
+ return;
+
+ scoped_refptr<ComputedStyle> new_style =
+ ComputedStyle::Clone(layout_object.StyleRef());
+ new_style->SetLogicalHeight(height);
+ layout_object.SetStyleInternal(std::move(new_style));
+}
+
+} // namespace
+
// 1. Place marker as a child of <li>. Make sure don't share parent with empty
-// inline elements which don't gernerate inlineBox.
+// inline elements which don't generate InlineBox.
// 2. Manage the logicalHeight of marker_container(marker's anonymous parent):
-// If marker is the only child of marker_container, set logicalHeight of
-// marker_container to 0px; else restore it to logicalHeight of <li>.
+// If marker is the only child of marker_container, set LogicalHeight of
+// marker_container to 0px; else restore it to LogicalHeight of <li>.
bool LayoutListItem::PrepareForBlockDirectionAlign(
const LayoutObject* line_box_parent) {
LayoutObject* marker_parent = marker_->Parent();
// Deal with the situation of layout tree changed.
if (marker_parent && marker_parent->IsAnonymous()) {
// When list-position-style change from outside to inside, we need to
- // restore logicalHeight. So add isinside().
+ // restore LogicalHeight. So add IsInside().
if (marker_->IsInside() || marker_->NextSibling()) {
- // Restore old marker_container logicalHeight.
- if (marker_parent->MutableStyleRef().LogicalHeight().IsZero()) {
- marker_parent->MutableStyleRef().SetLogicalHeight(
- Style()->LogicalHeight());
- }
+ // Restore old marker_container LogicalHeight.
+ if (marker_parent->StyleRef().LogicalHeight().IsZero())
+ ForceLogicalHeight(*marker_parent, StyleRef().LogicalHeight());
// 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:
@@ -192,9 +205,8 @@ bool LayoutListItem::PrepareForBlockDirectionAlign(
marker_->Remove();
marker_parent = nullptr;
}
- } else {
- if (line_box_parent)
- marker_parent->MutableStyleRef().SetLogicalHeight(Length(0, kFixed));
+ } else if (line_box_parent) {
+ ForceLogicalHeight(*marker_parent, Length(0, kFixed));
}
}
@@ -202,10 +214,10 @@ bool LayoutListItem::PrepareForBlockDirectionAlign(
if (!marker_parent) {
LayoutObject* before_child = FirstNonMarkerChild(this);
if (!marker_->IsInside() && before_child && before_child->IsLayoutBlock()) {
- // Create marker_container and set its logicalHeight to 0px.
+ // Create marker_container and set its LogicalHeight to 0px.
LayoutBlock* marker_container = CreateAnonymousBlock();
if (line_box_parent)
- marker_container->MutableStyleRef().SetLogicalHeight(Length(0, kFixed));
+ ForceLogicalHeight(*marker_container, Length(0, kFixed));
marker_container->AddChild(marker_,
FirstNonMarkerChild(marker_container));
AddChild(marker_container, before_child);
@@ -266,10 +278,10 @@ bool LayoutListItem::UpdateMarkerLocation() {
if (marker_parent != line_box_parent) {
marker_->Remove();
line_box_parent->AddChild(marker_, FirstNonMarkerChild(line_box_parent));
- // TODO(rhogan): lineBoxParent and markerParent may be deleted by addChild,
- // so they are not safe to reference here.
- // Once we have a safe way of referencing them delete markerParent if it is
- // an empty anonymous block.
+ // 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();
return true;
}
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 a555d54d258..37451f7e409 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
@@ -114,23 +114,6 @@ bool LayoutListMarker::IsImage() const {
return image_ && !image_->ErrorOccurred();
}
-LayoutRect LayoutListMarker::LocalSelectionRect() const {
- InlineBox* box = InlineBoxWrapper();
- if (!box)
- return LayoutRect(LayoutPoint(), Size());
- RootInlineBox& root = InlineBoxWrapper()->Root();
- const ComputedStyle* block_style = root.Block().Style();
- LayoutUnit new_logical_top =
- block_style->IsFlippedBlocksWritingMode()
- ? InlineBoxWrapper()->LogicalBottom() - root.SelectionBottom()
- : root.SelectionTop() - InlineBoxWrapper()->LogicalTop();
- return block_style->IsHorizontalWritingMode()
- ? LayoutRect(LayoutUnit(), new_logical_top, Size().Width(),
- root.SelectionHeight())
- : LayoutRect(new_logical_top, LayoutUnit(), root.SelectionHeight(),
- Size().Height());
-}
-
void LayoutListMarker::Paint(const PaintInfo& paint_info,
const LayoutPoint& paint_offset) const {
ListMarkerPainter(*this).Paint(paint_info, paint_offset);
@@ -194,16 +177,14 @@ void LayoutListMarker::ImageChanged(WrappedImagePtr o,
}
void LayoutListMarker::UpdateMarginsAndContent() {
- UpdateContent();
- UpdateMargins();
+ if (PreferredLogicalWidthsDirty())
+ ComputePreferredLogicalWidths();
+ else
+ UpdateMargins();
}
void LayoutListMarker::UpdateContent() {
- // FIXME: This if-statement is just a performance optimization, but it's messy
- // to use the preferredLogicalWidths dirty bit for this.
- // It's unclear if this is a premature optimization.
- if (!PreferredLogicalWidthsDirty())
- return;
+ DCHECK(PreferredLogicalWidthsDirty());
text_ = "";
@@ -299,8 +280,16 @@ void LayoutListMarker::UpdateMargins() {
std::tie(margin_start, margin_end) =
InlineMarginsForOutside(style, IsImage(), MinPreferredLogicalWidth());
}
- MutableStyleRef().SetMarginStart(Length(margin_start, kFixed));
- MutableStyleRef().SetMarginEnd(Length(margin_end, kFixed));
+
+ Length start_length(margin_start, kFixed);
+ Length end_length(margin_end, kFixed);
+
+ 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));
+ }
}
std::pair<LayoutUnit, LayoutUnit> LayoutListMarker::InlineMarginsForInside(
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 b25b7645a0d..0d53ea51e60 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
@@ -67,7 +67,6 @@ class LayoutListMarker final : public LayoutBox {
LayoutUnit marker_inline_size);
LayoutRect GetRelativeMarkerRect() const;
- LayoutRect LocalSelectionRect() const final;
bool IsImage() const override;
const StyleImage* GetImage() const { return image_.Get(); }
const LayoutListItem* ListItem() const { return list_item_; }
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 01a437e0f9a..70c0aee3661 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_media.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_media.cc
@@ -92,11 +92,8 @@ void LayoutMedia::UpdateLayout() {
LayoutBox* layout_box = ToLayoutBox(child);
layout_box->SetLocation(new_rect.Location());
- // TODO(foolip): Remove the mutableStyleRef() and depend on CSS
- // width/height: inherit to match the media element size.
- layout_box->MutableStyleRef().SetHeight(Length(new_rect.Height(), kFixed));
- layout_box->MutableStyleRef().SetWidth(Length(width, kFixed));
-
+ layout_box->SetOverrideLogicalWidth(width);
+ layout_box->SetOverrideLogicalHeight(new_rect.Height());
layout_box->ForceLayout();
}
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 648e3fed223..f2a37a50b43 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_media.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_media.h
@@ -26,8 +26,8 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_MEDIA_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_MEDIA_H_
+#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/layout_image.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink {
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
index ffa3a05e368..22186050829 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_menu_list.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_menu_list.cc
@@ -32,6 +32,7 @@
#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/platform/text/platform_locale.h"
@@ -59,6 +60,25 @@ bool LayoutMenuList::IsChildAllowed(LayoutObject* object,
return object->IsAnonymous() && !object->IsLayoutFullScreen();
}
+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_->SetStyleInternal(std::move(inner_style));
+ // LayoutMenuList::ControlClipRect() depends on inner_block_->ContentsSize().
+ SetNeedsPaintPropertyUpdate();
+}
+
void LayoutMenuList::CreateInnerBlock() {
if (inner_block_) {
DCHECK_EQ(FirstChild(), inner_block_);
@@ -68,7 +88,8 @@ void LayoutMenuList::CreateInnerBlock() {
// Create an anonymous block.
DCHECK(!FirstChild());
- inner_block_ = CreateAnonymousBlock();
+ inner_block_ = LayoutBlockFlow::CreateAnonymous(&GetDocument());
+ inner_block_->SetStyle(CreateInnerStyle());
button_text_ = LayoutText::CreateEmptyAnonymous(GetDocument());
// We need to set the text explicitly though it was specified in the
@@ -76,17 +97,25 @@ void LayoutMenuList::CreateInnerBlock() {
// specified in the constructor in a case of re-transforming.
button_text_->SetStyle(MutableStyle());
inner_block_->AddChild(button_text_);
-
- AdjustInnerStyle();
LayoutFlexibleBox::AddChild(inner_block_);
+
+ // LayoutMenuList::ControlClipRect() depends on inner_block_->ContentsSize().
+ SetNeedsPaintPropertyUpdate();
+}
+
+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 = inner_block_->MutableStyleRef();
+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(0, kFixed));
+
// 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
@@ -113,21 +142,16 @@ void LayoutMenuList::AdjustInnerStyle() {
LayoutTheme::GetTheme().PopupInternalPaddingTop(StyleRef()), kFixed));
inner_style.SetPaddingBottom(Length(
LayoutTheme::GetTheme().PopupInternalPaddingBottom(StyleRef()), kFixed));
+ inner_style.SetTextAlign(StyleRef().IsLeftToRightDirection()
+ ? ETextAlign::kLeft
+ : ETextAlign::kRight);
- if (option_style_) {
- if ((option_style_->Direction() != inner_style.Direction() ||
- option_style_->GetUnicodeBidi() != inner_style.GetUnicodeBidi()))
- inner_block_->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
- LayoutInvalidationReason::kStyleChange);
- inner_style.SetTextAlign(Style()->IsLeftToRightDirection()
- ? ETextAlign::kLeft
- : ETextAlign::kRight);
+ if (HasOptionStyleChanged(inner_style)) {
+ inner_block_->SetNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(
+ LayoutInvalidationReason::kStyleChange);
inner_style.SetDirection(option_style_->Direction());
inner_style.SetUnicodeBidi(option_style_->GetUnicodeBidi());
}
-
- // LayoutMenuList::ControlClipRect() depends on inner_block_->ContentsSize().
- SetNeedsPaintPropertyUpdate();
}
HTMLSelectElement* LayoutMenuList::SelectElement() const {
@@ -163,7 +187,7 @@ void LayoutMenuList::StyleDidChange(StyleDifference diff,
CreateInnerBlock();
button_text_->SetStyle(MutableStyle());
- AdjustInnerStyle();
+ UpdateInnerStyle();
UpdateInnerBlockHeight();
}
@@ -181,7 +205,7 @@ void LayoutMenuList::UpdateOptionsWidth() const {
String text = option->TextIndentedToRespectGroupLabel();
const ComputedStyle* item_style =
option->GetComputedStyle() ? option->GetComputedStyle() : Style();
- ApplyTextTransform(item_style, text, ' ');
+ 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(Style()->GetFont(), text, *Style());
@@ -228,6 +252,10 @@ void LayoutMenuList::UpdateFromElement() {
SetText(text.StripWhiteSpace());
DidUpdateActiveOption(option);
+
+ DCHECK(inner_block_);
+ if (HasOptionStyleChanged(inner_block_->StyleRef()))
+ UpdateInnerStyle();
}
void LayoutMenuList::SetText(const String& s) {
@@ -245,7 +273,8 @@ void LayoutMenuList::SetText(const String& s) {
is_empty_ = false;
button_text_->SetText(s.Impl(), true);
}
- AdjustInnerStyle();
+ // LayoutMenuList::ControlClipRect() depends on inner_block_->ContentsSize().
+ SetNeedsPaintPropertyUpdate();
}
String LayoutMenuList::GetText() const {
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
index ed2c9ae2ca9..af1433eaaa3 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_menu_list.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_menu_list.h
@@ -94,7 +94,10 @@ class CORE_EXPORT LayoutMenuList final : public LayoutFlexibleBox {
}
void CreateInnerBlock();
- void AdjustInnerStyle();
+ 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;
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 dff71416047..4f96b5b4d2d 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
@@ -106,7 +106,7 @@ static inline bool CanContainSpannerInParentFragmentationContext(
return false;
const LayoutBlockFlow& block_flow = ToLayoutBlockFlow(object);
return !block_flow.CreatesNewFormattingContext() &&
- !block_flow.HasTransformRelatedProperty() &&
+ !block_flow.StyleRef().CanContainFixedPositionObjects(false) &&
block_flow.GetPaginationBreakability() != LayoutBox::kForbidBreaks &&
!IsMultiColumnContainer(block_flow);
}
@@ -1169,8 +1169,8 @@ static inline bool NeedsToReinsertIntoFlowThread(
// re-evaluate the need for column sets. There may be out-of-flow descendants
// further down that become part of the flow thread, or cease to be part of
// the flow thread, because of this change.
- if (old_style.HasTransformRelatedProperty() !=
- new_style.HasTransformRelatedProperty())
+ if (old_style.CanContainFixedPositionObjects(false) !=
+ new_style.CanContainFixedPositionObjects(false))
return true;
return (old_style.HasInFlowPosition() &&
new_style.GetPosition() == EPosition::kStatic) ||
@@ -1461,4 +1461,45 @@ void LayoutMultiColumnFlowThread::RestoreMultiColumnLayoutState(
last_set_worked_on_ = state.ColumnSet();
}
+unsigned LayoutMultiColumnFlowThread::CalculateActualColumnCountAllowance()
+ const {
+ // To avoid performance problems, limit the maximum number of columns. Try to
+ // identify legitimate reasons for creating many columns, and allow many
+ // columns in such cases. The amount of "content" will determine the
+ // allowance.
+ unsigned allowance = 0;
+
+ // This isn't a particularly clever algorithm. For example, we don't account
+ // for parallel flows (absolute positioning, floats, visible overflow, table
+ // cells, flex items). We just generously add everything together.
+ for (const LayoutObject* descendant = this; descendant;) {
+ bool examine_children = false;
+ if (descendant->IsBox() && !descendant->IsInline() &&
+ !ToLayoutBox(descendant)->IsWritingModeRoot()) {
+ // Give one point to any kind of block level content.
+ allowance++;
+ if (descendant->IsLayoutBlockFlow() && descendant->ChildrenInline()) {
+ // It's a block-level block container in the same writing mode, and it
+ // has inline children. Count the lines and add it to the allowance.
+ allowance += ToLayoutBlockFlow(descendant)->LineCount();
+ } else {
+ // We could examine other types of layout modes (tables, flexbox, etc.)
+ // as well, but then again, that might be overkill. Just enter and see
+ // what we find.
+ examine_children = true;
+ }
+ }
+
+ if (allowance >= ColumnCountClampMax())
+ return ColumnCountClampMax();
+
+ descendant = examine_children
+ ? descendant->NextInPreOrder(this)
+ : descendant->NextInPreOrderAfterChildren(this);
+ }
+
+ DCHECK_LE(allowance, ColumnCountClampMax());
+ return std::max(allowance, ColumnCountClampMin());
+}
+
} // namespace blink
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 697e426394f..6b5e6548d48 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
@@ -190,6 +190,18 @@ class CORE_EXPORT LayoutMultiColumnFlowThread : public LayoutFlowThread,
unsigned ColumnCount() const { return column_count_; }
+ // Calculate and return the actual column count allowance. This method should
+ // only be called when we ended up with an actual column count larger than
+ // ColumnCountClampMin() in some fragmentainer group.
+ unsigned CalculateActualColumnCountAllowance() const;
+
+ // Any actual column count value lower than this will be allowed
+ // unconditionally.
+ static unsigned ColumnCountClampMin() { return 10; }
+
+ // The maximum actual column count we're going to allow.
+ static unsigned ColumnCountClampMax() { return 2000; }
+
// Total height available to columns and spanners. This is the multicol
// container's content box logical height, or 0 if auto.
LayoutUnit ColumnHeightAvailable() const { return column_height_available_; }
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 a35feb73599..21754a49bda 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object.cc
@@ -51,6 +51,7 @@
#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/frame/use_counter.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"
@@ -78,6 +79,8 @@
#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.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"
@@ -92,7 +95,6 @@
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/style/content_data.h"
#include "third_party/blink/renderer/core/style/cursor_data.h"
-#include "third_party/blink/renderer/platform/geometry/transform_state.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/graphics/paint/property_tree_state.h"
@@ -100,6 +102,7 @@
#include "third_party/blink/renderer/platform/instance_counters.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/transforms/transform_state.h"
#include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -140,7 +143,8 @@ LayoutBlock* FindContainingBlock(LayoutObject* container,
// LayoutObject::Container() method can actually be used to obtain the inline
// directly.
if (container && container->IsInline() && !container->IsAtomicInlineLevel()) {
- DCHECK(container->Style()->HasInFlowPosition());
+ DCHECK(container->Style()->HasInFlowPosition() ||
+ container->Style()->HasFilter());
container = container->ContainingBlock(skip_info);
}
@@ -265,6 +269,8 @@ LayoutObject* LayoutObject::CreateObject(Element* element,
return new LayoutNGTableCell(element);
return new LayoutTableCell(element);
case EDisplay::kTableCaption:
+ if (ShouldUseNewLayout(style))
+ return new LayoutNGTableCaption(element);
return new LayoutTableCaption(element);
case EDisplay::kWebkitBox:
case EDisplay::kWebkitInlineBox:
@@ -273,8 +279,7 @@ LayoutObject* LayoutObject::CreateObject(Element* element,
case EDisplay::kInlineFlex:
if (RuntimeEnabledFeatures::LayoutNGFlexBoxEnabled() &&
ShouldUseNewLayout(style)) {
- // TODO(dgrogan): Change this to new class LayoutNGFlex.
- return new LayoutNGBlockFlow(element);
+ return new LayoutNGFlexibleBox(element);
}
return new LayoutFlexibleBox(element);
case EDisplay::kGrid:
@@ -1004,6 +1009,11 @@ inline void LayoutObject::InvalidateContainerPreferredLogicalWidths() {
LayoutObject* LayoutObject::ContainerForAbsolutePosition(
AncestorSkipInfo* skip_info) const {
return FindAncestorByPredicate(this, skip_info, [](LayoutObject* candidate) {
+ if (!candidate->CanContainAbsolutePositionObjects() &&
+ candidate->StyleRef().ContainsLayout()) {
+ UseCounter::Count(candidate->GetDocument(),
+ WebFeature::kCSSContainLayoutPositionedDescendants);
+ }
return candidate->CanContainAbsolutePositionObjects();
});
}
@@ -1012,6 +1022,11 @@ LayoutObject* LayoutObject::ContainerForFixedPosition(
AncestorSkipInfo* skip_info) const {
DCHECK(!IsText());
return FindAncestorByPredicate(this, skip_info, [](LayoutObject* candidate) {
+ if (!candidate->CanContainFixedPositionObjects() &&
+ candidate->StyleRef().ContainsLayout()) {
+ UseCounter::Count(candidate->GetDocument(),
+ WebFeature::kCSSContainLayoutPositionedDescendants);
+ }
return candidate->CanContainFixedPositionObjects();
});
}
@@ -1211,7 +1226,7 @@ bool LayoutObject::GetUpperLeftCorner(ExpandScrollMargin expand,
}
if (runner->IsText() && !runner->IsBR()) {
- const Optional<FloatPoint> maybe_point =
+ const base::Optional<FloatPoint> maybe_point =
ToLayoutText(runner)->GetUpperLeftCorner();
if (maybe_point.has_value()) {
point = runner->LocalToAbsolute(maybe_point.value(), kUseTransforms);
@@ -1560,23 +1575,30 @@ LayoutRect LayoutObject::LocalVisualRectIgnoringVisibility() const {
bool LayoutObject::MapToVisualRectInAncestorSpaceInternalFastPath(
const LayoutBoxModelObject* ancestor,
LayoutRect& rect,
- VisualRectFlags visual_rect_flags) const {
+ VisualRectFlags visual_rect_flags,
+ bool& intersects) const {
if (!(visual_rect_flags & kUseGeometryMapper) ||
!RuntimeEnabledFeatures::SlimmingPaintV175Enabled() ||
- (visual_rect_flags & kEdgeInclusive) ||
!FirstFragment().HasLocalBorderBoxProperties() || !ancestor ||
!ancestor->FirstFragment().HasLocalBorderBoxProperties()) {
+ intersects = true;
return false;
}
- if (ancestor == this)
+ if (ancestor == this) {
+ intersects = true;
return true;
+ }
rect.MoveBy(FirstFragment().PaintOffset());
FloatClipRect clip_rect((FloatRect(rect)));
- GeometryMapper::LocalToAncestorVisualRect(
+ intersects = GeometryMapper::LocalToAncestorVisualRect(
FirstFragment().LocalBorderBoxProperties(),
- ancestor->FirstFragment().ContentsProperties(), clip_rect);
+ ancestor->FirstFragment().ContentsProperties(), clip_rect,
+ kIgnorePlatformOverlayScrollbarSize,
+ (visual_rect_flags & kEdgeInclusive) ? kInclusiveIntersect
+ : kNonInclusiveIntersect);
+
rect = LayoutRect(clip_rect.Rect());
rect.MoveBy(-ancestor->FirstFragment().PaintOffset());
@@ -1587,17 +1609,18 @@ bool LayoutObject::MapToVisualRectInAncestorSpace(
const LayoutBoxModelObject* ancestor,
LayoutRect& rect,
VisualRectFlags visual_rect_flags) const {
- if (MapToVisualRectInAncestorSpaceInternalFastPath(ancestor, rect,
- visual_rect_flags))
- return !rect.IsEmpty();
+ bool intersects = true;
+ if (MapToVisualRectInAncestorSpaceInternalFastPath(
+ ancestor, rect, visual_rect_flags, intersects))
+ return intersects;
TransformState transform_state(TransformState::kApplyTransformDirection,
FloatQuad(FloatRect(rect)));
- bool retval = MapToVisualRectInAncestorSpaceInternal(
- ancestor, transform_state, visual_rect_flags);
+ intersects = MapToVisualRectInAncestorSpaceInternal(ancestor, transform_state,
+ visual_rect_flags);
transform_state.Flatten();
rect = LayoutRect(transform_state.LastPlanarQuad().BoundingBox());
- return retval;
+ return intersects;
}
bool LayoutObject::MapToVisualRectInAncestorSpaceInternal(
@@ -2115,14 +2138,25 @@ void LayoutObject::StyleWillChange(StyleDifference diff,
//
// Since a CSS property cannot be applied directly to a text node, a
// handler will have already been added for its parent so ignore it.
- TouchAction old_touch_action =
- style_ ? style_->GetTouchAction() : TouchAction::kTouchActionAuto;
+ //
+ // 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;
+ bool is_document_element = GetNode() && IsDocumentElement();
+ if (style_) {
+ old_touch_action = is_document_element ? style_->GetEffectiveTouchAction()
+ : style_->GetTouchAction();
+ }
+ TouchAction new_touch_action = is_document_element
+ ? new_style.GetEffectiveTouchAction()
+ : new_style.GetTouchAction();
if (GetNode() && !GetNode()->IsTextNode() &&
(old_touch_action == TouchAction::kTouchActionAuto) !=
- (new_style.GetTouchAction() == TouchAction::kTouchActionAuto)) {
+ (new_touch_action == TouchAction::kTouchActionAuto)) {
EventHandlerRegistry& registry =
- GetDocument().GetPage()->GetEventHandlerRegistry();
- if (new_style.GetTouchAction() != TouchAction::kTouchActionAuto) {
+ GetDocument().GetFrame()->GetEventHandlerRegistry();
+ if (new_touch_action != TouchAction::kTouchActionAuto) {
registry.DidAddEventHandler(*GetNode(),
EventHandlerRegistry::kTouchAction);
} else {
@@ -2307,18 +2341,6 @@ void LayoutObject::SetStyleWithWritingModeOfParent(
SetStyleWithWritingModeOf(std::move(style), Parent());
}
-void LayoutObject::AddChildWithWritingModeOfParent(LayoutObject* new_child,
- LayoutObject* before_child) {
- const WritingMode old_writing_mode =
- new_child->MutableStyleRef().GetWritingMode();
- const WritingMode new_writing_mode = StyleRef().GetWritingMode();
- if (old_writing_mode != new_writing_mode && new_child->IsBoxModelObject()) {
- new_child->MutableStyleRef().SetWritingMode(new_writing_mode);
- new_child->SetHorizontalWritingMode(IsHorizontalWritingMode());
- }
- AddChild(new_child, before_child);
-}
-
void LayoutObject::UpdateFillImages(const FillLayer* old_layers,
const FillLayer& new_layers) {
// Optimize the common case
@@ -2446,8 +2468,8 @@ void LayoutObject::MapLocalToAncestor(const LayoutBoxModelObject* ancestor,
}
}
- LayoutSize container_offset = OffsetFromContainer(container);
-
+ LayoutSize container_offset =
+ OffsetFromContainer(container, mode & kIgnoreScrollOffset);
// TODO(smcgruer): This is inefficient. Instead we should avoid including
// offsetForInFlowPosition in offsetFromContainer when ignoring sticky.
if (mode & kIgnoreStickyOffset && IsStickyPositioned()) {
@@ -2695,13 +2717,34 @@ TransformationMatrix LayoutObject::LocalToAncestorTransform(
return transform_state.AccumulatedTransform();
}
-LayoutSize LayoutObject::OffsetFromContainer(const LayoutObject* o) const {
+LayoutSize LayoutObject::OffsetFromContainer(const LayoutObject* o,
+ bool ignore_scroll_offset) const {
+ return OffsetFromContainerInternal(o, ignore_scroll_offset);
+}
+
+LayoutSize LayoutObject::OffsetFromContainerInternal(
+ const LayoutObject* o,
+ bool ignore_scroll_offset) const {
DCHECK_EQ(o, Container());
return o->HasOverflowClip()
- ? LayoutSize(-ToLayoutBox(o)->ScrolledContentOffset())
+ ? OffsetFromScrollableContainer(o, ignore_scroll_offset)
: LayoutSize();
}
+LayoutSize LayoutObject::OffsetFromScrollableContainer(
+ const LayoutObject* container,
+ bool ignore_scroll_offset) const {
+ DCHECK(container->HasOverflowClip());
+ const LayoutBox* box = ToLayoutBox(container);
+ if (!ignore_scroll_offset)
+ return -LayoutSize(box->ScrolledContentOffset());
+
+ // ScrollOrigin accounts for other writing modes whose content's origin is not
+ // at the top-left.
+ return LayoutSize(ToIntSize(box->GetScrollableArea()->ScrollOrigin()) -
+ box->OriginAdjustmentForScrollbars());
+}
+
LayoutSize LayoutObject::OffsetFromAncestorContainer(
const LayoutObject* ancestor_container) const {
if (ancestor_container == this)
@@ -2792,7 +2835,7 @@ void LayoutObject::AddLayerHitTestRects(
// tracking those rects outweighs the benefit of doing compositor thread hit
// testing.
// FIXME: This limit needs to be low due to the O(n^2) algorithm in
- // WebLayer::setTouchEventHandlerRegion - crbug.com/300282.
+ // ScrollingCoordinator::SetTouchEventTargetRects() - crbug.com/300282.
const size_t kMaxRectsPerLayer = 100;
LayerHitTestRects::iterator iter = layer_rects.find(current_layer);
@@ -2981,7 +3024,7 @@ void LayoutObject::WillBeDestroyed() {
if (GetNode() && !GetNode()->IsTextNode() && style_ &&
style_->GetTouchAction() != TouchAction::kTouchActionAuto) {
EventHandlerRegistry& registry =
- GetDocument().GetPage()->GetEventHandlerRegistry();
+ GetDocument().GetFrame()->GetEventHandlerRegistry();
if (registry.EventHandlerTargets(EventHandlerRegistry::kTouchAction)
->Contains(GetNode())) {
registry.DidRemoveEventHandler(*GetNode(),
@@ -3127,8 +3170,7 @@ void LayoutObject::WillBeRemovedFromTree() {
if (Parent()->IsSVG())
Parent()->SetNeedsBoundariesUpdate();
- if (RuntimeEnabledFeatures::ScrollAnchoringEnabled() &&
- bitfields_.IsScrollAnchorObject()) {
+ if (bitfields_.IsScrollAnchorObject()) {
// Clear the bit first so that anchor.clear() doesn't recurse into
// findReferencingScrollAnchors.
bitfields_.SetIsScrollAnchorObject(false);
@@ -3392,8 +3434,6 @@ static scoped_refptr<ComputedStyle> FirstLineStyleForCachedUncachedType(
if (type == kCached) {
// A first-line style is in effect. Cache a first-line style for
// ourselves.
- layout_object_for_first_line_style->MutableStyleRef().SetHasPseudoStyle(
- kPseudoIdFirstLineInherited);
return layout_object_for_first_line_style->GetCachedPseudoStyle(
kPseudoIdFirstLineInherited, parent_style);
}
@@ -3813,7 +3853,8 @@ void LayoutObject::ClearPaintInvalidationFlags() {
#if DCHECK_IS_ON()
DCHECK(!ShouldCheckForPaintInvalidation() || PaintInvalidationStateIsDirty());
#endif
- if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
+ if (!RuntimeEnabledFeatures::SlimmingPaintV175Enabled() ||
+ !RuntimeEnabledFeatures::PartialRasterInvalidationEnabled())
fragment_.SetPartialInvalidationRect(LayoutRect());
ClearShouldDoFullPaintInvalidation();
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 d31d5a8515e..25a0dc1757e 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_object.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_object.h
@@ -27,6 +27,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_OBJECT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_OBJECT_H_
+#include "base/auto_reset.h"
#include "base/macros.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/dom/document.h"
@@ -43,18 +44,17 @@
#include "third_party/blink/renderer/core/loader/resource/image_resource_observer.h"
#include "third_party/blink/renderer/core/paint/compositing/compositing_state.h"
#include "third_party/blink/renderer/core/paint/fragment_data.h"
-#include "third_party/blink/renderer/core/paint/layer_hit_test_rects.h"
#include "third_party/blink/renderer/core/paint/paint_phase.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/style_difference.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
-#include "third_party/blink/renderer/platform/geometry/transform_state.h"
#include "third_party/blink/renderer/platform/graphics/compositing_reasons.h"
#include "third_party/blink/renderer/platform/graphics/paint/display_item_client.h"
#include "third_party/blink/renderer/platform/graphics/paint_invalidation_reason.h"
+#include "third_party/blink/renderer/platform/graphics/touch_action_rect.h"
+#include "third_party/blink/renderer/platform/transforms/transform_state.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
-#include "third_party/blink/renderer/platform/wtf/auto_reset.h"
namespace blink {
@@ -522,6 +522,9 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bool IsLayoutNGBlockFlow() const {
return IsOfType(kLayoutObjectNGBlockFlow);
}
+ bool IsLayoutNGFlexibleBox() const {
+ return IsOfType(kLayoutObjectNGFlexibleBox);
+ }
bool IsLayoutNGMixin() const { return IsOfType(kLayoutObjectNGMixin); }
bool IsLayoutNGListItem() const { return IsOfType(kLayoutObjectNGListItem); }
bool IsLayoutNGListMarker() const {
@@ -530,6 +533,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bool IsLayoutNGListMarkerImage() const {
return IsOfType(kLayoutObjectNGListMarkerImage);
}
+ bool IsLayoutNGText() const { return IsOfType(kLayoutObjectNGText); }
bool IsLayoutTableCol() const {
return IsOfType(kLayoutObjectLayoutTableCol);
}
@@ -1211,8 +1215,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
void SetStyleWithWritingModeOf(scoped_refptr<ComputedStyle>,
LayoutObject* parent);
void SetStyleWithWritingModeOfParent(scoped_refptr<ComputedStyle>);
- void AddChildWithWritingModeOfParent(LayoutObject* new_child,
- LayoutObject* before_child);
void FirstLineStyleDidChange(const ComputedStyle& old_style,
const ComputedStyle& new_style);
@@ -1331,7 +1333,8 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// Return the offset from the container() layoutObject (excluding transforms
// and multicol).
- virtual LayoutSize OffsetFromContainer(const LayoutObject*) const;
+ LayoutSize OffsetFromContainer(const LayoutObject*,
+ bool ignore_scroll_offset = false) const;
// Return the offset from an object up the container() chain. Asserts that
// none of the intermediate objects have transforms.
LayoutSize OffsetFromAncestorContainer(const LayoutObject*) const;
@@ -1394,7 +1397,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// style_ can only be nullptr before the first style is set, thus most
// callers will never see a nullptr style and should use StyleRef().
- // FIXME: It would be better if style() returned a const reference.
const ComputedStyle& StyleRef() const { return MutableStyleRef(); }
ComputedStyle& MutableStyleRef() const {
DCHECK(style_);
@@ -1467,11 +1469,11 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// and clip. This is even true if the main frame is remote.
//
// If visualRectFlags has the EdgeInclusive bit set, clipping operations will
- // use/ LayoutRect::inclusiveIntersect, and the return value of
- // inclusiveIntersect will be propagated to the return value of this method.
+ // use LayoutRect::InclusiveIntersect, and the return value of
+ // InclusiveIntersect will be propagated to the return value of this method.
// Otherwise, clipping operations will use LayoutRect::intersect, and the
// return value will be true only if the clipped rect has non-zero area.
- // See the documentation for LayoutRect::inclusiveIntersect for more
+ // See the documentation for LayoutRect::InclusiveIntersect for more
// information.
bool MapToVisualRectInAncestorSpace(
const LayoutBoxModelObject* ancestor,
@@ -1959,7 +1961,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
LayoutRect SelectionVisualRect() const {
return fragment_.SelectionVisualRect();
}
- LayoutRect PartialInvalidationRect() const {
+ LayoutRect PartialInvalidationRect() const override {
return fragment_.PartialInvalidationRect();
}
@@ -1969,6 +1971,10 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
return bitfields_.ContainsInlineWithOutlineAndContinuation();
}
+ void SetOutlineMayBeAffectedByDescendants(bool b) {
+ bitfields_.SetOutlineMayBeAffectedByDescendants(b);
+ }
+
protected:
enum LayoutObjectType {
kLayoutObjectBr,
@@ -1987,10 +1993,12 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
kLayoutObjectMedia,
kLayoutObjectMenuList,
kLayoutObjectNGBlockFlow,
+ kLayoutObjectNGFlexibleBox,
kLayoutObjectNGMixin,
kLayoutObjectNGListItem,
kLayoutObjectNGListMarker,
kLayoutObjectNGListMarkerImage,
+ kLayoutObjectNGText,
kLayoutObjectProgress,
kLayoutObjectQuote,
kLayoutObjectLayoutButton,
@@ -2058,11 +2066,15 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
virtual bool AnonymousHasStylePropagationOverride() { return false; }
// A fast path for MapToVisualRectInAncestorSpace for when GeometryMapper
- // can be used.
+ // can be used. |intersects| is set to whether the input rect intersected
+ // (see documentation of return value of MapToVisualRectInAncestorSpace).
+ //
+ // The return value of this method is whether the fast path could be used.
bool MapToVisualRectInAncestorSpaceInternalFastPath(
const LayoutBoxModelObject* ancestor,
LayoutRect&,
- VisualRectFlags) const;
+ VisualRectFlags,
+ bool& intersects) const;
// This function is called before calling the destructor so that some clean-up
// can happen regardless of whether they call a virtual function or not. As a
@@ -2142,9 +2154,6 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
bitfields_.SetContainsInlineWithOutlineAndContinuation(b);
}
- void SetOutlineMayBeAffectedByDescendants(bool b) {
- bitfields_.SetOutlineMayBeAffectedByDescendants(b);
- }
void SetPreviousOutlineMayBeAffectedByDescendants(bool b) {
bitfields_.SetPreviousOutlineMayBeAffectedByDescendants(b);
}
@@ -2154,6 +2163,12 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
virtual bool CanBeSelectionLeafInternal() const { return false; }
+ virtual LayoutSize OffsetFromContainerInternal(
+ const LayoutObject*,
+ bool ignore_scroll_offset) const;
+ LayoutSize OffsetFromScrollableContainer(const LayoutObject*,
+ bool ignore_scroll_offset) const;
+
private:
// Used only by applyFirstLineChanges to get a first line style based off of a
// given new style, without accessing the cache.
@@ -2327,7 +2342,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
needs_paint_property_update_(true),
subtree_needs_paint_property_update_(true),
descendant_needs_paint_property_update_(true),
- background_changed_since_last_paint_invalidation_(false),
+ background_changed_since_last_paint_invalidation_(true),
outline_may_be_affected_by_descendants_(false),
previous_outline_may_be_affected_by_descendants_(false),
is_truncated_(false),
@@ -2665,7 +2680,7 @@ class DeprecatedDisableModifyLayoutTreeStructureAsserts {
static bool CanModifyLayoutTreeStateInAnyState();
private:
- AutoReset<bool> disabler_;
+ base::AutoReset<bool> disabler_;
DISALLOW_COPY_AND_ASSIGN(DeprecatedDisableModifyLayoutTreeStructureAsserts);
};
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 cb9f7ffe5ac..9d85f86f006 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
@@ -28,12 +28,35 @@
#include "third_party/blink/renderer/core/dom/ax_object_cache.h"
#include "third_party/blink/renderer/core/layout/layout_counter.h"
+#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h"
#include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
namespace blink {
+namespace {
+
+// Invalidate InineItems() in LayoutNGText.
+//
+// They need to be invalidated when moving across inline formatting context
+// (i.e., to a different LayoutBlockFlow.)
+void InvalidateInlineItems(LayoutObject* object) {
+ if (object->IsLayoutNGText()) {
+ ToLayoutNGText(object)->InvalidateInlineItems();
+ } else if (object->IsLayoutInline()) {
+ // When moving without |notify_layout_object|, only top-level objects are
+ // moved. Ensure to invalidate all LayoutNGText in this inline formatting
+ // context.
+ for (LayoutObject* curr = object->SlowFirstChild(); curr;
+ curr = curr->NextSibling())
+ InvalidateInlineItems(curr);
+ }
+}
+
+} // namespace
+
void LayoutObjectChildList::DestroyLeftoverChildren() {
while (FirstChild()) {
// List markers are owned by their enclosing list and so don't get destroyed
@@ -167,9 +190,16 @@ void LayoutObjectChildList::InsertChildNode(LayoutObject* owner,
last_child_ = new_child;
}
- if (!owner->DocumentBeingDestroyed() && notify_layout_object) {
- new_child->InsertedIntoTree();
- LayoutCounter::LayoutObjectSubtreeAttached(new_child);
+ if (!owner->DocumentBeingDestroyed()) {
+ if (notify_layout_object) {
+ new_child->InsertedIntoTree();
+ LayoutCounter::LayoutObjectSubtreeAttached(new_child);
+ } else if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
+ // |notify_layout_object| is an optimization to skip notifications when
+ // moving within the same tree. Inline items need to be invalidated even
+ // when moving.
+ InvalidateInlineItems(new_child);
+ }
}
// Propagate the need to notify ancestors down into any
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 ccaefc6f812..5d240d4b73a 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
@@ -7,11 +7,15 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
+#include "third_party/blink/renderer/core/frame/event_handler_registry.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
+#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/svg/svg_g_element.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_request.h"
+#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
#include "third_party/blink/renderer/platform/json/json_values.h"
#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
@@ -487,7 +491,7 @@ TEST_F(LayoutObjectTest, VisualRect) {
MOCK_CONST_METHOD0(VisualRectRespectsVisibility, bool());
private:
- LayoutRect LocalVisualRectIgnoringVisibility() const {
+ LayoutRect LocalVisualRectIgnoringVisibility() const override {
return LayoutRect(10, 10, 20, 20);
}
const char* GetName() const final { return "MockLayoutObject"; }
@@ -724,4 +728,67 @@ TEST_F(LayoutObjectTest, DisplayContentsSVGGElementInHTML) {
ASSERT_FALSE(text->GetLayoutObject());
}
+class LayoutObjectSimTest : public SimTest {
+ public:
+ bool DocumentHasTouchActionRegion(const EventHandlerRegistry& registry) {
+ GetDocument().View()->UpdateAllLifecyclePhases();
+ return registry.HasEventHandlers(
+ EventHandlerRegistry::EventHandlerClass::kTouchAction);
+ }
+};
+
+TEST_F(LayoutObjectSimTest, TouchActionUpdatesSubframeEventHandler) {
+ SimRequest main_resource("https://example.com/test.html", "text/html");
+ SimRequest frame_resource("https://example.com/frame.html", "text/html");
+
+ LoadURL("https://example.com/test.html");
+ main_resource.Complete(
+ "<!DOCTYPE html>"
+ "<div id='container'>"
+ "<iframe src=frame.html></iframe>"
+ "</div>");
+ frame_resource.Complete(
+ "<!DOCTYPE html>"
+ "<html><body>"
+ "<div id='inner'></div>"
+ "</body></html>");
+
+ Element* iframe_element = GetDocument().QuerySelector("iframe");
+ HTMLFrameOwnerElement* frame_owner_element =
+ ToHTMLFrameOwnerElement(iframe_element);
+ Document* iframe_doc = frame_owner_element->contentDocument();
+ Element* inner = iframe_doc->getElementById("inner");
+ Element* iframe_doc_element = iframe_doc->documentElement();
+ Element* container = GetDocument().getElementById("container");
+
+ EventHandlerRegistry& registry =
+ iframe_doc->GetFrame()->GetEventHandlerRegistry();
+
+ // We should add event handler if touch action is set on subframe.
+ inner->setAttribute("style", "touch-action: none");
+ EXPECT_TRUE(DocumentHasTouchActionRegion(registry));
+
+ // We should remove event handler if touch action is removed on subframe.
+ inner->setAttribute("style", "touch-action: auto");
+ EXPECT_FALSE(DocumentHasTouchActionRegion(registry));
+
+ // We should add event handler if touch action is set on main frame.
+ container->setAttribute("style", "touch-action: none");
+ EXPECT_TRUE(DocumentHasTouchActionRegion(registry));
+
+ // We should keep event handler if touch action is set on subframe document
+ // element.
+ iframe_doc_element->setAttribute("style", "touch-action: none");
+ EXPECT_TRUE(DocumentHasTouchActionRegion(registry));
+
+ // We should keep the event handler if touch action is removed on subframe
+ // document element.
+ iframe_doc_element->setAttribute("style", "touch-action: auto");
+ EXPECT_TRUE(DocumentHasTouchActionRegion(registry));
+
+ // We should remove the handler if touch action is removed on main frame.
+ container->setAttribute("style", "touch-action: auto");
+ EXPECT_FALSE(DocumentHasTouchActionRegion(registry));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_progress.cc b/chromium/third_party/blink/renderer/core/layout/layout_progress.cc
index 8d6e0a6b8aa..d818339bc51 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_progress.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_progress.cc
@@ -36,7 +36,7 @@ LayoutProgress::LayoutProgress(HTMLProgressElement* element)
animation_duration_(0),
animating_(false),
animation_timer_(
- element->GetDocument().GetTaskRunner(TaskType::kInternalAnimation),
+ element->GetDocument().GetTaskRunner(TaskType::kInternalDefault),
this,
&LayoutProgress::AnimationTimerFired) {}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_quote.cc b/chromium/third_party/blink/renderer/core/layout/layout_quote.cc
index a84dea51d31..335af89a053 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_quote.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_quote.cc
@@ -233,7 +233,7 @@ const QuotesData* QuotesDataForLanguage(const AtomicString& lang) {
return nullptr;
// This could be just a hash table, but doing that adds 200k to LayoutQuote.o
- Language* languages_end = g_languages + WTF_ARRAY_LENGTH(g_languages);
+ Language* languages_end = g_languages + arraysize(g_languages);
CString lowercase_lang = lang.DeprecatedLower().Utf8();
Language key = {lowercase_lang.data(), 0, 0, 0, 0, nullptr};
Language* match = std::lower_bound(g_languages, languages_end, key);
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 8ffe6c326a2..0b8fb3761b8 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_replaced.cc
@@ -152,31 +152,17 @@ static inline bool LayoutObjectHasAspectRatio(
void LayoutReplaced::ComputeIntrinsicSizingInfoForReplacedContent(
IntrinsicSizingInfo& intrinsic_sizing_info) const {
- if (GetNestedIntrinsicSizingInfo(intrinsic_sizing_info)) {
- // Handle zoom & vertical writing modes here, as the embedded document
- // doesn't know about them.
- intrinsic_sizing_info.size.Scale(Style()->EffectiveZoom());
- if (IsLayoutImage() && Style()->GetObjectFit() != EObjectFit::kScaleDown)
- intrinsic_sizing_info.size.Scale(
- ToLayoutImage(this)->ImageDevicePixelRatio());
-
- // Update our intrinsic size to match what the content layoutObject has
- // computed, so that when we constrain the size below, the correct intrinsic
- // size will be obtained for comparison against min and max widths.
- if (!intrinsic_sizing_info.aspect_ratio.IsEmpty() &&
- !intrinsic_sizing_info.size.IsEmpty())
- intrinsic_size_ = LayoutSize(intrinsic_sizing_info.size);
-
- if (!IsHorizontalWritingMode())
- intrinsic_sizing_info.Transpose();
- } else {
- ComputeIntrinsicSizingInfo(intrinsic_sizing_info);
- if (!intrinsic_sizing_info.aspect_ratio.IsEmpty() &&
- !intrinsic_sizing_info.size.IsEmpty())
- intrinsic_size_ =
- LayoutSize(IsHorizontalWritingMode()
- ? intrinsic_sizing_info.size
- : intrinsic_sizing_info.size.TransposedSize());
+ ComputeIntrinsicSizingInfo(intrinsic_sizing_info);
+
+ // Update our intrinsic size to match what was computed, so that
+ // when we constrain the size, the correct intrinsic size will be
+ // obtained for comparison against min and max widths.
+ if (!intrinsic_sizing_info.aspect_ratio.IsEmpty() &&
+ !intrinsic_sizing_info.size.IsEmpty()) {
+ intrinsic_size_ =
+ LayoutSize(IsHorizontalWritingMode()
+ ? intrinsic_sizing_info.size
+ : intrinsic_sizing_info.size.TransposedSize());
}
}
@@ -961,9 +947,12 @@ PositionWithAffinity LayoutReplaced::PositionForPoint(
CaretMaxOffset()); // coordinates are below
if (GetNode()) {
- if (line_direction_position <= LogicalLeft() + (LogicalWidth() / 2))
- return CreatePositionWithAffinity(0);
- return CreatePositionWithAffinity(1);
+ const bool is_at_left_side =
+ line_direction_position <= LogicalLeft() + (LogicalWidth() / 2);
+ const bool is_at_start = is_at_left_side == IsLtr(ResolvedDirection());
+ // TODO(crbug.com/827923): Stop creating positions using int offsets on
+ // non-text nodes.
+ return CreatePositionWithAffinity(is_at_start ? 0 : 1);
}
return LayoutBox::PositionForPoint(point);
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 d81e62ac4c4..4ae22643a55 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_replaced.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_replaced.h
@@ -104,13 +104,6 @@ class CORE_EXPORT LayoutReplaced : public LayoutBox {
void ComputeIntrinsicLogicalWidths(LayoutUnit& min_logical_width,
LayoutUnit& max_logical_width) const final;
- // Extract intrinsic sizing info from a potential nested layout
- // context. Returns true if successful, and populates the IntrinsicSizingInfo
- // structure if so.
- virtual bool GetNestedIntrinsicSizingInfo(IntrinsicSizingInfo&) const {
- return false;
- }
-
// This function calculates the placement of the replaced contents. It takes
// intrinsic size of the replaced contents, stretch to fit CSS content box
// according to object-fit.
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_scrollbar.h b/chromium/third_party/blink/renderer/core/layout/layout_scrollbar.h
index bcb617306c9..8b070820d45 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_scrollbar.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_scrollbar.h
@@ -99,7 +99,7 @@ class LayoutScrollbar final : public Scrollbar {
};
DEFINE_TYPE_CASTS(LayoutScrollbar,
- ScrollbarThemeClient,
+ Scrollbar,
scrollbar,
scrollbar->IsCustomScrollbar(),
scrollbar.IsCustomScrollbar());
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_scrollbar_theme.cc b/chromium/third_party/blink/renderer/core/layout/layout_scrollbar_theme.cc
index 39a27295a70..c358de3b4a6 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_scrollbar_theme.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_scrollbar_theme.cc
@@ -39,10 +39,9 @@ LayoutScrollbarTheme* LayoutScrollbarTheme::GetLayoutScrollbarTheme() {
return &theme;
}
-void LayoutScrollbarTheme::ButtonSizesAlongTrackAxis(
- const ScrollbarThemeClient& scrollbar,
- int& before_size,
- int& after_size) {
+void LayoutScrollbarTheme::ButtonSizesAlongTrackAxis(const Scrollbar& scrollbar,
+ int& before_size,
+ int& after_size) {
IntRect first_button = BackButtonRect(scrollbar, kBackButtonStartPart);
IntRect second_button = ForwardButtonRect(scrollbar, kForwardButtonStartPart);
IntRect third_button = BackButtonRect(scrollbar, kBackButtonEndPart);
@@ -56,7 +55,7 @@ void LayoutScrollbarTheme::ButtonSizesAlongTrackAxis(
}
}
-bool LayoutScrollbarTheme::HasButtons(const ScrollbarThemeClient& scrollbar) {
+bool LayoutScrollbarTheme::HasButtons(const Scrollbar& scrollbar) {
int start_size;
int end_size;
ButtonSizesAlongTrackAxis(scrollbar, start_size, end_size);
@@ -65,31 +64,27 @@ bool LayoutScrollbarTheme::HasButtons(const ScrollbarThemeClient& scrollbar) {
: scrollbar.Height());
}
-bool LayoutScrollbarTheme::HasThumb(const ScrollbarThemeClient& scrollbar) {
+bool LayoutScrollbarTheme::HasThumb(const Scrollbar& scrollbar) {
return TrackLength(scrollbar) - ThumbLength(scrollbar) >= 0;
}
-int LayoutScrollbarTheme::MinimumThumbLength(
- const ScrollbarThemeClient& scrollbar) {
+int LayoutScrollbarTheme::MinimumThumbLength(const Scrollbar& scrollbar) {
return ToLayoutScrollbar(scrollbar).MinimumThumbLength();
}
-IntRect LayoutScrollbarTheme::BackButtonRect(
- const ScrollbarThemeClient& scrollbar,
- ScrollbarPart part_type,
- bool) {
+IntRect LayoutScrollbarTheme::BackButtonRect(const Scrollbar& scrollbar,
+ ScrollbarPart part_type,
+ bool) {
return ToLayoutScrollbar(scrollbar).ButtonRect(part_type);
}
-IntRect LayoutScrollbarTheme::ForwardButtonRect(
- const ScrollbarThemeClient& scrollbar,
- ScrollbarPart part_type,
- bool) {
+IntRect LayoutScrollbarTheme::ForwardButtonRect(const Scrollbar& scrollbar,
+ ScrollbarPart part_type,
+ bool) {
return ToLayoutScrollbar(scrollbar).ButtonRect(part_type);
}
-IntRect LayoutScrollbarTheme::TrackRect(const ScrollbarThemeClient& scrollbar,
- bool) {
+IntRect LayoutScrollbarTheme::TrackRect(const Scrollbar& scrollbar, bool) {
if (!HasButtons(scrollbar))
return scrollbar.FrameRect();
@@ -101,7 +96,7 @@ IntRect LayoutScrollbarTheme::TrackRect(const ScrollbarThemeClient& scrollbar,
}
IntRect LayoutScrollbarTheme::ConstrainTrackRectToTrackPieces(
- const ScrollbarThemeClient& scrollbar,
+ const Scrollbar& scrollbar,
const IntRect& rect) {
IntRect back_rect = ToLayoutScrollbar(scrollbar).TrackPieceRectWithMargins(
kBackTrackPart, rect);
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_scrollbar_theme.h b/chromium/third_party/blink/renderer/core/layout/layout_scrollbar_theme.h
index bc9516e8f61..053df443971 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_scrollbar_theme.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_scrollbar_theme.h
@@ -49,12 +49,12 @@ class LayoutScrollbarTheme final : public ScrollbarTheme {
const DisplayItemClient&,
const IntRect& corner_rect) override;
- bool ShouldCenterOnThumb(const ScrollbarThemeClient& scrollbar,
+ bool ShouldCenterOnThumb(const Scrollbar& scrollbar,
const WebMouseEvent& event) override {
return ScrollbarTheme::DeprecatedStaticGetTheme().ShouldCenterOnThumb(
scrollbar, event);
}
- bool ShouldSnapBackToDragOrigin(const ScrollbarThemeClient& scrollbar,
+ bool ShouldSnapBackToDragOrigin(const Scrollbar& scrollbar,
const WebMouseEvent& event) override {
return ScrollbarTheme::DeprecatedStaticGetTheme()
.ShouldSnapBackToDragOrigin(scrollbar, event);
@@ -68,35 +68,34 @@ class LayoutScrollbarTheme final : public ScrollbarTheme {
return ScrollbarTheme::DeprecatedStaticGetTheme().AutoscrollTimerDelay();
}
- void RegisterScrollbar(ScrollbarThemeClient& scrollbar) override {
+ void RegisterScrollbar(Scrollbar& scrollbar) override {
return ScrollbarTheme::DeprecatedStaticGetTheme().RegisterScrollbar(
scrollbar);
}
- void UnregisterScrollbar(ScrollbarThemeClient& scrollbar) override {
+ void UnregisterScrollbar(Scrollbar& scrollbar) override {
return ScrollbarTheme::DeprecatedStaticGetTheme().UnregisterScrollbar(
scrollbar);
}
- int MinimumThumbLength(const ScrollbarThemeClient&) override;
+ int MinimumThumbLength(const Scrollbar&) override;
- void ButtonSizesAlongTrackAxis(const ScrollbarThemeClient&,
+ void ButtonSizesAlongTrackAxis(const Scrollbar&,
int& before_size,
int& after_size);
static LayoutScrollbarTheme* GetLayoutScrollbarTheme();
protected:
- bool HasButtons(const ScrollbarThemeClient&) override;
- bool HasThumb(const ScrollbarThemeClient&) override;
+ bool HasButtons(const Scrollbar&) override;
+ bool HasThumb(const Scrollbar&) override;
- IntRect BackButtonRect(const ScrollbarThemeClient&,
+ IntRect BackButtonRect(const Scrollbar&,
ScrollbarPart,
bool painting = false) override;
- IntRect ForwardButtonRect(const ScrollbarThemeClient&,
+ IntRect ForwardButtonRect(const Scrollbar&,
ScrollbarPart,
bool painting = false) override;
- IntRect TrackRect(const ScrollbarThemeClient&,
- bool painting = false) override;
+ IntRect TrackRect(const Scrollbar&, bool painting = false) override;
void PaintScrollbarBackground(GraphicsContext&, const Scrollbar&) override;
void PaintTrackBackground(GraphicsContext&,
@@ -115,7 +114,7 @@ class LayoutScrollbarTheme final : public ScrollbarTheme {
const Scrollbar&,
const IntRect&) override;
- IntRect ConstrainTrackRectToTrackPieces(const ScrollbarThemeClient&,
+ IntRect ConstrainTrackRectToTrackPieces(const Scrollbar&,
const IntRect&) override;
};
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 3cdee4139f4..a442b80ea2f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_slider.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_slider.cc
@@ -24,7 +24,6 @@
#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/core/layout/layout_slider_thumb.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
namespace blink {
@@ -64,16 +63,6 @@ inline SliderThumbElement* LayoutSlider::GetSliderThumbElement() const {
ShadowElementNames::SliderThumb()));
}
-void LayoutSlider::UpdateLayout() {
- // FIXME: Find a way to cascade appearance.
- // http://webkit.org/b/62535
- LayoutBox* thumb_box = GetSliderThumbElement()->GetLayoutBox();
- if (thumb_box && thumb_box->IsSliderThumb())
- ToLayoutSliderThumb(thumb_box)->UpdateAppearance(StyleRef());
-
- LayoutFlexibleBox::UpdateLayout();
-}
-
bool LayoutSlider::InDragMode() const {
return GetSliderThumbElement()->IsActive();
}
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 10236f42b52..6bfcca82c9a 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_slider.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_slider.h
@@ -53,7 +53,6 @@ class LayoutSlider final : public LayoutFlexibleBox {
void ComputeIntrinsicLogicalWidths(
LayoutUnit& min_logical_width,
LayoutUnit& max_logical_width) const override;
- void UpdateLayout() override;
SliderThumbElement* GetSliderThumbElement() const;
};
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 596286b1eec..111cbabae2a 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
@@ -100,15 +100,6 @@ void LayoutSliderContainer::ComputeLogicalHeight(
void LayoutSliderContainer::UpdateLayout() {
HTMLInputElement* input = ToHTMLInputElement(GetNode()->OwnerShadowHost());
bool is_vertical = HasVerticalAppearance(input);
- MutableStyleRef().SetFlexDirection(is_vertical ? EFlexDirection::kColumn
- : EFlexDirection::kRow);
- TextDirection old_text_direction = Style()->Direction();
- if (is_vertical) {
- // FIXME: Work around rounding issues in RTL vertical sliders. We want them
- // to render identically to LTR vertical sliders. We can remove this work
- // around when subpixel rendering is enabled on all ports.
- MutableStyleRef().SetDirection(TextDirection::kLtr);
- }
Element* thumb_element = input->UserAgentShadowRoot()->getElementById(
ShadowElementNames::SliderThumb());
@@ -127,7 +118,6 @@ void LayoutSliderContainer::UpdateLayout() {
LayoutFlexibleBox::UpdateLayout();
- MutableStyleRef().SetDirection(old_text_direction);
// These should always exist, unless someone mutates the shadow DOM (e.g., in
// the inspector).
if (!thumb || !track)
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_slider_thumb.cc b/chromium/third_party/blink/renderer/core/layout/layout_slider_thumb.cc
deleted file mode 100644
index 4c7b354765a..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/layout_slider_thumb.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2010 Google 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:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
- * OWNER OR 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_slider_thumb.h"
-
-#include "third_party/blink/renderer/core/html/forms/slider_thumb_element.h"
-#include "third_party/blink/renderer/core/layout/layout_theme.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
-
-namespace blink {
-
-LayoutSliderThumb::LayoutSliderThumb(SliderThumbElement* element)
- : LayoutBlockFlow(element) {}
-
-void LayoutSliderThumb::UpdateAppearance(const ComputedStyle& parent_style) {
- if (parent_style.Appearance() == kSliderVerticalPart)
- MutableStyleRef().SetAppearance(kSliderThumbVerticalPart);
- else if (parent_style.Appearance() == kSliderHorizontalPart)
- MutableStyleRef().SetAppearance(kSliderThumbHorizontalPart);
- else if (parent_style.Appearance() == kMediaSliderPart)
- MutableStyleRef().SetAppearance(kMediaSliderThumbPart);
- else if (parent_style.Appearance() == kMediaVolumeSliderPart)
- MutableStyleRef().SetAppearance(kMediaVolumeSliderThumbPart);
- if (StyleRef().HasAppearance())
- LayoutTheme::GetTheme().AdjustSliderThumbSize(MutableStyleRef());
-}
-
-} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_slider_thumb.h b/chromium/third_party/blink/renderer/core/layout/layout_slider_thumb.h
deleted file mode 100644
index fa0dc424980..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/layout_slider_thumb.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
- * Copyright (C) 2010 Google 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:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * 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.
- * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
- * OWNER OR 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_SLIDER_THUMB_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_SLIDER_THUMB_H_
-
-#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
-
-namespace blink {
-
-class SliderThumbElement;
-
-class LayoutSliderThumb final : public LayoutBlockFlow {
- public:
- LayoutSliderThumb(SliderThumbElement*);
- void UpdateAppearance(const ComputedStyle& parent_style);
-
- private:
- bool IsOfType(LayoutObjectType type) const override {
- return type == kLayoutObjectSliderThumb || LayoutBlockFlow::IsOfType(type);
- }
-};
-
-DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutSliderThumb, IsSliderThumb());
-
-} // namespace blink
-
-#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_SLIDER_THUMB_H_
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 c1eb06c2338..1dc29c6de9f 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_state.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_state.cc
@@ -80,11 +80,6 @@ LayoutState::LayoutState(LayoutBox& layout_object,
// Now adjust the pagination offset, so that we can easily figure out how far
// away we are from the start of the pagination context.
- pagination_offset_ = next_->pagination_offset_;
- bool fixed = layout_object.IsOutOfFlowPositioned() &&
- layout_object.Style()->GetPosition() == EPosition::kFixed;
- if (fixed)
- return;
pagination_offset_ =
next_->pagination_offset_ + layout_object.LocationOffset();
if (!layout_object.IsOutOfFlowPositioned())
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 04f1858093d..0e1dfe389a5 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table.cc
@@ -324,8 +324,8 @@ void LayoutTable::UpdateLogicalWidth() {
LayoutUnit available_content_logical_width =
(container_width_in_inline_direction - margin_total)
.ClampNegativeToZero();
- if (!cb->IsLayoutNGMixin() && ShrinkToAvoidFloats() &&
- cb->IsLayoutBlockFlow() && ToLayoutBlockFlow(cb)->ContainsFloats() &&
+ if (ShrinkToAvoidFloats() && cb->IsLayoutBlockFlow() &&
+ ToLayoutBlockFlow(cb)->ContainsFloats() &&
!has_perpendicular_containing_block)
available_content_logical_width = ShrinkLogicalWidthToAvoidFloats(
margin_start, margin_end, ToLayoutBlockFlow(cb));
@@ -1518,8 +1518,10 @@ bool LayoutTable::NodeAtPoint(HitTestResult& result,
LayoutPoint adjusted_location = accumulated_offset + Location();
// Check kids first.
- if (!HasOverflowClip() ||
- location_in_container.Intersects(OverflowClipRect(adjusted_location))) {
+ bool skip_children = (result.GetHitTestRequest().GetStopNode() == this);
+ if (!skip_children &&
+ (!HasOverflowClip() ||
+ location_in_container.Intersects(OverflowClipRect(adjusted_location)))) {
for (LayoutObject* child = LastChild(); child;
child = child->PreviousSibling()) {
if (child->IsBox() && !ToLayoutBox(child)->HasSelfPaintingLayer() &&
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_table_box_component.cc b/chromium/third_party/blink/renderer/core/layout/layout_table_box_component.cc
index 5187525c94f..49e4040afb9 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_table_box_component.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_table_box_component.cc
@@ -60,7 +60,8 @@ void LayoutTableBoxComponent::MutableForPainting::UpdatePaintResult(
void LayoutTableBoxComponent::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) {
LayoutBox::StyleDidChange(diff, old_style);
- SetCanContainFixedPositionObjects(Style()->CanContainFixedPositionObjects());
+ SetCanContainFixedPositionObjects(
+ Style()->CanContainFixedPositionObjects(false));
}
} // namespace blink
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 ec25d93b264..044f88bf100 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
@@ -35,24 +35,25 @@ class LayoutTable;
//
// This class is very simple as the logic for handling the caption is done in
// LayoutTable. In particular, the placement and sizing is done in
-// LayoutTable::layoutCaption. The function is called at different timing
+// LayoutTable::LayoutCaption. The function is called at different timing
// depending on the 'caption-side' property: "top" is laid out before table row
// groups when "bottom" ones are laid out after. This ensures that "top"
// captions are visually before the row groups and "bottom" ones are after.
//
// See http://www.w3.org/TR/CSS21/tables.html#caption-position for the
// positioning.
-class LayoutTableCaption final : public LayoutBlockFlow {
+class LayoutTableCaption : public LayoutBlockFlow {
public:
explicit LayoutTableCaption(Element*);
~LayoutTableCaption() override;
LayoutUnit ContainingBlockLogicalWidthForContent() const override;
- private:
+ protected:
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectTableCaption || LayoutBlockFlow::IsOfType(type);
}
+ private:
void InsertedIntoTree() override;
void WillBeRemovedFromTree() override;
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 ff5e08d5655..6663af368fd 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
@@ -38,7 +38,7 @@
#include "third_party/blink/renderer/core/paint/table_cell_paint_invalidator.h"
#include "third_party/blink/renderer/core/paint/table_cell_painter.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
-#include "third_party/blink/renderer/platform/geometry/transform_state.h"
+#include "third_party/blink/renderer/platform/transforms/transform_state.h"
namespace blink {
@@ -189,14 +189,13 @@ 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.
- LayoutUnit content_height = HasOverrideLogicalContentHeight()
- ? OverrideLogicalContentHeight()
- : LayoutUnit(-1);
- if (content_height > -1)
- SetOverrideLogicalContentHeight(LayoutUnit());
+ LayoutUnit logical_height =
+ HasOverrideLogicalHeight() ? OverrideLogicalHeight() : LayoutUnit(-1);
+ if (logical_height > -1)
+ SetOverrideLogicalHeight(LayoutUnit());
LayoutBlockFlow::ComputePreferredLogicalWidths();
- if (content_height > -1)
- SetOverrideLogicalContentHeight(content_height);
+ if (logical_height > -1)
+ SetOverrideLogicalHeight(logical_height);
if (GetNode() && Style()->AutoWrap()) {
// See if nowrap was set.
@@ -347,18 +346,19 @@ LayoutUnit LayoutTableCell::PaddingRight() const {
: LayoutUnit(result.ToInt());
}
-void LayoutTableCell::SetOverrideLogicalContentHeightFromRowHeight(
+void LayoutTableCell::SetOverrideLogicalHeightFromRowHeight(
LayoutUnit row_height) {
ClearIntrinsicPadding();
- SetOverrideLogicalContentHeight(
- (row_height - CollapsedBorderAndCSSPaddingLogicalHeight())
- .ClampNegativeToZero());
+ SetOverrideLogicalHeight(row_height);
}
-LayoutSize LayoutTableCell::OffsetFromContainer(const LayoutObject* o) const {
+LayoutSize LayoutTableCell::OffsetFromContainerInternal(
+ const LayoutObject* o,
+ bool ignore_scroll_offset) const {
DCHECK_EQ(o, Container());
- LayoutSize offset = LayoutBlockFlow::OffsetFromContainer(o);
+ LayoutSize offset =
+ LayoutBlockFlow::OffsetFromContainerInternal(o, ignore_scroll_offset);
if (Parent())
offset -= ParentBox()->PhysicalLocationOffset();
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 99c3beac656..ef20ef0213d 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
@@ -226,7 +226,7 @@ class CORE_EXPORT LayoutTableCell : public LayoutBlockFlow {
LayoutUnit PaddingLeft() const override;
LayoutUnit PaddingRight() const override;
- void SetOverrideLogicalContentHeightFromRowHeight(LayoutUnit);
+ void SetOverrideLogicalHeightFromRowHeight(LayoutUnit);
void ScrollbarsChanged(bool horizontal_scrollbar_changed,
bool vertical_scrollbar_changed,
@@ -364,6 +364,10 @@ class CORE_EXPORT LayoutTableCell : public LayoutBlockFlow {
PaintInvalidationReason InvalidatePaint(
const PaintInvalidatorContext&) const override;
+ LayoutSize OffsetFromContainerInternal(
+ const LayoutObject*,
+ bool ignore_scroll_offset) const override;
+
protected:
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectTableCell || LayoutBlockFlow::IsOfType(type);
@@ -380,8 +384,6 @@ class CORE_EXPORT LayoutTableCell : public LayoutBlockFlow {
const LayoutPoint&) const override;
void PaintMask(const PaintInfo&, const LayoutPoint&) const override;
- LayoutSize OffsetFromContainer(const LayoutObject*) const override;
-
bool ShouldClipOverflow() const override;
using CollapsedBorderValuesMethod =
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 d06210946e5..7cd66cfba55 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
@@ -904,7 +904,7 @@ int LayoutTableSection::CalcRowLogicalHeight() {
row_span_cells.push_back(cell);
}
- if (cell->HasOverrideLogicalContentHeight()) {
+ if (cell->HasOverrideLogicalHeight()) {
cell->ClearIntrinsicPadding();
cell->ClearOverrideSize();
cell->ForceChildLayout();
@@ -1926,7 +1926,7 @@ void LayoutTableSection::RelayoutCellIfFlexed(LayoutTableCell& cell,
// Alignment within a cell is based off the calculated height, which becomes
// irrelevant once the cell has been resized based off its percentage.
- cell.SetOverrideLogicalContentHeightFromRowHeight(LayoutUnit(row_height));
+ cell.SetOverrideLogicalHeightFromRowHeight(LayoutUnit(row_height));
cell.ForceChildLayout();
// If the baseline moved, we may have to update the data for our row. Find
@@ -2046,10 +2046,6 @@ bool LayoutTableSection::GroupShouldRepeat() const {
if (GetPaginationBreakability() == kAllowAnyBreaks)
return false;
- // TODO(rhogan): Sections can be self-painting.
- if (HasSelfPaintingLayer())
- return false;
-
// If we don't know the page height yet, just assume we fit.
if (!IsPageLogicalHeightKnown())
return true;
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 a27c592b2d4..f5f6ed18829 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text.cc
@@ -32,6 +32,8 @@
#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"
+#include "third_party/blink/renderer/core/editing/inline_box_position.h"
+#include "third_party/blink/renderer/core/editing/inline_box_traversal.h"
#include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
@@ -53,11 +55,13 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.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/platform/fonts/character_range.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
-#include "third_party/blink/renderer/platform/scheduler/child/web_scheduler.h"
+#include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
#include "third_party/blink/renderer/platform/text/bidi_resolver.h"
#include "third_party/blink/renderer/platform/text/character.h"
#include "third_party/blink/renderer/platform/text/hyphenation.h"
@@ -69,7 +73,7 @@
namespace blink {
struct SameSizeAsLayoutText : public LayoutObject {
- uint32_t bitfields : 11;
+ uint32_t bitfields : 12;
float widths[4];
String text;
void* pointers[2];
@@ -111,55 +115,11 @@ class SecureTextTimer final : public TimerBase {
int last_typed_character_offset_;
};
-static void MakeCapitalized(String* string, UChar previous) {
- if (string->IsNull())
- return;
-
- unsigned length = string->length();
- const StringImpl& input = *string->Impl();
-
- CHECK_LT(length, std::numeric_limits<unsigned>::max());
- StringBuffer<UChar> string_with_previous(length + 1);
- string_with_previous[0] =
- previous == kNoBreakSpaceCharacter ? kSpaceCharacter : previous;
- for (unsigned i = 1; i < length + 1; i++) {
- // Replace &nbsp with a real space since ICU no longer treats &nbsp as a
- // word separator.
- if (input[i - 1] == kNoBreakSpaceCharacter)
- string_with_previous[i] = kSpaceCharacter;
- else
- string_with_previous[i] = input[i - 1];
- }
-
- TextBreakIterator* boundary =
- WordBreakIterator(string_with_previous.Characters(), length + 1);
- if (!boundary)
- return;
-
- StringBuilder result;
- result.ReserveCapacity(length);
-
- int32_t end_of_word;
- int32_t start_of_word = boundary->first();
- for (end_of_word = boundary->next(); end_of_word != kTextBreakDone;
- start_of_word = end_of_word, end_of_word = boundary->next()) {
- if (start_of_word) { // Ignore first char of previous string
- result.Append(
- input[start_of_word - 1] == kNoBreakSpaceCharacter
- ? kNoBreakSpaceCharacter
- : WTF::Unicode::ToTitleCase(string_with_previous[start_of_word]));
- }
- for (int i = start_of_word + 1; i < end_of_word; i++)
- result.Append(input[i - 1]);
- }
-
- *string = result.ToString();
-}
-
LayoutText::LayoutText(Node* node, scoped_refptr<StringImpl> str)
: LayoutObject(node),
has_tab_(false),
lines_dirty_(false),
+ valid_ng_items_(false),
contains_reversed_text_(false),
known_to_have_no_overflow_and_no_fallback_fonts_(false),
contains_only_whitespace_or_nbsp_(
@@ -219,6 +179,10 @@ void LayoutText::StyleDidChange(StyleDifference diff,
TextAutosizer* text_autosizer = GetDocument().GetTextAutosizer();
if (!old_style && text_autosizer)
text_autosizer->Record(this);
+
+ // TODO(layout-dev): This is only really needed for style changes that affect
+ // how text is rendered. Font, text-decoration, etc.
+ valid_ng_items_ = false;
}
void LayoutText::RemoveAndDestroyTextBoxes() {
@@ -245,6 +209,7 @@ void LayoutText::WillBeDestroyed() {
RemoveAndDestroyTextBoxes();
LayoutObject::WillBeDestroyed();
+ valid_ng_items_ = false;
}
void LayoutText::ExtractTextBox(InlineTextBox* box) {
@@ -263,7 +228,7 @@ void LayoutText::DeleteTextBoxes() {
text_boxes_.DeleteLineBoxes();
}
-Optional<FloatPoint> LayoutText::GetUpperLeftCorner() const {
+base::Optional<FloatPoint> LayoutText::GetUpperLeftCorner() const {
DCHECK(!IsBR());
if (HasLegacyTextBoxes()) {
if (StyleRef().IsHorizontalWritingMode()) {
@@ -284,7 +249,7 @@ Optional<FloatPoint> LayoutText::GetUpperLeftCorner() const {
return FloatPoint(line_box->InlineOffsetToContainerBox().left.ToFloat(),
LinesBoundingBox().Y());
}
- return WTF::nullopt;
+ return base::nullopt;
}
bool LayoutText::HasTextBoxes() const {
@@ -580,13 +545,15 @@ FloatRect LayoutText::LocalBoundingBoxRectForAccessibility() const {
return result;
}
+namespace {
+
enum ShouldAffinityBeDownstream {
kAlwaysDownstream,
kAlwaysUpstream,
kUpstreamIfPositionIsNotAtStart
};
-static bool LineDirectionPointFitsInBox(
+bool LineDirectionPointFitsInBox(
int point_line_direction,
InlineTextBox* box,
ShouldAffinityBeDownstream& should_affinity_be_downstream) {
@@ -626,7 +593,7 @@ static bool LineDirectionPointFitsInBox(
return false;
}
-static PositionWithAffinity CreatePositionWithAffinityForBox(
+PositionWithAffinity CreatePositionWithAffinityForBox(
const InlineBox* box,
int offset,
ShouldAffinityBeDownstream should_affinity_be_downstream) {
@@ -652,7 +619,7 @@ static PositionWithAffinity CreatePositionWithAffinityForBox(
offset + text_start_offset, affinity);
}
-static PositionWithAffinity
+PositionWithAffinity
CreatePositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(
const InlineTextBox* box,
int offset,
@@ -660,94 +627,24 @@ CreatePositionWithAffinityForBoxAfterAdjustingOffsetForBiDi(
DCHECK(box);
DCHECK_GE(offset, 0);
+ // TODO(layout-dev): Stop passing out-of-range |offset|.
+ if (static_cast<unsigned>(offset) > box->Len())
+ offset = box->Len();
+
if (offset && static_cast<unsigned>(offset) < box->Len()) {
return CreatePositionWithAffinityForBox(box, box->Start() + offset,
should_affinity_be_downstream);
}
- bool position_is_at_start_of_box = !offset;
- if (position_is_at_start_of_box == box->IsLeftToRightDirection()) {
- // offset is on the left edge
-
- const InlineBox* prev_box = box->PrevLeafChildIgnoringLineBreak();
- if ((prev_box && prev_box->BidiLevel() == box->BidiLevel()) ||
- box->GetLineLayoutItem().ContainingBlock().Style()->Direction() ==
- box->Direction()) { // FIXME: left on 12CBA
- return CreatePositionWithAffinityForBox(box, box->CaretLeftmostOffset(),
- should_affinity_be_downstream);
- }
-
- if (prev_box && prev_box->BidiLevel() > box->BidiLevel()) {
- // e.g. left of B in aDC12BAb
- const InlineBox* leftmost_box;
- do {
- leftmost_box = prev_box;
- prev_box = leftmost_box->PrevLeafChildIgnoringLineBreak();
- } while (prev_box && prev_box->BidiLevel() > box->BidiLevel());
- return CreatePositionWithAffinityForBox(
- leftmost_box, leftmost_box->CaretRightmostOffset(),
- should_affinity_be_downstream);
- }
-
- if (!prev_box || prev_box->BidiLevel() < box->BidiLevel()) {
- // e.g. left of D in aDC12BAb
- const InlineBox* rightmost_box;
- const InlineBox* next_box = box;
- do {
- rightmost_box = next_box;
- next_box = rightmost_box->NextLeafChildIgnoringLineBreak();
- } while (next_box && next_box->BidiLevel() >= box->BidiLevel());
- return CreatePositionWithAffinityForBox(
- rightmost_box,
- box->IsLeftToRightDirection() ? rightmost_box->CaretMaxOffset()
- : rightmost_box->CaretMinOffset(),
- should_affinity_be_downstream);
- }
-
- return CreatePositionWithAffinityForBox(box, box->CaretRightmostOffset(),
- should_affinity_be_downstream);
- }
-
- const InlineBox* next_box = box->NextLeafChildIgnoringLineBreak();
- if ((next_box && next_box->BidiLevel() == box->BidiLevel()) ||
- box->GetLineLayoutItem().ContainingBlock().Style()->Direction() ==
- box->Direction()) {
- return CreatePositionWithAffinityForBox(box, box->CaretRightmostOffset(),
- should_affinity_be_downstream);
- }
-
- // offset is on the right edge
- if (next_box && next_box->BidiLevel() > box->BidiLevel()) {
- // e.g. right of C in aDC12BAb
- const InlineBox* rightmost_box;
- do {
- rightmost_box = next_box;
- next_box = rightmost_box->NextLeafChildIgnoringLineBreak();
- } while (next_box && next_box->BidiLevel() > box->BidiLevel());
- return CreatePositionWithAffinityForBox(
- rightmost_box, rightmost_box->CaretLeftmostOffset(),
- should_affinity_be_downstream);
- }
-
- if (!next_box || next_box->BidiLevel() < box->BidiLevel()) {
- // e.g. right of A in aDC12BAb
- const InlineBox* leftmost_box;
- const InlineBox* prev_box = box;
- do {
- leftmost_box = prev_box;
- prev_box = leftmost_box->PrevLeafChildIgnoringLineBreak();
- } while (prev_box && prev_box->BidiLevel() >= box->BidiLevel());
- return CreatePositionWithAffinityForBox(
- leftmost_box,
- box->IsLeftToRightDirection() ? leftmost_box->CaretMinOffset()
- : leftmost_box->CaretMaxOffset(),
- should_affinity_be_downstream);
- }
-
- return CreatePositionWithAffinityForBox(box, box->CaretLeftmostOffset(),
+ const InlineBoxPosition adjusted = BidiAdjustment::AdjustForHitTest(
+ InlineBoxPosition(box, box->Start() + offset));
+ return CreatePositionWithAffinityForBox(adjusted.inline_box,
+ adjusted.offset_in_box,
should_affinity_be_downstream);
}
+} // namespace
+
PositionWithAffinity LayoutText::PositionForPoint(
const LayoutPoint& point) const {
if (const LayoutBlockFlow* ng_block_flow = EnclosingNGBlockFlow())
@@ -1646,6 +1543,12 @@ void LayoutText::SetTextWithOffset(scoped_refptr<StringImpl> text,
lines_dirty_ = dirtied_lines;
SetText(std::move(text), force || dirtied_lines);
+
+ // TODO(layout-dev): Invalidation is currently all or nothing in LayoutNG,
+ // this is probably fine for NGInlineItem reuse as recreating the individual
+ // items is relatively cheap. If partial relayout performance improvement are
+ // needed partial re-shapes are likely to be sufficient. Revisit as needed.
+ valid_ng_items_ = false;
}
void LayoutText::TransformText() {
@@ -1693,37 +1596,16 @@ void LayoutText::AddLayerHitTestRects(
// Text nodes aren't event targets, so don't descend any further.
}
-void ApplyTextTransform(const ComputedStyle* style,
- String& text,
- UChar previous_character) {
- if (!style)
- return;
-
- switch (style->TextTransform()) {
- case ETextTransform::kNone:
- break;
- case ETextTransform::kCapitalize:
- MakeCapitalized(&text, previous_character);
- break;
- case ETextTransform::kUppercase:
- text = text.UpperUnicode(style->Locale());
- break;
- case ETextTransform::kLowercase:
- text = text.LowerUnicode(style->Locale());
- break;
- }
-}
-
void LayoutText::SetTextInternal(scoped_refptr<StringImpl> text) {
DCHECK(text);
text_ = String(std::move(text));
- if (Style()) {
- ApplyTextTransform(Style(), text_, PreviousCharacter());
+ if (const ComputedStyle* style = Style()) {
+ style->ApplyTextTransform(&text_, PreviousCharacter());
// We use the same characters here as for list markers.
// See the listMarkerText function in LayoutListMarker.cpp.
- switch (Style()->TextSecurity()) {
+ switch (style->TextSecurity()) {
case ETextSecurity::kNone:
break;
case ETextSecurity::kCircle:
@@ -1789,6 +1671,8 @@ void LayoutText::SetText(scoped_refptr<StringImpl> text, bool force) {
TextAutosizer* text_autosizer = GetDocument().GetTextAutosizer();
if (text_autosizer)
text_autosizer->Record(this);
+
+ valid_ng_items_ = false;
}
void LayoutText::DirtyOrDeleteLineBoxesIfNeeded(bool full_layout) {
@@ -1797,12 +1681,14 @@ void LayoutText::DirtyOrDeleteLineBoxesIfNeeded(bool full_layout) {
else if (!lines_dirty_)
DirtyLineBoxes();
lines_dirty_ = false;
+ valid_ng_items_ = false;
}
void LayoutText::DirtyLineBoxes() {
for (InlineTextBox* box : TextBoxes())
box->DirtyLineBoxes();
lines_dirty_ = false;
+ valid_ng_items_ = false;
}
InlineTextBox* LayoutText::CreateTextBox(int start, unsigned short length) {
@@ -2006,6 +1892,23 @@ LayoutRect LayoutText::LocalSelectionRect() const {
if (!cb)
return LayoutRect();
+ const FrameSelection& frame_selection = GetFrame()->Selection();
+ const auto fragments = NGPaintFragment::InlineFragmentsFor(this);
+ if (fragments.IsInLayoutNGInlineFormattingContext()) {
+ LayoutRect rect;
+ for (const NGPaintFragment* fragment : fragments) {
+ const LayoutSelectionStatus status =
+ frame_selection.ComputeLayoutSelectionStatus(*fragment);
+ if (status.start == status.end)
+ continue;
+ NGPhysicalOffsetRect fragment_rect =
+ fragment->ComputeLocalSelectionRect(status);
+ fragment_rect.offset += fragment->InlineOffsetToContainerBox();
+ rect.Unite(fragment_rect.ToLayoutRect());
+ }
+ return rect;
+ }
+
// Now calculate startPos and endPos for painting selection.
// We include a selection while endPos > 0
unsigned start_pos, end_pos;
@@ -2014,7 +1917,6 @@ LayoutRect LayoutText::LocalSelectionRect() const {
start_pos = 0;
end_pos = TextLength();
} else {
- const FrameSelection& frame_selection = GetFrame()->Selection();
if (GetSelectionState() == SelectionState::kStart) {
// TODO(yoichio): value_or is used to prevent use uininitialized value
// on release. It should be value() after LayoutSelection brushup.
@@ -2030,12 +1932,8 @@ LayoutRect LayoutText::LocalSelectionRect() const {
}
}
- // TODO(yoichio): The following DCHECK should pass, but fails 14 tests.
- // DCHECK_LE(start_pos, end_pos);
+ DCHECK_LE(start_pos, end_pos);
LayoutRect rect;
- if (start_pos >= end_pos)
- return rect;
-
for (InlineTextBox* box : TextBoxes()) {
rect.Unite(box->LocalSelectionRect(start_pos, end_pos));
rect.Unite(LayoutRect(EllipsisRectForBox(box, start_pos, end_pos)));
@@ -2053,52 +1951,39 @@ const NGOffsetMapping* LayoutText::GetNGOffsetMapping() const {
Position LayoutText::PositionForCaretOffset(unsigned offset) const {
// ::first-letter handling should be done by LayoutTextFragment override.
DCHECK(!IsTextFragment());
+ // BR handling should be done by LayoutBR override.
+ DCHECK(!IsBR());
// WBR handling should be done by LayoutWordBreak override.
DCHECK(!IsWordBreak());
DCHECK_LE(offset, TextLength());
const Node* node = GetNode();
if (!node)
return Position();
- if (node->IsTextNode()) {
- // TODO(layout-dev): Support offset change due to text-transform.
- return Position(node, offset);
- }
- // TODO(xiaochengh): This should be done in LayoutBR override.
- if (IsBR()) {
- DCHECK(IsHTMLBRElement(node));
- DCHECK_LE(offset, 1u);
- return offset ? Position::AfterNode(*node) : Position::BeforeNode(*node);
- }
- NOTREACHED();
- return Position();
+ DCHECK(node->IsTextNode());
+ // TODO(layout-dev): Support offset change due to text-transform.
+ return Position(node, offset);
}
-Optional<unsigned> LayoutText::CaretOffsetForPosition(
+base::Optional<unsigned> LayoutText::CaretOffsetForPosition(
const Position& position) const {
// ::first-letter handling should be done by LayoutTextFragment override.
DCHECK(!IsTextFragment());
+ // BR handling should be done by LayoutBR override.
+ DCHECK(!IsBR());
// WBR handling should be done by LayoutWordBreak override.
DCHECK(!IsWordBreak());
if (position.IsNull() || position.AnchorNode() != GetNode())
- return WTF::nullopt;
- if (GetNode()->IsTextNode()) {
- if (position.IsBeforeAnchor())
- return 0;
- // TODO(layout-dev): Support offset change due to text-transform.
- if (position.IsAfterAnchor())
- return TextLength();
- DCHECK(position.IsOffsetInAnchor()) << position;
- DCHECK_LE(position.OffsetInContainerNode(), static_cast<int>(TextLength()))
- << position;
- return position.OffsetInContainerNode();
- }
- // TODO(xiaochengh): This should be done by LayoutBR override.
- if (IsBR()) {
- DCHECK(position.IsBeforeAnchor() || position.IsAfterAnchor()) << position;
- return position.IsBeforeAnchor() ? 0 : 1;
- }
- NOTREACHED();
- return WTF::nullopt;
+ return base::nullopt;
+ DCHECK(GetNode()->IsTextNode());
+ if (position.IsBeforeAnchor())
+ return 0;
+ // TODO(layout-dev): Support offset change due to text-transform.
+ if (position.IsAfterAnchor())
+ return TextLength();
+ DCHECK(position.IsOffsetInAnchor()) << position;
+ DCHECK_LE(position.OffsetInContainerNode(), static_cast<int>(TextLength()))
+ << position;
+ return position.OffsetInContainerNode();
}
int LayoutText::CaretMinOffset() const {
@@ -2108,7 +1993,7 @@ int LayoutText::CaretMinOffset() const {
const Position first_position = PositionForCaretOffset(0);
if (first_position.IsNull())
return 0;
- Optional<unsigned> candidate = CaretOffsetForPosition(
+ base::Optional<unsigned> candidate = CaretOffsetForPosition(
mapping->StartOfNextNonCollapsedContent(first_position));
// Align with the legacy behavior that 0 is returned if the entire node
// contains only collapsed whitespaces.
@@ -2132,7 +2017,7 @@ int LayoutText::CaretMaxOffset() const {
const Position last_position = PositionForCaretOffset(TextLength());
if (last_position.IsNull())
return TextLength();
- Optional<unsigned> candidate = CaretOffsetForPosition(
+ base::Optional<unsigned> candidate = CaretOffsetForPosition(
mapping->EndOfLastNonCollapsedContent(last_position));
// Align with the legacy behavior that |TextLenght()| is returned if the
// entire node contains only collapsed whitespaces.
@@ -2159,8 +2044,9 @@ unsigned LayoutText::ResolvedTextLength() const {
return 0;
}
DCHECK(end_position.IsNotNull()) << start_position;
- Optional<unsigned> start = mapping->GetTextContentOffset(start_position);
- Optional<unsigned> end = mapping->GetTextContentOffset(end_position);
+ base::Optional<unsigned> start =
+ mapping->GetTextContentOffset(start_position);
+ base::Optional<unsigned> end = mapping->GetTextContentOffset(end_position);
if (!start.has_value() || !end.has_value()) {
DCHECK(!start.has_value()) << this;
DCHECK(!end.has_value()) << this;
@@ -2334,9 +2220,6 @@ scoped_refptr<AbstractInlineTextBox> LayoutText::FirstAbstractInlineTextBox() {
void LayoutText::InvalidateDisplayItemClients(
PaintInvalidationReason invalidation_reason) const {
- // TODO(yoichio): Cover other PaintInvalidateionReasons.
- DCHECK(invalidation_reason != PaintInvalidationReason::kSelection ||
- !EnclosingNGBlockFlow());
ObjectPaintInvalidator paint_invalidator(*this);
if (RuntimeEnabledFeatures::LayoutNGEnabled()) {
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 b90bafab86e..6fac55a2ad1 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text.h
@@ -59,10 +59,9 @@ enum class OnlyWhitespaceOrNbsp : unsigned { kUnknown = 0, kNo = 1, kYes = 2 };
//
//
// ***** LINE BOXES OWNERSHIP *****
-// InlineTextBox in text_boxes_ are not owned by LayoutText
-// but are pointers into the enclosing inline / block (see LayoutInline's
-// and LayoutBlockFlow's m_lineBoxes).
-//
+// InlineTextBox in text_boxes_ are not owned by LayoutText but are pointers
+// into the enclosing inline / block (see LayoutInline's and LayoutBlockFlow's
+// line_boxes_).
//
// This class implements the preferred logical widths computation
// for its underlying text. The widths are stored into m_minWidth
@@ -207,7 +206,7 @@ class CORE_EXPORT LayoutText : public LayoutObject {
// Returns upper left corner point in local physical coordinates with flipped
// block-flow direction if this object has rendered text.
- Optional<FloatPoint> GetUpperLeftCorner() const;
+ base::Optional<FloatPoint> GetUpperLeftCorner() const;
// True if we have inline text box children which implies rendered text (or
// whitespace) output.
@@ -225,7 +224,8 @@ class CORE_EXPORT LayoutText : public LayoutObject {
// Returns the offset in the |text_| string that corresponds to the given
// position in DOM; Returns nullopt is the position is not in this LayoutText.
// TODO(layout-dev): Fix it when text-transform changes text length.
- virtual Optional<unsigned> CaretOffsetForPosition(const Position&) const;
+ virtual base::Optional<unsigned> CaretOffsetForPosition(
+ const Position&) const;
// Returns true if the offset (0-based in the |text_| string) is next to a
// non-collapsed non-linebreak character, or before a forced linebreak (<br>,
@@ -354,7 +354,7 @@ class CORE_EXPORT LayoutText : public LayoutObject {
LayoutRect LocalVisualRectIgnoringVisibility() const final;
// We put the bitfield first to minimize padding on 64-bit.
-
+ protected:
// Whether or not we can be broken into multiple lines.
unsigned has_breakable_char_ : 1;
// Whether or not we have a hard break (e.g., <pre> with '\n').
@@ -370,10 +370,18 @@ class CORE_EXPORT LayoutText : public LayoutObject {
// dirtying everything when character data is modified (e.g., appended/
// inserted or removed).
unsigned lines_dirty_ : 1;
+
+ // Used by LayoutNGText. Whether the NGInlineItems associated with this
+ // object are valid. Set after layout and cleared whenever the LayoutText is
+ // modified.
+ // Functionally the inverse equivalent of lines_dirty_ for LayoutNG.
+ unsigned valid_ng_items_ : 1;
+
unsigned contains_reversed_text_ : 1;
mutable unsigned known_to_have_no_overflow_and_no_fallback_fonts_ : 1;
unsigned contains_only_whitespace_or_nbsp_ : 2;
+ private:
float min_width_;
float max_width_;
float first_line_min_width_;
@@ -421,8 +429,6 @@ inline LayoutText* Text::GetLayoutObject() const {
return ToLayoutText(CharacterData::GetLayoutObject());
}
-void ApplyTextTransform(const ComputedStyle*, String&, UChar);
-
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_TEXT_H_
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 9fced5e8f96..dde546fa0ee 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
@@ -31,21 +31,44 @@ LayoutTextCombine::LayoutTextCombine(Node* node,
: LayoutText(node, std::move(string)),
combined_text_width_(0),
scale_x_(1.0f),
- is_combined_(false),
- needs_font_update_(false) {}
+ is_combined_(false) {}
void LayoutTextCombine::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) {
- SetStyleInternal(ComputedStyle::Clone(StyleRef()));
LayoutText::StyleDidChange(diff, old_style);
-
UpdateIsCombined();
+ if (!IsCombined())
+ return;
+
+ // We need to call LayoutText::StyleDidChange before updating combined text
+ // font because StyleDidChange may change the text through text-transform.
+ UpdateFontStyleForCombinedText();
}
void LayoutTextCombine::SetTextInternal(scoped_refptr<StringImpl> text) {
LayoutText::SetTextInternal(std::move(text));
+ bool was_combined = IsCombined();
UpdateIsCombined();
+
+ // SetTextInternal may be called on construction for applying text-transform
+ // in which case Parent() is nullptr. However, was_combined should be false
+ // since it initially is.
+ DCHECK(!was_combined || Parent());
+
+ if (was_combined) {
+ // Re-set the ComputedStyle from the parent to base the measurements in
+ // UpdateFontStyleForCombinedText on the original font and not what was
+ // previously set for combined text. If IsCombined() is now false, we are
+ // simply resetting the style to the parent style.
+ SetStyle(Parent()->MutableStyle());
+ } else if (IsCombined()) {
+ // If the text was previously not combined, SetStyle would have been a no-op
+ // since the before and after style would be the same ComputedStyle
+ // instance and StyleDidChange would not be called. Instead, call
+ // UpdateFontStyleForCombinedText directly.
+ UpdateFontStyleForCombinedText();
+ }
}
float LayoutTextCombine::Width(unsigned from,
@@ -82,7 +105,6 @@ void ScaleHorizontallyAndTranslate(GraphicsContext& context,
void LayoutTextCombine::TransformToInlineCoordinates(GraphicsContext& context,
const LayoutRect& box_rect,
bool clip) const {
- DCHECK_EQ(needs_font_update_, false);
DCHECK(is_combined_);
// No transform needed if we don't have a font.
@@ -130,37 +152,31 @@ void LayoutTextCombine::UpdateIsCombined() {
is_combined_ = !Style()->IsHorizontalWritingMode()
// Nothing to combine.
&& !HasEmptyText();
-
- if (is_combined_)
- needs_font_update_ = true;
}
-void LayoutTextCombine::UpdateFont() {
- if (!needs_font_update_)
- return;
-
- needs_font_update_ = false;
+void LayoutTextCombine::UpdateFontStyleForCombinedText() {
+ DCHECK(is_combined_);
- if (!is_combined_)
- return;
+ scoped_refptr<ComputedStyle> style = ComputedStyle::Clone(StyleRef());
+ SetStyleInternal(style);
unsigned offset = 0;
- TextRun run = ConstructTextRun(OriginalFont(), this, offset, TextLength(),
- StyleRef(), Style()->Direction());
- FontDescription description = OriginalFont().GetFontDescription();
+ TextRun run = ConstructTextRun(style->GetFont(), this, offset, TextLength(),
+ *style, style->Direction());
+ FontDescription description = style->GetFont().GetFontDescription();
float em_width = description.ComputedSize();
- if (!EnumHasFlags(Style()->TextDecorationsInEffect(),
+ if (!EnumHasFlags(style->TextDecorationsInEffect(),
TextDecoration::kUnderline | TextDecoration::kOverline))
em_width *= kTextCombineMargin;
// We are going to draw combined text horizontally.
description.SetOrientation(FontOrientation::kHorizontal);
- combined_text_width_ = OriginalFont().Width(run);
+ combined_text_width_ = style->GetFont().Width(run);
- FontSelector* font_selector = Style()->GetFont().GetFontSelector();
+ FontSelector* font_selector = style->GetFont().GetFontSelector();
- bool should_update_font = MutableStyleRef().SetFontDescription(
- description); // Need to change font orientation to horizontal.
+ // Need to change font orientation to horizontal.
+ bool should_update_font = style->SetFontDescription(description);
if (combined_text_width_ <= em_width) {
scale_x_ = 1.0f;
@@ -168,7 +184,7 @@ void LayoutTextCombine::UpdateFont() {
// Need to try compressed glyphs.
static const FontWidthVariant kWidthVariants[] = {kHalfWidth, kThirdWidth,
kQuarterWidth};
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(kWidthVariants); ++i) {
+ for (size_t i = 0; i < arraysize(kWidthVariants); ++i) {
description.SetWidthVariant(kWidthVariants[i]);
Font compressed_font = Font(description);
compressed_font.Update(font_selector);
@@ -177,7 +193,7 @@ void LayoutTextCombine::UpdateFont() {
combined_text_width_ = run_width;
// Replace my font with the new one.
- should_update_font = MutableStyleRef().SetFontDescription(description);
+ should_update_font = style->SetFontDescription(description);
break;
}
}
@@ -194,7 +210,7 @@ void LayoutTextCombine::UpdateFont() {
}
if (should_update_font)
- Style()->GetFont().Update(font_selector);
+ style->GetFont().Update(font_selector);
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_combine.h b/chromium/third_party/blink/renderer/core/layout/layout_text_combine.h
index 02649ce5d6e..2afca4e195c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_combine.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_combine.h
@@ -33,7 +33,6 @@ class LayoutTextCombine final : public LayoutText {
public:
LayoutTextCombine(Node*, scoped_refptr<StringImpl>);
- void UpdateFont();
bool IsCombined() const { return is_combined_; }
float CombinedTextWidth(const Font& font) const {
return font.GetFontDescription().ComputedSize();
@@ -59,17 +58,16 @@ class LayoutTextCombine final : public LayoutText {
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
void SetTextInternal(scoped_refptr<StringImpl>) override;
void UpdateIsCombined();
+ void UpdateFontStyleForCombinedText();
float combined_text_width_;
float scale_x_;
bool is_combined_ : 1;
- bool needs_font_update_ : 1;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutTextCombine, IsCombineText());
inline LayoutUnit LayoutTextCombine::InlineWidthForLayout() const {
- DCHECK(!needs_font_update_);
return LayoutUnit::FromFloatCeil(combined_text_width_);
}
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 e975a51f045..986814a2177 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
@@ -41,24 +41,19 @@ TextControlElement* LayoutTextControl::GetTextControlElement() const {
return ToTextControl(GetNode());
}
-HTMLElement* LayoutTextControl::InnerEditorElement() const {
+TextControlInnerEditorElement* LayoutTextControl::InnerEditorElement() const {
return GetTextControlElement()->InnerEditorElement();
}
void LayoutTextControl::StyleDidChange(StyleDifference diff,
const ComputedStyle* old_style) {
LayoutBlockFlow::StyleDidChange(diff, old_style);
- Element* inner_editor = InnerEditorElement();
+ TextControlInnerEditorElement* inner_editor = InnerEditorElement();
if (!inner_editor)
return;
LayoutBlock* inner_editor_layout_object =
ToLayoutBlock(inner_editor->GetLayoutObject());
if (inner_editor_layout_object) {
- // We may have set the width and the height in the old style in layout().
- // Reset them now to avoid getting a spurious layout hint.
- inner_editor_layout_object->MutableStyleRef().SetHeight(Length());
- inner_editor_layout_object->MutableStyleRef().SetWidth(Length());
- inner_editor_layout_object->SetStyle(CreateInnerEditorStyle(StyleRef()));
inner_editor->SetNeedsStyleRecalc(
kSubtreeStyleChange,
StyleChangeReasonForTracing::Create(StyleChangeReason::kControl));
@@ -75,25 +70,6 @@ void LayoutTextControl::StyleDidChange(StyleDifference diff,
GetTextControlElement()->UpdatePlaceholderVisibility();
}
-static inline void UpdateUserModifyProperty(TextControlElement& node,
- ComputedStyle& style) {
- style.SetUserModify(node.IsDisabledOrReadOnly()
- ? EUserModify::kReadOnly
- : EUserModify::kReadWritePlaintextOnly);
-}
-
-void LayoutTextControl::AdjustInnerEditorStyle(
- ComputedStyle& text_block_style) const {
- // The inner block, if present, always has its direction set to LTR,
- // so we need to inherit the direction and unicode-bidi style from the
- // element.
- text_block_style.SetDirection(Style()->Direction());
- text_block_style.SetUnicodeBidi(Style()->GetUnicodeBidi());
- text_block_style.SetUserSelect(EUserSelect::kText);
-
- UpdateUserModifyProperty(*GetTextControlElement(), text_block_style);
-}
-
int LayoutTextControl::TextBlockLogicalHeight() const {
return (LogicalHeight() - BorderAndPaddingLogicalHeight()).ToInt();
}
@@ -110,14 +86,6 @@ int LayoutTextControl::TextBlockLogicalWidth() const {
return unit_width.ToInt();
}
-void LayoutTextControl::UpdateFromElement() {
- Element* inner_editor = InnerEditorElement();
- if (inner_editor && inner_editor->GetLayoutObject())
- UpdateUserModifyProperty(
- *GetTextControlElement(),
- inner_editor->GetLayoutObject()->MutableStyleRef());
-}
-
int LayoutTextControl::ScrollbarThickness() const {
// FIXME: We should get the size of the scrollbar from the LayoutTheme
// instead.
@@ -237,8 +205,7 @@ bool LayoutTextControl::HasValidAvgCharWidth(const SimpleFontData* font_data,
if (!font_families_with_invalid_char_width_map) {
font_families_with_invalid_char_width_map = new HashSet<AtomicString>;
- for (size_t i = 0; i < WTF_ARRAY_LENGTH(kFontFamiliesWithInvalidCharWidth);
- ++i)
+ for (size_t i = 0; i < arraysize(kFontFamiliesWithInvalidCharWidth); ++i)
font_families_with_invalid_char_width_map->insert(
AtomicString(kFontFamiliesWithInvalidCharWidth[i]));
}
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 89c608180e9..8f42483d431 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
@@ -30,15 +30,13 @@
namespace blink {
class TextControlElement;
+class TextControlInnerEditorElement;
class CORE_EXPORT LayoutTextControl : public LayoutBlockFlow {
public:
~LayoutTextControl() override;
TextControlElement* GetTextControlElement() const;
- virtual scoped_refptr<ComputedStyle> CreateInnerEditorStyle(
- const ComputedStyle& start_style) const = 0;
-
const char* GetName() const override { return "LayoutTextControl"; }
protected:
@@ -46,10 +44,9 @@ class CORE_EXPORT LayoutTextControl : public LayoutBlockFlow {
// This convenience function should not be made public because
// innerEditorElement may outlive the layout tree.
- HTMLElement* InnerEditorElement() const;
+ TextControlInnerEditorElement* InnerEditorElement() const;
int ScrollbarThickness() const;
- void AdjustInnerEditorStyle(ComputedStyle& text_block_style) const;
void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
@@ -70,7 +67,6 @@ class CORE_EXPORT LayoutTextControl : public LayoutBlockFlow {
LayoutUnit line_height,
LayoutUnit non_content_height) const = 0;
- void UpdateFromElement() override;
void ComputeLogicalHeight(LayoutUnit logical_height,
LayoutUnit logical_top,
LogicalExtentComputedValues&) const override;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_control_multi_line.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_control_multi_line.cc
index c068c735a98..1a71eb52b03 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_control_multi_line.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_control_multi_line.cc
@@ -88,17 +88,6 @@ LayoutUnit LayoutTextControlMultiLine::BaselinePosition(
line_position_mode);
}
-scoped_refptr<ComputedStyle> LayoutTextControlMultiLine::CreateInnerEditorStyle(
- const ComputedStyle& start_style) const {
- scoped_refptr<ComputedStyle> text_block_style = ComputedStyle::Create();
- text_block_style->InheritFrom(start_style);
- AdjustInnerEditorStyle(*text_block_style);
- text_block_style->SetDisplay(EDisplay::kBlock);
- text_block_style->SetUnique();
-
- return text_block_style;
-}
-
LayoutObject* LayoutTextControlMultiLine::LayoutSpecialExcludedChild(
bool relayout_children,
SubtreeLayoutScope& layout_scope) {
@@ -110,9 +99,6 @@ LayoutObject* LayoutTextControlMultiLine::LayoutSpecialExcludedChild(
if (!placeholder_layout_object->IsBox())
return placeholder_layout_object;
LayoutBox* placeholder_box = ToLayoutBox(placeholder_layout_object);
- placeholder_box->MutableStyleRef().SetLogicalWidth(Length(
- ContentLogicalWidth() - placeholder_box->BorderAndPaddingLogicalWidth(),
- kFixed));
placeholder_box->LayoutIfNeeded();
placeholder_box->SetX(BorderLeft() + PaddingLeft());
placeholder_box->SetY(BorderTop() + PaddingTop());
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 91f36806736..77a522cc75d 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
@@ -60,8 +60,6 @@ class LayoutTextControlMultiLine final : public LayoutTextControl {
return LayoutUnit(-1);
}
- scoped_refptr<ComputedStyle> CreateInnerEditorStyle(
- const ComputedStyle& start_style) const override;
LayoutObject* LayoutSpecialExcludedChild(bool relayout_children,
SubtreeLayoutScope&) override;
};
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 e1616a9e9f1..6263ec7939b 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
@@ -131,13 +131,11 @@ void LayoutTextControlSingleLine::UpdateLayout() {
HTMLElement* placeholder_element = InputElement()->PlaceholderElement();
if (LayoutBox* placeholder_box =
placeholder_element ? placeholder_element->GetLayoutBox() : nullptr) {
- LayoutSize inner_editor_size;
+ LayoutUnit inner_editor_logical_width;
if (inner_editor_layout_object)
- inner_editor_size = inner_editor_layout_object->Size();
- placeholder_box->MutableStyleRef().SetWidth(Length(
- inner_editor_size.Width() - placeholder_box->BorderAndPaddingWidth(),
- kFixed));
+ inner_editor_logical_width = inner_editor_layout_object->LogicalWidth();
+ placeholder_box->SetOverrideLogicalWidth(inner_editor_logical_width);
bool needed_layout = placeholder_box->NeedsLayout();
placeholder_box->LayoutIfNeeded();
LayoutPoint text_offset;
@@ -200,16 +198,6 @@ bool LayoutTextControlSingleLine::NodeAtPoint(
return true;
}
-void LayoutTextControlSingleLine::StyleDidChange(
- StyleDifference diff,
- const ComputedStyle* old_style) {
- LayoutTextControl::StyleDidChange(diff, old_style);
- if (HTMLElement* placeholder = InputElement()->PlaceholderElement())
- placeholder->SetInlineStyleProperty(
- CSSPropertyTextOverflow,
- TextShouldBeTruncated() ? CSSValueEllipsis : CSSValueClip);
-}
-
void LayoutTextControlSingleLine::CapsLockStateMayHaveChanged() {
if (!GetNode())
return;
@@ -304,66 +292,6 @@ LayoutUnit LayoutTextControlSingleLine::ComputeControlLogicalHeight(
return line_height + non_content_height;
}
-scoped_refptr<ComputedStyle>
-LayoutTextControlSingleLine::CreateInnerEditorStyle(
- const ComputedStyle& start_style) const {
- scoped_refptr<ComputedStyle> text_block_style = ComputedStyle::Create();
- text_block_style->InheritFrom(start_style);
- AdjustInnerEditorStyle(*text_block_style);
-
- text_block_style->SetWhiteSpace(EWhiteSpace::kPre);
- text_block_style->SetOverflowWrap(EOverflowWrap::kNormal);
- text_block_style->SetTextOverflow(TextShouldBeTruncated()
- ? ETextOverflow::kEllipsis
- : ETextOverflow::kClip);
-
- int computed_line_height =
- LineHeight(true, kHorizontalLine, kPositionOfInteriorLineBoxes).ToInt();
- // Do not allow line-height to be smaller than our default.
- if (text_block_style->FontSize() >= computed_line_height) {
- text_block_style->SetLineHeight(
- ComputedStyleInitialValues::InitialLineHeight());
- }
-
- // We'd like to remove line-height if it's unnecessary because
- // overflow:scroll clips editing text by line-height.
- Length logical_height = start_style.LogicalHeight();
- // Here, we remove line-height if the INPUT fixed height is taller than the
- // line-height. It's not the precise condition because logicalHeight
- // includes border and padding if box-sizing:border-box, and there are cases
- // in which we don't want to remove line-height with percent or calculated
- // length.
- // TODO(tkent): This should be done during layout.
- if (logical_height.IsPercentOrCalc() ||
- (logical_height.IsFixed() &&
- logical_height.GetFloatValue() > computed_line_height)) {
- text_block_style->SetLineHeight(
- ComputedStyleInitialValues::InitialLineHeight());
- }
-
- text_block_style->SetDisplay(EDisplay::kBlock);
- text_block_style->SetUnique();
-
- if (InputElement()->ShouldRevealPassword())
- text_block_style->SetTextSecurity(ETextSecurity::kNone);
-
- text_block_style->SetOverflowX(EOverflow::kScroll);
- // overflow-y:visible doesn't work because overflow-x:scroll makes a layer.
- text_block_style->SetOverflowY(EOverflow::kScroll);
- scoped_refptr<ComputedStyle> no_scrollbar_style = ComputedStyle::Create();
- no_scrollbar_style->SetStyleType(kPseudoIdScrollbar);
- no_scrollbar_style->SetDisplay(EDisplay::kNone);
- text_block_style->AddCachedPseudoStyle(no_scrollbar_style);
- text_block_style->SetHasPseudoStyle(kPseudoIdScrollbar);
-
- return text_block_style;
-}
-
-bool LayoutTextControlSingleLine::TextShouldBeTruncated() const {
- return GetDocument().FocusedElement() != GetNode() &&
- StyleRef().TextOverflow() == ETextOverflow::kEllipsis;
-}
-
void LayoutTextControlSingleLine::Autoscroll(const IntPoint& position) {
LayoutBox* layout_object = InnerEditorElement()->GetLayoutBox();
if (!layout_object)
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 f30518fcffd..c849f746f54 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
@@ -35,9 +35,6 @@ class LayoutTextControlSingleLine : public LayoutTextControl {
public:
LayoutTextControlSingleLine(HTMLInputElement*);
~LayoutTextControlSingleLine() override;
- // FIXME: Move createInnerEditorStyle() to TextControlInnerEditorElement.
- scoped_refptr<ComputedStyle> CreateInnerEditorStyle(
- const ComputedStyle& start_style) const final;
void CapsLockStateMayHaveChanged();
@@ -77,12 +74,10 @@ class LayoutTextControlSingleLine : public LayoutTextControl {
LayoutUnit ComputeControlLogicalHeight(
LayoutUnit line_height,
LayoutUnit non_content_height) const override;
- void StyleDidChange(StyleDifference, const ComputedStyle* old_style) final;
void AddOverflowFromChildren() final;
bool AllowsOverflowClip() const override { return false; }
- bool TextShouldBeTruncated() const;
HTMLElement* InnerSpinButtonElement() const;
bool should_draw_caps_lock_indicator_;
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_fragment.cc b/chromium/third_party/blink/renderer/core/layout/layout_text_fragment.cc
index 26293a503fc..41153d33ddc 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_fragment.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_fragment.cc
@@ -183,10 +183,10 @@ Position LayoutTextFragment::PositionForCaretOffset(unsigned offset) const {
return Position(node, Start() + offset);
}
-Optional<unsigned> LayoutTextFragment::CaretOffsetForPosition(
+base::Optional<unsigned> LayoutTextFragment::CaretOffsetForPosition(
const Position& position) const {
if (position.IsNull() || position.AnchorNode() != AssociatedTextNode())
- return WTF::nullopt;
+ return base::nullopt;
unsigned dom_offset;
if (position.IsBeforeAnchor()) {
dom_offset = 0;
@@ -199,7 +199,7 @@ Optional<unsigned> LayoutTextFragment::CaretOffsetForPosition(
dom_offset = position.OffsetInContainerNode();
}
if (dom_offset < Start() || dom_offset > Start() + FragmentLength())
- return WTF::nullopt;
+ return base::nullopt;
return dom_offset - Start();
}
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_text_fragment.h b/chromium/third_party/blink/renderer/core/layout/layout_text_fragment.h
index b744e13da9c..3782d3d41f6 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_text_fragment.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_text_fragment.h
@@ -52,7 +52,8 @@ class CORE_EXPORT LayoutTextFragment final : public LayoutText {
bool IsTextFragment() const override { return true; }
Position PositionForCaretOffset(unsigned) const override;
- Optional<unsigned> CaretOffsetForPosition(const Position&) const override;
+ base::Optional<unsigned> CaretOffsetForPosition(
+ const Position&) const override;
unsigned Start() const { return start_; }
unsigned FragmentLength() const { return fragment_length_; }
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 3cd39c3da89..255966a250f 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
@@ -6,6 +6,9 @@
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/editing/frame_selection.h"
+#include "third_party/blink/renderer/core/editing/selection_template.h"
+#include "third_party/blink/renderer/core/editing/testing/selection_sample.h"
#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
@@ -33,6 +36,35 @@ class LayoutTextTest : public RenderingTest {
}
LayoutText* GetBasicText() { return GetLayoutTextById("target"); }
+
+ void SetSelectionAndUpdateLayoutSelection(const std::string& selection_text) {
+ const SelectionInDOMTree selection =
+ SelectionSample::SetSelectionText(GetDocument().body(), selection_text);
+ UpdateAllLifecyclePhases();
+ Selection().SetSelectionAndEndTyping(selection);
+ Selection().CommitAppearanceIfNeeded();
+ }
+
+ const LayoutText* FindFirstLayoutText() {
+ for (const Node& node :
+ NodeTraversal::DescendantsOf(*GetDocument().body())) {
+ if (node.GetLayoutObject() && node.GetLayoutObject()->IsText())
+ return ToLayoutTextOrDie(node.GetLayoutObject());
+ }
+ NOTREACHED();
+ return nullptr;
+ }
+
+ LayoutRect GetSelectionRectFor(const std::string& selection_text) {
+ std::stringstream stream;
+ stream << "<div style='font: 10px/10px Ahem;'>" << selection_text
+ << "</div>";
+ SetSelectionAndUpdateLayoutSelection(stream.str());
+ const Node* target = GetDocument().getElementById("target");
+ const LayoutObject* layout_object =
+ target ? target->GetLayoutObject() : FindFirstLayoutText();
+ return layout_object->LocalSelectionRect();
+ }
};
const char kTacoText[] = "Los Compadres Taco Truck";
@@ -447,7 +479,7 @@ TEST_P(ParameterizedLayoutTextTest, GetUpperLeftCorner) {
<div>12345 123<span id="target">45</span></div>
)HTML");
LayoutText* layout_text = GetLayoutTextById("target");
- Optional<FloatPoint> upper_left = layout_text->GetUpperLeftCorner();
+ base::Optional<FloatPoint> upper_left = layout_text->GetUpperLeftCorner();
EXPECT_TRUE(upper_left.has_value());
EXPECT_EQ(FloatPoint(30, 10), upper_left.value());
}
@@ -465,7 +497,7 @@ TEST_P(ParameterizedLayoutTextTest, GetUpperLeftCornerVLR) {
<div>12345 123<span id="target">45</span></div>
)HTML");
LayoutText* layout_text = GetLayoutTextById("target");
- Optional<FloatPoint> upper_left = layout_text->GetUpperLeftCorner();
+ base::Optional<FloatPoint> upper_left = layout_text->GetUpperLeftCorner();
EXPECT_TRUE(upper_left.has_value());
EXPECT_EQ(FloatPoint(10, 30), upper_left.value());
}
@@ -579,4 +611,32 @@ TEST_P(ParameterizedLayoutTextTest, WordBreakElement) {
EXPECT_EQ(0, layout_wbr->CaretMaxOffset());
}
+TEST_P(ParameterizedLayoutTextTest, LocalSelectionRect) {
+ LoadAhem();
+ // TODO(yoichio): Fix LayoutNG incompatibility.
+ EXPECT_EQ(LayoutRect(10, 0, 50, 10), GetSelectionRectFor("f^oo ba|r"));
+ EXPECT_EQ(LayoutRect(0, 0, 40, 20),
+ GetSelectionRectFor("<div style='width: 2em'>f^oo ba|r</div>"));
+ EXPECT_EQ(
+ LayoutNGEnabled() ? LayoutRect(0, 0, 0, 0) : LayoutRect(30, 0, 10, 10),
+ GetSelectionRectFor("foo^<br id='target'>|bar"));
+ EXPECT_EQ(
+ LayoutNGEnabled() ? LayoutRect(10, 0, 30, 10) : LayoutRect(10, 0, 20, 10),
+ GetSelectionRectFor("f^oo<br>b|ar"));
+ EXPECT_EQ(LayoutRect(10, 0, 30, 10),
+ GetSelectionRectFor("<div>f^oo</div><div>b|ar</div>"));
+ EXPECT_EQ(LayoutRect(30, 0, 10, 10), GetSelectionRectFor("foo^ |bar"));
+ EXPECT_EQ(LayoutRect(0, 0, 0, 0), GetSelectionRectFor("^ |foo"));
+ EXPECT_EQ(LayoutRect(0, 0, 0, 0),
+ GetSelectionRectFor("fo^o<wbr id='target'>ba|r"));
+ EXPECT_EQ(
+ LayoutRect(0, 0, 10, 10),
+ GetSelectionRectFor("<style>:first-letter { float: right}</style>^fo|o"));
+ // Since we don't paint trimed white spaces on LayoutNG, we don't need fix
+ // this case.
+ EXPECT_EQ(
+ LayoutNGEnabled() ? LayoutRect(0, 0, 0, 0) : LayoutRect(30, 0, 10, 10),
+ GetSelectionRectFor("foo^ |"));
+}
+
} // namespace blink
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 a5a2a3b0a8b..fe2ee59d0ec 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme.cc
@@ -22,7 +22,6 @@
#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/public/platform/platform.h"
-#include "third_party/blink/public/platform/web_fallback_theme_engine.h"
#include "third_party/blink/public/platform/web_rect.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
@@ -47,16 +46,18 @@
#include "third_party/blink/renderer/core/layout/layout_theme_mobile.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/core/paint/fallback_theme.h"
#include "third_party/blink/renderer/core/style/computed_style.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/layout_test_support.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/text/string_truncator.h"
#include "third_party/blink/renderer/platform/theme.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
+#include "ui/native_theme/native_theme.h"
// The methods in this file are shared by all themes on every platform.
@@ -883,8 +884,9 @@ void LayoutTheme::AdjustCheckboxStyleUsingFallbackTheme(
if (!style.Width().IsIntrinsicOrAuto() && !style.Height().IsAuto())
return;
- IntSize size = Platform::Current()->FallbackThemeEngine()->GetSize(
- WebFallbackThemeEngine::kPartCheckbox);
+ IntSize size(GetFallbackTheme().GetPartSize(ui::NativeTheme::kCheckbox,
+ ui::NativeTheme::kNormal,
+ ui::NativeTheme::ExtraParams()));
float zoom_level = style.EffectiveZoom();
size.SetWidth(size.Width() * zoom_level);
size.SetHeight(size.Height() * zoom_level);
@@ -906,8 +908,9 @@ void LayoutTheme::AdjustRadioStyleUsingFallbackTheme(
if (!style.Width().IsIntrinsicOrAuto() && !style.Height().IsAuto())
return;
- IntSize size = Platform::Current()->FallbackThemeEngine()->GetSize(
- WebFallbackThemeEngine::kPartRadio);
+ IntSize size(GetFallbackTheme().GetPartSize(ui::NativeTheme::kRadio,
+ ui::NativeTheme::kNormal,
+ ui::NativeTheme::ExtraParams()));
float zoom_level = style.EffectiveZoom();
size.SetWidth(size.Width() * zoom_level);
size.SetHeight(size.Height() * zoom_level);
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 59baded35ab..0a7a6a6035c 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_theme.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_theme.h
@@ -36,6 +36,7 @@
namespace blink {
+class ChromeClient;
class ComputedStyle;
class Element;
class FileList;
@@ -45,7 +46,6 @@ class HTMLInputElement;
class LengthSize;
class Locale;
class Node;
-class PlatformChromeClient;
class Theme;
class ThemePainter;
@@ -190,7 +190,7 @@ class CORE_EXPORT LayoutTheme : public RefCounted<LayoutTheme> {
virtual int PopupInternalPaddingStart(const ComputedStyle&) const {
return 0;
}
- virtual int PopupInternalPaddingEnd(const PlatformChromeClient*,
+ virtual int PopupInternalPaddingEnd(const ChromeClient*,
const ComputedStyle&) const {
return 0;
}
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 4b9acafd7f7..e00e520626e 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
@@ -28,11 +28,11 @@
#include "third_party/blink/public/platform/web_theme_engine.h"
#include "third_party/blink/renderer/core/css_value_keywords.h"
#include "third_party/blink/renderer/core/layout/layout_theme_font_provider.h"
+#include "third_party/blink/renderer/core/page/chrome_client.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#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/layout_test_support.h"
-#include "third_party/blink/renderer/platform/platform_chrome_client.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
@@ -317,7 +317,7 @@ int LayoutThemeDefault::PopupInternalPaddingStart(
}
int LayoutThemeDefault::PopupInternalPaddingEnd(
- const PlatformChromeClient* client,
+ const ChromeClient* client,
const ComputedStyle& style) const {
if (style.Appearance() == kNoControlPart)
return 0;
@@ -344,7 +344,7 @@ int LayoutThemeDefault::MenuListArrowWidthInDIP() const {
}
float LayoutThemeDefault::ClampedMenuListArrowPaddingSize(
- const PlatformChromeClient* client,
+ const ChromeClient* client,
const ComputedStyle& style) const {
if (cached_menu_list_arrow_padding_size_ > 0 &&
style.EffectiveZoom() == cached_menu_list_arrow_zoom_level_)
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 1d9b1fb38b2..ba106da1757 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
@@ -112,7 +112,7 @@ class CORE_EXPORT LayoutThemeDefault : public LayoutTheme {
// These methods define the padding for the MenuList's inner block.
int PopupInternalPaddingStart(const ComputedStyle&) const override;
- int PopupInternalPaddingEnd(const PlatformChromeClient*,
+ int PopupInternalPaddingEnd(const ChromeClient*,
const ComputedStyle&) const override;
int PopupInternalPaddingTop(const ComputedStyle&) const override;
int PopupInternalPaddingBottom(const ComputedStyle&) const override;
@@ -121,7 +121,7 @@ class CORE_EXPORT LayoutThemeDefault : public LayoutTheme {
// thickness, which is 3px or 4px, and we use the value from the default Aura
// theme.
int MenuListArrowWidthInDIP() const;
- float ClampedMenuListArrowPaddingSize(const PlatformChromeClient*,
+ float ClampedMenuListArrowPaddingSize(const ChromeClient*,
const ComputedStyle&) const;
static void SetSelectionColors(unsigned active_background_color,
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 986809fa106..f0ffd0fb0da 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
@@ -69,9 +69,6 @@ class LayoutThemeMac final : public LayoutTheme {
float& font_size,
AtomicString& font_family) const override;
- bool NeedsHackForTextControlWithFontFamily(
- const AtomicString& family) const override;
-
int MinimumMenuListSize(const ComputedStyle&) const override;
void AdjustSliderThumbSize(ComputedStyle&) const override;
@@ -80,7 +77,7 @@ class LayoutThemeMac final : public LayoutTheme {
int SliderTickOffsetFromTrackCenter() const override;
int PopupInternalPaddingStart(const ComputedStyle&) const override;
- int PopupInternalPaddingEnd(const PlatformChromeClient*,
+ int PopupInternalPaddingEnd(const ChromeClient*,
const ComputedStyle&) const override;
int PopupInternalPaddingTop(const ComputedStyle&) const override;
int PopupInternalPaddingBottom(const ComputedStyle&) const override;
@@ -97,7 +94,7 @@ class LayoutThemeMac final : public LayoutTheme {
bool SupportsSelectionForegroundColors() const override { return false; }
- virtual bool IsModalColorChooser() const { return false; }
+ bool IsModalColorChooser() const override { return false; }
protected:
LayoutThemeMac();
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 79f3c20dbe6..d2d26f07ab9 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,6 +31,7 @@
#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/layout_test_support.h"
#import "third_party/blink/renderer/platform/mac/color_mac.h"
@@ -39,7 +40,6 @@
#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/text/string_truncator.h"
#import "third_party/blink/renderer/platform/theme.h"
// The methods in this file are specific to the Mac OS X platform.
@@ -265,13 +265,6 @@ void LayoutThemeMac::SystemFont(CSSValueID system_font_id,
font_family = FontFamilyNames::system_ui;
}
-bool LayoutThemeMac::NeedsHackForTextControlWithFontFamily(
- const AtomicString& family) const {
- // This hack is only applied on OSX 10.9.
- // https://code.google.com/p/chromium/issues/detail?id=515989#c8
- return IsOS10_9() && family == FontFamilyNames::system_ui;
-}
-
static RGBA32 ConvertNSColorToColor(NSColor* color) {
NSColor* color_in_color_space = ColorInColorSpace(color);
if (color_in_color_space) {
@@ -494,10 +487,6 @@ bool LayoutThemeMac::IsControlStyled(const ComputedStyle& style) const {
return true;
if (!style.Height().IsIntrinsicOrAuto())
return true;
- // NSPopUpButtonCell on macOS 10.9 doesn't support
- // NSUserInterfaceLayoutDirectionRightToLeft.
- if (IsOS10_9() && style.Direction() == TextDirection::kRtl)
- return true;
}
// Some other cells don't work well when scaled.
if (style.EffectiveZoom() != 1) {
@@ -770,7 +759,7 @@ int LayoutThemeMac::PopupInternalPaddingStart(
return 0;
}
-int LayoutThemeMac::PopupInternalPaddingEnd(const PlatformChromeClient*,
+int LayoutThemeMac::PopupInternalPaddingEnd(const ChromeClient*,
const ComputedStyle& style) const {
if (style.Appearance() == kMenulistPart)
return PopupButtonPadding(
@@ -981,7 +970,7 @@ NSSearchFieldCell* LayoutThemeMac::Search() const {
// this is achieved by calling |setCenteredLook| with NO. In OS10.11 and
// later, instead call |setPlaceholderString| with an empty string.
// See https://crbug.com/752362.
- if (IsOS10_9() || IsOS10_10()) {
+ if (IsOS10_10()) {
SEL sel = @selector(setCenteredLook:);
if ([search_.Get() respondsToSelector:sel]) {
BOOL bool_value = NO;
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 893292f5a68..f7d8c402de2 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
@@ -48,6 +48,7 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.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/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"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h"
@@ -67,7 +68,8 @@ namespace blink {
using namespace HTMLNames;
-static void PrintBorderStyle(TextStream& ts, const EBorderStyle border_style) {
+static void PrintBorderStyle(WTF::TextStream& ts,
+ const EBorderStyle border_style) {
switch (border_style) {
case EBorderStyle::kNone:
ts << "none";
@@ -141,11 +143,11 @@ String QuoteAndEscapeNonPrintables(const String& s) {
return result.ToString();
}
-TextStream& operator<<(TextStream& ts, const Color& c) {
+WTF::TextStream& operator<<(WTF::TextStream& ts, const Color& c) {
return ts << c.NameForLayoutTreeAsText();
}
-void LayoutTreeAsText::WriteLayoutObject(TextStream& ts,
+void LayoutTreeAsText::WriteLayoutObject(WTF::TextStream& ts,
const LayoutObject& o,
LayoutAsTextBehavior behavior) {
ts << o.DecoratedName();
@@ -363,7 +365,9 @@ void LayoutTreeAsText::WriteLayoutObject(TextStream& ts,
}
}
-static void WriteInlineBox(TextStream& ts, const InlineBox& box, int indent) {
+static void WriteInlineBox(WTF::TextStream& ts,
+ const InlineBox& box,
+ int indent) {
WriteIndent(ts, indent);
ts << "+ ";
ts << box.BoxName() << " {" << box.GetLineLayoutItem().DebugName() << "}"
@@ -373,7 +377,7 @@ static void WriteInlineBox(TextStream& ts, const InlineBox& box, int indent) {
<< box.BaselinePosition(kIdeographicBaseline);
}
-static void WriteInlineTextBox(TextStream& ts,
+static void WriteInlineTextBox(WTF::TextStream& ts,
const InlineTextBox& text_box,
int indent) {
WriteInlineBox(ts, text_box, indent);
@@ -386,7 +390,7 @@ static void WriteInlineTextBox(TextStream& ts,
<< " \"" << value << "\"";
}
-static void WriteInlineFlowBox(TextStream& ts,
+static void WriteInlineFlowBox(WTF::TextStream& ts,
const InlineFlowBox& root_box,
int indent) {
WriteInlineBox(ts, root_box, indent);
@@ -407,7 +411,7 @@ static void WriteInlineFlowBox(TextStream& ts,
}
}
-void LayoutTreeAsText::WriteLineBoxTree(TextStream& ts,
+void LayoutTreeAsText::WriteLineBoxTree(WTF::TextStream& ts,
const LayoutBlockFlow& o,
int indent) {
for (const InlineFlowBox* root_box : o.LineBoxes()) {
@@ -415,7 +419,7 @@ void LayoutTreeAsText::WriteLineBoxTree(TextStream& ts,
}
}
-static void WriteTextRun(TextStream& ts,
+static void WriteTextRun(WTF::TextStream& ts,
const LayoutText& o,
const InlineTextBox& run) {
// FIXME: For now use an "enclosingIntRect" model for x, y and logicalWidth,
@@ -444,7 +448,7 @@ static void WriteTextRun(TextStream& ts,
ts << "\n";
}
-static void WriteTextFragment(TextStream& ts,
+static void WriteTextFragment(WTF::TextStream& ts,
const NGPhysicalFragment& physical_fragment,
NGPhysicalOffset offset_to_container_box) {
if (!physical_fragment.IsText())
@@ -464,7 +468,7 @@ static void WriteTextFragment(TextStream& ts,
ts << "\n";
}
-static void WritePaintProperties(TextStream& ts,
+static void WritePaintProperties(WTF::TextStream& ts,
const LayoutObject& o,
int indent) {
bool has_fragments = o.FirstFragment().NextFragment();
@@ -490,7 +494,7 @@ static void WritePaintProperties(TextStream& ts,
}
}
-void Write(TextStream& ts,
+void Write(WTF::TextStream& ts,
const LayoutObject& o,
int indent,
LayoutAsTextBehavior behavior) {
@@ -585,7 +589,7 @@ enum LayerPaintPhase {
kLayerPaintPhaseForeground = 1
};
-static void Write(TextStream& ts,
+static void Write(WTF::TextStream& ts,
PaintLayer& layer,
const LayoutRect& layer_bounds,
const LayoutRect& background_clip_rect,
@@ -595,24 +599,10 @@ static void Write(TextStream& ts,
LayoutAsTextBehavior behavior = kLayoutAsTextBehaviorNormal,
const PaintLayer* marked_layer = nullptr) {
IntRect adjusted_layout_bounds = PixelSnappedIntRect(layer_bounds);
- IntRect adjusted_layout_bounds_with_scrollbars = adjusted_layout_bounds;
IntRect adjusted_background_clip_rect =
PixelSnappedIntRect(background_clip_rect);
IntRect adjusted_clip_rect = PixelSnappedIntRect(clip_rect);
- bool report_frame_scroll_info =
- layer.GetLayoutObject().IsLayoutView() &&
- !RuntimeEnabledFeatures::RootLayerScrollingEnabled();
-
- if (report_frame_scroll_info) {
- LayoutView& layout_view = ToLayoutView(layer.GetLayoutObject());
-
- adjusted_layout_bounds_with_scrollbars.SetWidth(
- layout_view.ViewWidth(kIncludeScrollbars));
- adjusted_layout_bounds_with_scrollbars.SetHeight(
- layout_view.ViewHeight(kIncludeScrollbars));
- }
-
if (marked_layer)
ts << (marked_layer == &layer ? "*" : " ");
@@ -626,24 +616,19 @@ static void Write(TextStream& ts,
if (behavior & kLayoutAsTextShowAddresses)
ts << static_cast<const void*>(&layer) << " ";
- ts << adjusted_layout_bounds_with_scrollbars;
+ ts << adjusted_layout_bounds;
if (!adjusted_layout_bounds.IsEmpty()) {
if (!adjusted_background_clip_rect.Contains(adjusted_layout_bounds))
ts << " backgroundClip " << adjusted_background_clip_rect;
- if (!adjusted_clip_rect.Contains(adjusted_layout_bounds_with_scrollbars))
+ if (!adjusted_clip_rect.Contains(adjusted_layout_bounds))
ts << " clip " << adjusted_clip_rect;
}
if (layer.IsTransparent())
ts << " transparent";
- if (layer.GetLayoutObject().HasOverflowClip() || report_frame_scroll_info) {
- ScrollableArea* scrollable_area;
- if (report_frame_scroll_info)
- scrollable_area = ToLayoutView(layer.GetLayoutObject()).GetFrameView();
- else
- scrollable_area = layer.GetScrollableArea();
-
+ if (layer.GetLayoutObject().HasOverflowClip()) {
+ ScrollableArea* scrollable_area = layer.GetScrollableArea();
ScrollOffset adjusted_scroll_offset =
scrollable_area->GetScrollOffset() +
ToFloatSize(scrollable_area->ScrollOrigin());
@@ -669,8 +654,9 @@ static void Write(TextStream& ts,
if (layer.GetLayoutObject().Style()->HasBlendMode()) {
ts << " blendMode: "
- << CompositeOperatorName(kCompositeSourceOver,
- layer.GetLayoutObject().Style()->BlendMode());
+ << CompositeOperatorName(
+ kCompositeSourceOver,
+ layer.GetLayoutObject().Style()->GetBlendMode());
}
if (behavior & kLayoutAsTextShowCompositedLayers) {
@@ -703,7 +689,7 @@ static Vector<PaintLayerStackingNode*> NormalFlowListFor(
return vector;
}
-void LayoutTreeAsText::WriteLayers(TextStream& ts,
+void LayoutTreeAsText::WriteLayers(WTF::TextStream& ts,
const PaintLayer* root_layer,
PaintLayer* layer,
const LayoutRect& paint_rect,
@@ -829,7 +815,7 @@ static String NodePosition(Node* node) {
return result.ToString();
}
-static void WriteSelection(TextStream& ts, const LayoutObject* o) {
+static void WriteSelection(WTF::TextStream& ts, const LayoutObject* o) {
Node* n = o->GetNode();
if (!n || !n->IsDocumentNode())
return;
@@ -859,7 +845,7 @@ static void WriteSelection(TextStream& ts, const LayoutObject* o) {
static String ExternalRepresentation(LayoutBox* layout_object,
LayoutAsTextBehavior behavior,
const PaintLayer* marked_layer = nullptr) {
- TextStream ts;
+ WTF::TextStream ts;
if (!layout_object->HasLayer())
return ts.Release();
@@ -917,7 +903,7 @@ String ExternalRepresentation(Element* element, LayoutAsTextBehavior behavior) {
behavior | kLayoutAsTextShowAllLayers);
}
-static void WriteCounterValuesFromChildren(TextStream& stream,
+static void WriteCounterValuesFromChildren(WTF::TextStream& stream,
LayoutObject* parent,
bool& is_first_counter) {
for (LayoutObject* child = parent->SlowFirstChild(); child;
@@ -934,7 +920,7 @@ static void WriteCounterValuesFromChildren(TextStream& stream,
String CounterValueForElement(Element* element) {
element->GetDocument().UpdateStyleAndLayout();
- TextStream stream;
+ WTF::TextStream stream;
bool is_first_counter = true;
// The counter layoutObjects should be children of :before or :after
// pseudo-elements.
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.h b/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.h
index 601a9dd2e21..2c6191a187d 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_tree_as_text.h
@@ -27,9 +27,9 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LAYOUT_TREE_AS_TEXT_H_
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/text/text_stream.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/forward.h"
+#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
namespace blink {
@@ -40,7 +40,6 @@ class LayoutRect;
class LocalFrame;
class LayoutBlockFlow;
class LayoutObject;
-class TextStream;
enum LayoutAsTextBehaviorFlags {
kLayoutAsTextBehaviorNormal = 0,
@@ -77,7 +76,7 @@ ExternalRepresentation(LocalFrame*,
CORE_EXPORT String
ExternalRepresentation(Element*,
LayoutAsTextBehavior = kLayoutAsTextBehaviorNormal);
-void Write(TextStream&,
+void Write(WTF::TextStream&,
const LayoutObject&,
int indent = 0,
LayoutAsTextBehavior = kLayoutAsTextBehaviorNormal);
@@ -89,17 +88,17 @@ class LayoutTreeAsText {
// (This just involves rebaselining many results though, so for now it's
// not being done).
public:
- static void WriteLayoutObject(TextStream&,
+ static void WriteLayoutObject(WTF::TextStream&,
const LayoutObject&,
LayoutAsTextBehavior);
- static void WriteLayers(TextStream&,
+ static void WriteLayers(WTF::TextStream&,
const PaintLayer* root_layer,
PaintLayer*,
const LayoutRect& paint_dirty_rect,
int indent = 0,
LayoutAsTextBehavior = kLayoutAsTextBehaviorNormal,
const PaintLayer* marked_layer = nullptr);
- static void WriteLineBoxTree(TextStream&,
+ static void WriteLineBoxTree(WTF::TextStream&,
const LayoutBlockFlow&,
int indent = 0);
};
@@ -111,7 +110,7 @@ CORE_EXPORT String CounterValueForElement(Element*);
CORE_EXPORT String MarkerTextForListItem(Element*);
-TextStream& operator<<(TextStream&, const Color&);
+WTF::TextStream& operator<<(WTF::TextStream&, const Color&);
} // namespace blink
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 db9b951b1d6..b66e83313a3 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_video.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_video.cc
@@ -25,7 +25,6 @@
#include "third_party/blink/renderer/core/layout/layout_video.h"
-#include "third_party/blink/public/platform/web_layer.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_names.h"
@@ -185,7 +184,7 @@ LayoutRect LayoutVideo::ReplacedContentRect() const {
}
bool LayoutVideo::SupportsAcceleratedRendering() const {
- return !!MediaElement()->PlatformLayer();
+ return !!MediaElement()->CcLayer();
}
static const LayoutBlock* LayoutObjectPlaceholder(
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 1ce91caf717..bc3bf00be63 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_view.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_view.cc
@@ -45,12 +45,12 @@
#include "third_party/blink/renderer/core/paint/view_painter.h"
#include "third_party/blink/renderer/core/svg/svg_document_extensions.h"
#include "third_party/blink/renderer/platform/geometry/float_quad.h"
-#include "third_party/blink/renderer/platform/geometry/transform_state.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_controller.h"
#include "third_party/blink/renderer/platform/histogram.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/traced_value.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
+#include "third_party/blink/renderer/platform/transforms/transform_state.h"
namespace blink {
@@ -244,8 +244,7 @@ void LayoutView::SetShouldDoFullPaintInvalidationOnResizeIfNeeded(
// should fully invalidate on viewport resize if the background image is not
// composited and needs full paint invalidation on background positioning area
// resize.
- if (Style()->HasFixedBackgroundImage() &&
- (!compositor_ || !compositor_->NeedsFixedRootBackgroundLayer())) {
+ if (Style()->HasFixedBackgroundImage()) {
if ((width_changed && MustInvalidateFillLayersPaintOnWidthChange(
Style()->BackgroundLayers())) ||
(height_changed && MustInvalidateFillLayersPaintOnHeightChange(
@@ -294,14 +293,10 @@ void LayoutView::UpdateLayout() {
if (!GetDocument().Paginated())
SetPageLogicalHeight(LayoutUnit());
- // TODO(wangxianzhu): Move this into ViewPaintInvalidator when
- // rootLayerScrolling is permanently enabled.
- IncludeScrollbarsInRect include_scrollbars =
- RuntimeEnabledFeatures::RootLayerScrollingEnabled() ? kIncludeScrollbars
- : kExcludeScrollbars;
+ // TODO(wangxianzhu): Move this into ViewPaintInvalidator.
SetShouldDoFullPaintInvalidationOnResizeIfNeeded(
- OffsetWidth() != GetLayoutSize(include_scrollbars).Width(),
- OffsetHeight() != GetLayoutSize(include_scrollbars).Height());
+ OffsetWidth() != GetLayoutSize(kIncludeScrollbars).Width(),
+ OffsetHeight() != GetLayoutSize(kIncludeScrollbars).Height());
if (PageLogicalHeight() && ShouldUsePrintingLayout()) {
min_preferred_logical_width_ = max_preferred_logical_width_ =
@@ -327,22 +322,7 @@ void LayoutView::UpdateLayout() {
ClearNeedsLayout();
}
-LayoutRect LayoutView::VisualOverflowRect() const {
- // In root layer scrolling mode, the LayoutView performs overflow clipping
- // like a regular scrollable div.
- if (RuntimeEnabledFeatures::RootLayerScrollingEnabled())
- return LayoutBlockFlow::VisualOverflowRect();
-
- // In normal compositing mode, LayoutView doesn't actually apply clipping
- // on its descendants. Instead their visual overflow is propagated to
- // compositor()->m_rootContentLayer for accelerated scrolling.
- return LayoutOverflowRect();
-}
-
LayoutRect LayoutView::LocalVisualRectIgnoringVisibility() const {
- // TODO(wangxianzhu): This is only required without rootLayerScrolls (though
- // it is also correct but unnecessary with rootLayerScrolls) because of the
- // special LayoutView overflow model.
LayoutRect rect = VisualOverflowRect();
rect.Unite(LayoutRect(rect.Location(), ViewRect().Size()));
return rect;
@@ -492,17 +472,18 @@ bool LayoutView::MapToVisualRectInAncestorSpace(
LayoutRect& rect,
MapCoordinatesFlags mode,
VisualRectFlags visual_rect_flags) const {
- if (MapToVisualRectInAncestorSpaceInternalFastPath(ancestor, rect,
- visual_rect_flags))
- return !rect.IsEmpty();
+ bool intersects = true;
+ if (MapToVisualRectInAncestorSpaceInternalFastPath(
+ ancestor, rect, visual_rect_flags, intersects))
+ return intersects;
TransformState transform_state(TransformState::kApplyTransformDirection,
FloatQuad(FloatRect(rect)));
- bool retval = MapToVisualRectInAncestorSpaceInternal(
- ancestor, transform_state, mode, visual_rect_flags);
+ intersects = MapToVisualRectInAncestorSpaceInternal(ancestor, transform_state,
+ mode, visual_rect_flags);
transform_state.Flatten();
rect = LayoutRect(transform_state.LastPlanarQuad().BoundingBox());
- return retval;
+ return intersects;
}
bool LayoutView::MapToVisualRectInAncestorSpaceInternal(
@@ -749,10 +730,6 @@ IntRect LayoutView::DocumentRect() const {
return PixelSnappedIntRect(overflow_rect);
}
-bool LayoutView::RootBackgroundIsEntirelyFixed() const {
- return Style()->HasEntirelyFixedBackground();
-}
-
IntSize LayoutView::GetLayoutSize(
IncludeScrollbarsInRect scrollbar_inclusion) const {
if (ShouldUsePrintingLayout())
@@ -780,18 +757,6 @@ int LayoutView::ViewLogicalHeight(
: ViewWidth(scrollbar_inclusion);
}
-int LayoutView::ViewLogicalWidthForBoxSizing() const {
- return ViewLogicalWidth(RuntimeEnabledFeatures::RootLayerScrollingEnabled()
- ? kIncludeScrollbars
- : kExcludeScrollbars);
-}
-
-int LayoutView::ViewLogicalHeightForBoxSizing() const {
- return ViewLogicalHeight(RuntimeEnabledFeatures::RootLayerScrollingEnabled()
- ? kIncludeScrollbars
- : kExcludeScrollbars);
-}
-
LayoutUnit LayoutView::ViewLogicalHeightForPercentages() const {
if (ShouldUsePrintingLayout())
return PageLogicalHeight();
@@ -892,24 +857,6 @@ void LayoutView::UpdateFromStyle() {
SetHasBoxDecorationBackground(true);
}
-bool LayoutView::AllowsOverflowClip() const {
- return RuntimeEnabledFeatures::RootLayerScrollingEnabled();
-}
-
-ScrollResult LayoutView::Scroll(ScrollGranularity granularity,
- const FloatSize& delta) {
- // TODO(bokan): We shouldn't need this specialization but we currently do
- // because of the Windows pan scrolling path. That should go through a more
- // normalized ScrollManager-like scrolling path and we should get rid of
- // of this override. All frame scrolling should be handled by
- // ViewportScrollCallback.
-
- if (!GetFrameView())
- return ScrollResult(false, false, delta.Width(), delta.Height());
-
- return GetFrameView()->GetScrollableArea()->UserScroll(granularity, delta);
-}
-
LayoutRect LayoutView::DebugRect() const {
LayoutRect rect;
LayoutBlock* block = ContainingBlock();
@@ -935,16 +882,6 @@ bool LayoutView::UpdateLogicalWidthAndColumnWidth() {
return relayout_children || ShouldUsePrintingLayout();
}
-bool LayoutView::PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const {
- // Frame scroll corner is painted using LayoutView as the display item client.
- if (!RuntimeEnabledFeatures::RootLayerScrollingEnabled() &&
- (GetFrameView()->HorizontalScrollbar() ||
- GetFrameView()->VerticalScrollbar()))
- return false;
-
- return LayoutBlockFlow::PaintedOutputOfObjectHasNoEffectRegardlessOfSize();
-}
-
void LayoutView::UpdateCounters() {
if (!needs_counter_update_)
return;
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 e6bbcdc0460..867d64060c1 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_view.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_view.h
@@ -184,10 +184,6 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
IntRect DocumentRect() const;
- // LayoutObject that paints the root background has background-images which
- // all have background-attachment: fixed.
- bool RootBackgroundIsEntirelyFixed() const;
-
IntervalArena* GetIntervalArena();
void SetLayoutQuoteHead(LayoutQuote* head) { layout_quote_head_ = head; }
@@ -224,7 +220,6 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
layout_state_ = layout_state_->Next();
}
- LayoutRect VisualOverflowRect() const override;
LayoutRect LocalVisualRectIgnoringVisibility() const override;
// Invalidates paint for the entire view, including composited descendants,
@@ -243,13 +238,9 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
return false;
}
- // The rootLayerScrolls setting will ultimately determine whether
- // LocalFrameView or PaintLayerScrollableArea handle the scroll.
- ScrollResult Scroll(ScrollGranularity, const FloatSize&) override;
-
LayoutRect DebugRect() const override;
- virtual IntSize ScrolledContentOffset() const;
+ IntSize ScrolledContentOffset() const override;
private:
void MapLocalToAncestor(
@@ -275,17 +266,18 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
#endif
void UpdateFromStyle() override;
- bool AllowsOverflowClip() const override;
bool ShouldUsePrintingLayout() const;
- int ViewLogicalWidthForBoxSizing() const;
- int ViewLogicalHeightForBoxSizing() const;
+ int ViewLogicalWidthForBoxSizing() const {
+ return ViewLogicalWidth(kIncludeScrollbars);
+ }
+ int ViewLogicalHeightForBoxSizing() const {
+ return ViewLogicalHeight(kIncludeScrollbars);
+ }
bool UpdateLogicalWidthAndColumnWidth() override;
- bool PaintedOutputOfObjectHasNoEffectRegardlessOfSize() const override;
-
UntracedMember<LocalFrameView> frame_view_;
// The page logical height.
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_word_break.cc b/chromium/third_party/blink/renderer/core/layout/layout_word_break.cc
index a52a3672888..71af9f4e0fb 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_word_break.cc
+++ b/chromium/third_party/blink/renderer/core/layout/layout_word_break.cc
@@ -47,10 +47,10 @@ Position LayoutWordBreak::PositionForCaretOffset(unsigned offset) const {
return Position::BeforeNode(*GetNode());
}
-Optional<unsigned> LayoutWordBreak::CaretOffsetForPosition(
+base::Optional<unsigned> LayoutWordBreak::CaretOffsetForPosition(
const Position& position) const {
if (position.IsNull() || position.AnchorNode() != GetNode())
- return WTF::nullopt;
+ return base::nullopt;
DCHECK(position.IsBeforeAnchor() || position.IsAfterAnchor());
// The only allowed caret offset is 0, since LayoutWordBreak always has
// |TextLength() == 0|.
diff --git a/chromium/third_party/blink/renderer/core/layout/layout_word_break.h b/chromium/third_party/blink/renderer/core/layout/layout_word_break.h
index a065ef0fd45..35d79ff71ca 100644
--- a/chromium/third_party/blink/renderer/core/layout/layout_word_break.h
+++ b/chromium/third_party/blink/renderer/core/layout/layout_word_break.h
@@ -38,7 +38,7 @@ class LayoutWordBreak final : public LayoutText {
explicit LayoutWordBreak(HTMLElement*);
Position PositionForCaretOffset(unsigned offset) const final;
- Optional<unsigned> CaretOffsetForPosition(const Position&) const final;
+ base::Optional<unsigned> CaretOffsetForPosition(const Position&) const final;
const char* GetName() const override { return "LayoutWordBreak"; }
bool IsWordBreak() const override;
diff --git a/chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h b/chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
index 0b50205bac7..b948bc287b7 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
+++ b/chromium/third_party/blink/renderer/core/layout/line/breaking_context_inline_headers.h
@@ -1491,7 +1491,11 @@ inline void BreakingContext::CommitAndUpdateLineBreakIfNeeded() {
bool check_for_break = auto_wrap_;
if (width_.CommittedWidth() && !width_.FitsOnLine() &&
line_break_.GetLineLayoutItem() && curr_ws_ == EWhiteSpace::kNowrap) {
- if (width_.FitsOnLine(0, kExcludeWhitespace)) {
+ // If this nowrap item fits but its trailing spaces does not, and if the
+ // next item is auto-wrap, break before the next item.
+ // TODO(kojii): This case should be handled when we read next item.
+ if (width_.FitsOnLine(0, kExcludeWhitespace) &&
+ (!next_object_ || next_object_.StyleRef().AutoWrap())) {
width_.Commit();
line_break_.MoveToStartOf(next_object_);
}
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 ddc8753cf76..ae29ffb06f4 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
@@ -202,9 +202,6 @@ class CORE_EXPORT InlineBox : public DisplayItemClient {
InlineBox* PrevLeafChild() const;
// Helper functions for editing and hit-testing code.
- // FIXME: These two functions should be moved to RenderedPosition once the
- // code to convert between Position and inline box, offset pair is moved to
- // RenderedPosition.
InlineBox* NextLeafChildIgnoringLineBreak() const;
InlineBox* PrevLeafChildIgnoringLineBreak() const;
diff --git a/chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.cc b/chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
index 337921a55a7..3f9a3fa0370 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/line/inline_flow_box.cc
@@ -34,6 +34,7 @@
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/line/glyph_overflow.h"
#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
+#include "third_party/blink/renderer/core/layout/line/line_orientation_utils.h"
#include "third_party/blink/renderer/core/layout/line/root_inline_box.h"
#include "third_party/blink/renderer/core/paint/box_painter.h"
#include "third_party/blink/renderer/core/paint/inline_flow_box_painter.h"
@@ -988,8 +989,8 @@ inline void InlineFlowBox::AddBoxShadowVisualOverflow(
// Similar to how glyph overflow works, if our lines are flipped, then it's
// actually the opposite shadow that applies, since the line is "upside down"
// in terms of block coordinates.
- LayoutRectOutsets logical_outsets(
- outsets.LineOrientationOutsetsWithFlippedLines(writing_mode));
+ LayoutRectOutsets logical_outsets =
+ LineOrientationLayoutRectOutsetsWithFlippedLines(outsets, writing_mode);
LayoutRect shadow_bounds(LogicalFrameRect());
shadow_bounds.Expand(logical_outsets);
@@ -1013,8 +1014,8 @@ inline void InlineFlowBox::AddBorderOutsetVisualOverflow(
// actually the opposite border that applies, since the line is "upside down"
// in terms of block coordinates. vertical-rl is the flipped line mode.
LayoutRectOutsets logical_outsets =
- style.BorderImageOutsets().LineOrientationOutsetsWithFlippedLines(
- style.GetWritingMode());
+ LineOrientationLayoutRectOutsetsWithFlippedLines(
+ style.BorderImageOutsets(), style.GetWritingMode());
if (!IncludeLogicalLeftEdge())
logical_outsets.SetLeft(LayoutUnit());
@@ -1082,8 +1083,9 @@ inline void InlineFlowBox::AddTextBoxVisualOverflow(
if (ShadowList* text_shadow = style.TextShadow()) {
LayoutRectOutsets text_shadow_logical_outsets =
- LayoutRectOutsets(text_shadow->RectOutsetsIncludingOriginal())
- .LineOrientationOutsets(style.GetWritingMode());
+ LineOrientationLayoutRectOutsets(
+ LayoutRectOutsets(text_shadow->RectOutsetsIncludingOriginal()),
+ style.GetWritingMode());
text_shadow_logical_outsets.ClampNegativeToZero();
visual_rect_outsets += text_shadow_logical_outsets;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/line/line_orientation_utils.cc b/chromium/third_party/blink/renderer/core/layout/line/line_orientation_utils.cc
new file mode 100644
index 00000000000..555a4a95e78
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/line/line_orientation_utils.cc
@@ -0,0 +1,31 @@
+// 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/line/line_orientation_utils.h"
+
+namespace blink {
+
+LayoutRectOutsets LineOrientationLayoutRectOutsets(
+ const LayoutRectOutsets& outsets,
+ WritingMode writing_mode) {
+ if (!IsHorizontalWritingMode(writing_mode)) {
+ return LayoutRectOutsets(outsets.Left(), outsets.Bottom(), outsets.Right(),
+ outsets.Top());
+ }
+ return outsets;
+}
+
+LayoutRectOutsets LineOrientationLayoutRectOutsetsWithFlippedLines(
+ const LayoutRectOutsets& original,
+ WritingMode writing_mode) {
+ LayoutRectOutsets outsets =
+ LineOrientationLayoutRectOutsets(original, writing_mode);
+ if (IsFlippedLinesWritingMode(writing_mode)) {
+ return LayoutRectOutsets(outsets.Bottom(), outsets.Right(), outsets.Top(),
+ outsets.Left());
+ }
+ return outsets;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/line/line_orientation_utils.h b/chromium/third_party/blink/renderer/core/layout/line/line_orientation_utils.h
new file mode 100644
index 00000000000..0cc963d3e96
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/line/line_orientation_utils.h
@@ -0,0 +1,30 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LINE_LINE_ORIENTATION_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LINE_LINE_ORIENTATION_UTILS_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/geometry/layout_rect_outsets.h"
+#include "third_party/blink/renderer/platform/text/writing_mode.h"
+
+namespace blink {
+
+// Produces a new LayoutRectOutsets in line orientation
+// (https://www.w3.org/TR/css-writing-modes-3/#line-orientation), whose
+// - |top| is the logical 'over',
+// - |right| is the logical 'line right',
+// - |bottom| is the logical 'under',
+// - |left| is the logical 'line left'.
+CORE_EXPORT LayoutRectOutsets
+LineOrientationLayoutRectOutsets(const LayoutRectOutsets&, WritingMode);
+
+// The same as |logicalOutsets|, but also adjusting for flipped lines.
+CORE_EXPORT LayoutRectOutsets
+LineOrientationLayoutRectOutsetsWithFlippedLines(const LayoutRectOutsets&,
+ WritingMode);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_LINE_LINE_ORIENTATION_UTILS_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/line/line_orientation_utils_test.cc b/chromium/third_party/blink/renderer/core/layout/line/line_orientation_utils_test.cc
new file mode 100644
index 00000000000..35b3376c366
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/line/line_orientation_utils_test.cc
@@ -0,0 +1,44 @@
+// Copyright 2015 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/line/line_orientation_utils.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+namespace {
+
+TEST(LineOrientationUtilsTest, LineOrientationLayoutRectOutsets_Horizontal) {
+ LayoutRectOutsets outsets(1, 2, 3, 4);
+ EXPECT_EQ(
+ LayoutRectOutsets(1, 2, 3, 4),
+ LineOrientationLayoutRectOutsets(outsets, WritingMode::kHorizontalTb));
+}
+
+TEST(LineOrientationUtilsTest, LineOrientationLayoutRectOutsets_Vertical) {
+ LayoutRectOutsets outsets(1, 2, 3, 4);
+ EXPECT_EQ(
+ LayoutRectOutsets(4, 3, 2, 1),
+ LineOrientationLayoutRectOutsets(outsets, WritingMode::kVerticalLr));
+ EXPECT_EQ(
+ LayoutRectOutsets(4, 3, 2, 1),
+ LineOrientationLayoutRectOutsets(outsets, WritingMode::kVerticalRl));
+}
+
+TEST(LineOrientationUtilsTest,
+ LineOrientationLayoutRectOutsetsWithFlippedLines) {
+ LayoutRectOutsets outsets(1, 2, 3, 4);
+ EXPECT_EQ(LayoutRectOutsets(1, 2, 3, 4),
+ LineOrientationLayoutRectOutsetsWithFlippedLines(
+ outsets, WritingMode::kHorizontalTb));
+ EXPECT_EQ(LayoutRectOutsets(2, 3, 4, 1),
+ LineOrientationLayoutRectOutsetsWithFlippedLines(
+ outsets, WritingMode::kVerticalLr));
+ EXPECT_EQ(LayoutRectOutsets(4, 3, 2, 1),
+ LineOrientationLayoutRectOutsetsWithFlippedLines(
+ outsets, WritingMode::kVerticalRl));
+}
+
+} // namespace
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/line/root_inline_box.cc b/chromium/third_party/blink/renderer/core/layout/line/root_inline_box.cc
index e2b2b8eae7d..8cb5e52f5be 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/root_inline_box.cc
+++ b/chromium/third_party/blink/renderer/core/layout/line/root_inline_box.cc
@@ -768,31 +768,26 @@ bool RootInlineBox::IncludeLeadingForBox(InlineBox* box) const {
(box->GetLineLayoutItem().IsText() && !box->IsText()));
}
-Node* RootInlineBox::GetLogicalStartBoxWithNode(InlineBox*& start_box) const {
+const InlineBox* RootInlineBox::GetLogicalStartNonPseudoBox() const {
Vector<InlineBox*> leaf_boxes_in_logical_order;
CollectLeafBoxesInLogicalOrder(leaf_boxes_in_logical_order);
for (size_t i = 0; i < leaf_boxes_in_logical_order.size(); ++i) {
- if (leaf_boxes_in_logical_order[i]->GetLineLayoutItem().NonPseudoNode()) {
- start_box = leaf_boxes_in_logical_order[i];
- return start_box->GetLineLayoutItem().NonPseudoNode();
- }
+ if (leaf_boxes_in_logical_order[i]->GetLineLayoutItem().NonPseudoNode())
+ return leaf_boxes_in_logical_order[i];
}
- start_box = nullptr;
return nullptr;
}
-Node* RootInlineBox::GetLogicalEndBoxWithNode(InlineBox*& end_box) const {
+const InlineBox* RootInlineBox::GetLogicalEndNonPseudoBox() const {
Vector<InlineBox*> leaf_boxes_in_logical_order;
CollectLeafBoxesInLogicalOrder(leaf_boxes_in_logical_order);
for (size_t i = leaf_boxes_in_logical_order.size(); i > 0; --i) {
if (leaf_boxes_in_logical_order[i - 1]
->GetLineLayoutItem()
.NonPseudoNode()) {
- end_box = leaf_boxes_in_logical_order[i - 1];
- return end_box->GetLineLayoutItem().NonPseudoNode();
+ return leaf_boxes_in_logical_order[i - 1];
}
}
- end_box = nullptr;
return nullptr;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/line/root_inline_box.h b/chromium/third_party/blink/renderer/core/layout/line/root_inline_box.h
index 5390deb2792..522cb2f5523 100644
--- a/chromium/third_party/blink/renderer/core/layout/line/root_inline_box.h
+++ b/chromium/third_party/blink/renderer/core/layout/line/root_inline_box.h
@@ -205,8 +205,8 @@ class RootInlineBox : public InlineFlowBox {
return InlineFlowBox::LogicalBottomLayoutOverflow(LineBottom());
}
- Node* GetLogicalStartBoxWithNode(InlineBox*&) const;
- Node* GetLogicalEndBoxWithNode(InlineBox*&) const;
+ const InlineBox* GetLogicalStartNonPseudoBox() const;
+ const InlineBox* GetLogicalEndNonPseudoBox() const;
const char* BoxName() const override;
diff --git a/chromium/third_party/blink/renderer/core/layout/map_coordinates_flags.h b/chromium/third_party/blink/renderer/core/layout/map_coordinates_flags.h
index 311acb42a6b..5a3af39fece 100644
--- a/chromium/third_party/blink/renderer/core/layout/map_coordinates_flags.h
+++ b/chromium/third_party/blink/renderer/core/layout/map_coordinates_flags.h
@@ -29,6 +29,10 @@ enum MapCoordinatesMode {
// Ignore offset adjustments caused by position:sticky calculations when
// walking the chain.
kIgnoreStickyOffset = 1 << 5,
+
+ // Ignore scroll offset from container, i.e. scrolling has no effect on mapped
+ // position.
+ kIgnoreScrollOffset = 1 << 6,
};
typedef unsigned MapCoordinatesFlags;
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 e8889112534..dc608308fa3 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
@@ -6,20 +6,13 @@
#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/testing/core_unit_test_helper.h"
-#include "third_party/blink/renderer/platform/geometry/transform_state.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
+#include "third_party/blink/renderer/platform/transforms/transform_state.h"
namespace blink {
-typedef bool TestParamRootLayerScrolling;
-class MapCoordinatesTest
- : public testing::WithParamInterface<TestParamRootLayerScrolling>,
- private ScopedRootLayerScrollingForTest,
- public RenderingTest {
+class MapCoordinatesTest : public RenderingTest {
public:
- MapCoordinatesTest()
- : ScopedRootLayerScrollingForTest(GetParam()),
- RenderingTest(SingleChildLocalFrameClient::Create()) {}
+ MapCoordinatesTest() : RenderingTest(SingleChildLocalFrameClient::Create()) {}
FloatPoint MapLocalToAncestor(const LayoutObject*,
const LayoutBoxModelObject* ancestor,
FloatPoint,
@@ -113,9 +106,7 @@ FloatQuad MapCoordinatesTest::MapAncestorToLocal(
return transform_state.LastPlanarQuad();
}
-INSTANTIATE_TEST_CASE_P(All, MapCoordinatesTest, testing::Bool());
-
-TEST_P(MapCoordinatesTest, SimpleText) {
+TEST_F(MapCoordinatesTest, SimpleText) {
SetBodyInnerHTML("<div id='container'><br>text</div>");
LayoutBox* container = ToLayoutBox(GetLayoutObjectByElementId("container"));
@@ -128,7 +119,7 @@ TEST_P(MapCoordinatesTest, SimpleText) {
EXPECT_EQ(FloatPoint(10, 30), mapped_point);
}
-TEST_P(MapCoordinatesTest, SimpleInline) {
+TEST_F(MapCoordinatesTest, SimpleInline) {
SetBodyInnerHTML("<div><span id='target'>text</span></div>");
LayoutObject* target = GetLayoutObjectByElementId("target");
@@ -140,7 +131,7 @@ TEST_P(MapCoordinatesTest, SimpleInline) {
EXPECT_EQ(FloatPoint(10, 10), mapped_point);
}
-TEST_P(MapCoordinatesTest, SimpleBlock) {
+TEST_F(MapCoordinatesTest, SimpleBlock) {
SetBodyInnerHTML(R"HTML(
<div style='margin:666px; border:8px solid; padding:7px;'>
<div id='target' style='margin:10px; border:666px;
@@ -157,7 +148,7 @@ TEST_P(MapCoordinatesTest, SimpleBlock) {
EXPECT_EQ(FloatPoint(100, 100), mapped_point);
}
-TEST_P(MapCoordinatesTest, OverflowClip) {
+TEST_F(MapCoordinatesTest, OverflowClip) {
SetBodyInnerHTML(R"HTML(
<div id='overflow' style='height: 100px; width: 100px; border:8px
solid; padding:7px; overflow:scroll'>
@@ -179,7 +170,7 @@ TEST_P(MapCoordinatesTest, OverflowClip) {
EXPECT_EQ(FloatPoint(100, 100), mapped_point);
}
-TEST_P(MapCoordinatesTest, TextInRelPosInline) {
+TEST_F(MapCoordinatesTest, TextInRelPosInline) {
SetBodyInnerHTML(
"<div><span style='position:relative; left:7px; top:4px;'><br "
"id='sibling'>text</span></div>");
@@ -195,7 +186,7 @@ TEST_P(MapCoordinatesTest, TextInRelPosInline) {
EXPECT_EQ(FloatPoint(10, 30), mapped_point);
}
-TEST_P(MapCoordinatesTest, RelposInline) {
+TEST_F(MapCoordinatesTest, RelposInline) {
SetBodyInnerHTML(
"<span id='target' style='position:relative; left:50px; "
"top:100px;'>text</span>");
@@ -209,7 +200,7 @@ TEST_P(MapCoordinatesTest, RelposInline) {
EXPECT_EQ(FloatPoint(10, 10), mapped_point);
}
-TEST_P(MapCoordinatesTest, RelposInlineInRelposInline) {
+TEST_F(MapCoordinatesTest, RelposInlineInRelposInline) {
SetBodyInnerHTML(R"HTML(
<div style='padding-left:10px;'>
<span style='position:relative; left:5px; top:6px;'>
@@ -243,7 +234,7 @@ TEST_P(MapCoordinatesTest, RelposInlineInRelposInline) {
EXPECT_EQ(FloatPoint(20, 10), mapped_point);
}
-TEST_P(MapCoordinatesTest, RelPosBlock) {
+TEST_F(MapCoordinatesTest, RelPosBlock) {
SetBodyInnerHTML(R"HTML(
<div id='container' style='margin:666px; border:8px solid;
padding:7px;'>
@@ -278,7 +269,7 @@ TEST_P(MapCoordinatesTest, RelPosBlock) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, AbsPos) {
+TEST_F(MapCoordinatesTest, AbsPos) {
SetBodyInnerHTML(R"HTML(
<div id='container' style='position:relative; margin:666px; border:8px
solid; padding:7px;'>
@@ -315,7 +306,7 @@ TEST_P(MapCoordinatesTest, AbsPos) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, AbsPosAuto) {
+TEST_F(MapCoordinatesTest, AbsPosAuto) {
SetBodyInnerHTML(R"HTML(
<div id='container' style='position:absolute; margin:666px; border:8px
solid; padding:7px;'>
@@ -352,7 +343,7 @@ TEST_P(MapCoordinatesTest, AbsPosAuto) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, FixedPos) {
+TEST_F(MapCoordinatesTest, FixedPos) {
// Assuming BODY margin of 8px.
SetBodyInnerHTML(R"HTML(
<div id='container' style='position:absolute; margin:4px; border:5px
@@ -411,7 +402,7 @@ TEST_P(MapCoordinatesTest, FixedPos) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, FixedPosAuto) {
+TEST_F(MapCoordinatesTest, FixedPosAuto) {
// Assuming BODY margin of 8px.
SetBodyInnerHTML(R"HTML(
<div id='container' style='position:absolute; margin:3px; border:8px
@@ -472,7 +463,7 @@ TEST_P(MapCoordinatesTest, FixedPosAuto) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, FixedPosInFixedPos) {
+TEST_F(MapCoordinatesTest, FixedPosInFixedPos) {
// Assuming BODY margin of 8px.
SetBodyInnerHTML(R"HTML(
<div id='container' style='position:absolute; margin:4px; border:5px
@@ -542,7 +533,7 @@ TEST_P(MapCoordinatesTest, FixedPosInFixedPos) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, FixedPosInFixedPosScrollView) {
+TEST_F(MapCoordinatesTest, FixedPosInFixedPosScrollView) {
SetBodyInnerHTML(R"HTML(
<div style='height: 4000px'></div>
<div id='container' style='position:fixed; top: 100px; left: 100px'>
@@ -578,7 +569,7 @@ TEST_P(MapCoordinatesTest, FixedPosInFixedPosScrollView) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, FixedPosInAbsolutePosScrollView) {
+TEST_F(MapCoordinatesTest, FixedPosInAbsolutePosScrollView) {
SetBodyInnerHTML(R"HTML(
<div style='height: 4000px'></div>
<div id='container' style='position:absolute; top: 100px; left: 100px'>
@@ -614,7 +605,7 @@ TEST_P(MapCoordinatesTest, FixedPosInAbsolutePosScrollView) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, FixedPosInTransform) {
+TEST_F(MapCoordinatesTest, FixedPosInTransform) {
SetBodyInnerHTML(R"HTML(
<style>#container { transform: translateY(100px); position: absolute;
left: 0; top: 100px; }
@@ -656,7 +647,7 @@ TEST_P(MapCoordinatesTest, FixedPosInTransform) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, FixedPosInContainPaint) {
+TEST_F(MapCoordinatesTest, FixedPosInContainPaint) {
SetBodyInnerHTML(R"HTML(
<style>#container { contain: paint; position: absolute; left: 0; top:
100px; }
@@ -699,7 +690,7 @@ TEST_P(MapCoordinatesTest, FixedPosInContainPaint) {
}
// TODO(chrishtr): add more multi-frame tests.
-TEST_P(MapCoordinatesTest, FixedPosInIFrameWhenMainFrameScrolled) {
+TEST_F(MapCoordinatesTest, FixedPosInIFrameWhenMainFrameScrolled) {
GetDocument().SetBaseURLOverride(KURL("http://test.com"));
SetBodyInnerHTML(R"HTML(
<style>body { margin: 0; }</style>
@@ -729,7 +720,7 @@ TEST_P(MapCoordinatesTest, FixedPosInIFrameWhenMainFrameScrolled) {
EXPECT_EQ(FloatPoint(10, -7930), AdjustForFrameScroll(mapped_point));
}
-TEST_P(MapCoordinatesTest, IFrameTransformed) {
+TEST_F(MapCoordinatesTest, IFrameTransformed) {
GetDocument().SetBaseURLOverride(KURL("http://test.com"));
SetBodyInnerHTML(R"HTML(
<style>body { margin: 0; }</style>
@@ -762,7 +753,7 @@ TEST_P(MapCoordinatesTest, IFrameTransformed) {
EXPECT_EQ(FloatPoint(225, 1225), mapped_point);
}
-TEST_P(MapCoordinatesTest, FixedPosInScrolledIFrameWithTransform) {
+TEST_F(MapCoordinatesTest, FixedPosInScrolledIFrameWithTransform) {
GetDocument().SetBaseURLOverride(KURL("http://test.com"));
SetBodyInnerHTML(R"HTML(
<style>* { margin: 0; }</style>
@@ -792,7 +783,7 @@ TEST_P(MapCoordinatesTest, FixedPosInScrolledIFrameWithTransform) {
EXPECT_EQ(FloatPoint(0, 0), mapped_point);
}
-TEST_P(MapCoordinatesTest, MulticolWithText) {
+TEST_F(MapCoordinatesTest, MulticolWithText) {
SetBodyInnerHTML(R"HTML(
<div id='multicol' style='columns:2; column-gap:20px; width:400px;
line-height:50px; padding:5px; orphans:1; widows:1;'>
@@ -819,7 +810,7 @@ TEST_P(MapCoordinatesTest, MulticolWithText) {
EXPECT_EQ(FloatPoint(10, 70), mapped_point);
}
-TEST_P(MapCoordinatesTest, MulticolWithInline) {
+TEST_F(MapCoordinatesTest, MulticolWithInline) {
SetBodyInnerHTML(R"HTML(
<div id='multicol' style='columns:2; column-gap:20px; width:400px;
line-height:50px; padding:5px; orphans:1; widows:1;'>
@@ -844,7 +835,7 @@ TEST_P(MapCoordinatesTest, MulticolWithInline) {
EXPECT_EQ(FloatPoint(10, 70), mapped_point);
}
-TEST_P(MapCoordinatesTest, MulticolWithBlock) {
+TEST_F(MapCoordinatesTest, MulticolWithBlock) {
SetBodyInnerHTML(R"HTML(
<div id='container' style='-webkit-columns:3; -webkit-column-gap:0;
column-fill:auto; width:300px; height:100px; border:8px solid;
@@ -879,7 +870,7 @@ TEST_P(MapCoordinatesTest, MulticolWithBlock) {
EXPECT_EQ(FloatPoint(10, 120), mapped_point);
}
-TEST_P(MapCoordinatesTest, MulticolWithBlockAbove) {
+TEST_F(MapCoordinatesTest, MulticolWithBlockAbove) {
SetBodyInnerHTML(R"HTML(
<div id='container' style='columns:3; column-gap:0;
column-fill:auto; width:300px; height:200px;'>
@@ -910,7 +901,7 @@ TEST_P(MapCoordinatesTest, MulticolWithBlockAbove) {
EXPECT_EQ(FloatPoint(0, -50), mapped_point);
}
-TEST_P(MapCoordinatesTest, NestedMulticolWithBlock) {
+TEST_F(MapCoordinatesTest, NestedMulticolWithBlock) {
SetBodyInnerHTML(R"HTML(
<div id='outerMulticol' style='columns:2; column-gap:0;
column-fill:auto; width:560px; height:215px; border:8px solid;
@@ -968,7 +959,7 @@ TEST_P(MapCoordinatesTest, NestedMulticolWithBlock) {
EXPECT_EQ(FloatPoint(140, 315), mapped_point);
}
-TEST_P(MapCoordinatesTest, MulticolWithAbsPosInRelPos) {
+TEST_F(MapCoordinatesTest, MulticolWithAbsPosInRelPos) {
SetBodyInnerHTML(R"HTML(
<div id='multicol' style='-webkit-columns:3; -webkit-column-gap:0;
column-fill:auto; width:300px; height:100px; border:8px solid;
@@ -1010,7 +1001,7 @@ TEST_P(MapCoordinatesTest, MulticolWithAbsPosInRelPos) {
EXPECT_EQ(FloatPoint(29, 139), mapped_point);
}
-TEST_P(MapCoordinatesTest, MulticolWithAbsPosNotContained) {
+TEST_F(MapCoordinatesTest, MulticolWithAbsPosNotContained) {
SetBodyInnerHTML(R"HTML(
<div id='container' style='position:relative; margin:666px; border:7px
solid; padding:3px;'>
@@ -1058,7 +1049,7 @@ TEST_P(MapCoordinatesTest, MulticolWithAbsPosNotContained) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, MulticolRtl) {
+TEST_F(MapCoordinatesTest, MulticolRtl) {
SetBodyInnerHTML(R"HTML(
<div id='container' style='columns:3; column-gap:0; column-fill:auto;
width:300px; height:200px; direction:rtl;'>
@@ -1090,7 +1081,7 @@ TEST_P(MapCoordinatesTest, MulticolRtl) {
EXPECT_EQ(FloatPoint(0, 200), mapped_point);
}
-TEST_P(MapCoordinatesTest, MulticolWithLargeBorder) {
+TEST_F(MapCoordinatesTest, MulticolWithLargeBorder) {
SetBodyInnerHTML(R"HTML(
<div id='container' style='columns:3; column-gap:0; column-fill:auto;
width:300px; height:200px; border:200px solid;'>
@@ -1123,7 +1114,7 @@ TEST_P(MapCoordinatesTest, MulticolWithLargeBorder) {
EXPECT_EQ(FloatPoint(0, 200), mapped_point);
}
-TEST_P(MapCoordinatesTest, FlippedBlocksWritingModeWithText) {
+TEST_F(MapCoordinatesTest, FlippedBlocksWritingModeWithText) {
SetBodyInnerHTML(R"HTML(
<div style='-webkit-writing-mode:vertical-rl;'>
<div style='width:13px;'></div>
@@ -1169,7 +1160,7 @@ TEST_P(MapCoordinatesTest, FlippedBlocksWritingModeWithText) {
EXPECT_EQ(FloatPoint(75, 10), mapped_point);
}
-TEST_P(MapCoordinatesTest, FlippedBlocksWritingModeWithInline) {
+TEST_F(MapCoordinatesTest, FlippedBlocksWritingModeWithInline) {
SetBodyInnerHTML(R"HTML(
<div style='-webkit-writing-mode:vertical-rl;'>
<div style='width:13px;'></div>
@@ -1235,7 +1226,7 @@ TEST_P(MapCoordinatesTest, FlippedBlocksWritingModeWithInline) {
EXPECT_EQ(FloatPoint(75, 10), mapped_point);
}
-TEST_P(MapCoordinatesTest, FlippedBlocksWritingModeWithBlock) {
+TEST_F(MapCoordinatesTest, FlippedBlocksWritingModeWithBlock) {
SetBodyInnerHTML(R"HTML(
<div id='container' style='-webkit-writing-mode:vertical-rl; border:8px
solid; padding:7px; width:200px; height:200px;'>
@@ -1268,7 +1259,7 @@ TEST_P(MapCoordinatesTest, FlippedBlocksWritingModeWithBlock) {
EXPECT_EQ(FloatPoint(7, 7), mapped_point);
}
-TEST_P(MapCoordinatesTest, Table) {
+TEST_F(MapCoordinatesTest, Table) {
SetBodyInnerHTML(R"HTML(
<style>td { padding: 2px; }</style>
<div id='container' style='border:3px solid;'>
@@ -1368,7 +1359,7 @@ static bool FloatQuadsAlmostEqual(const FloatQuad& expected,
} \
} while (false)
-TEST_P(MapCoordinatesTest, Transforms) {
+TEST_F(MapCoordinatesTest, Transforms) {
SetBodyInnerHTML(R"HTML(
<div id='container'>
<div id='outerTransform' style='transform:rotate(45deg);
@@ -1436,7 +1427,7 @@ TEST_P(MapCoordinatesTest, Transforms) {
EXPECT_FLOAT_QUAD_EQ(initial_quad, mapped_quad);
}
-TEST_P(MapCoordinatesTest, SVGShape) {
+TEST_F(MapCoordinatesTest, SVGShape) {
SetBodyInnerHTML(R"HTML(
<svg id='container'>
<g transform='translate(100 200)'>
@@ -1454,7 +1445,7 @@ TEST_P(MapCoordinatesTest, SVGShape) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, SVGShapeScale) {
+TEST_F(MapCoordinatesTest, SVGShapeScale) {
SetBodyInnerHTML(R"HTML(
<svg id='container'>
<g transform='scale(2) translate(50 40)'>
@@ -1473,7 +1464,7 @@ TEST_P(MapCoordinatesTest, SVGShapeScale) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, SVGShapeWithViewBoxWithoutScale) {
+TEST_F(MapCoordinatesTest, SVGShapeWithViewBoxWithoutScale) {
SetBodyInnerHTML(R"HTML(
<svg id='container' viewBox='0 0 200 200' width='400' height='200'>
<g transform='translate(100 50)'>
@@ -1491,7 +1482,7 @@ TEST_P(MapCoordinatesTest, SVGShapeWithViewBoxWithoutScale) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, SVGShapeWithViewBoxWithScale) {
+TEST_F(MapCoordinatesTest, SVGShapeWithViewBoxWithScale) {
SetBodyInnerHTML(R"HTML(
<svg id='container' viewBox='0 0 100 100' width='400' height='200'>
<g transform='translate(50 50)'>
@@ -1509,7 +1500,7 @@ TEST_P(MapCoordinatesTest, SVGShapeWithViewBoxWithScale) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, SVGShapeWithViewBoxWithNonZeroOffset) {
+TEST_F(MapCoordinatesTest, SVGShapeWithViewBoxWithNonZeroOffset) {
SetBodyInnerHTML(R"HTML(
<svg id='container' viewBox='100 100 200 200' width='400' height='200'>
<g transform='translate(100 50)'>
@@ -1528,7 +1519,7 @@ TEST_P(MapCoordinatesTest, SVGShapeWithViewBoxWithNonZeroOffset) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, SVGShapeWithViewBoxWithNonZeroOffsetAndScale) {
+TEST_F(MapCoordinatesTest, SVGShapeWithViewBoxWithNonZeroOffsetAndScale) {
SetBodyInnerHTML(R"HTML(
<svg id='container' viewBox='100 100 100 100' width='400' height='200'>
<g transform='translate(50 50)'>
@@ -1547,7 +1538,7 @@ TEST_P(MapCoordinatesTest, SVGShapeWithViewBoxWithNonZeroOffsetAndScale) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, SVGForeignObject) {
+TEST_F(MapCoordinatesTest, SVGForeignObject) {
SetBodyInnerHTML(R"HTML(
<svg id='container' viewBox='0 0 100 100' width='400' height='200'>
<g transform='translate(50 50)'>
@@ -1583,7 +1574,7 @@ TEST_P(MapCoordinatesTest, SVGForeignObject) {
EXPECT_EQ(FloatPoint(), mapped_point);
}
-TEST_P(MapCoordinatesTest, LocalToAbsoluteTransform) {
+TEST_F(MapCoordinatesTest, LocalToAbsoluteTransform) {
SetBodyInnerHTML(R"HTML(
<div id='container' style='position: absolute; left: 0; top: 0;'>
<div id='scale' style='transform: scale(2.0); transform-origin: left
@@ -1607,7 +1598,7 @@ TEST_P(MapCoordinatesTest, LocalToAbsoluteTransform) {
EXPECT_EQ(40.0, child_matrix.ProjectPoint(FloatPoint(10.0, 20.0)).Y());
}
-TEST_P(MapCoordinatesTest, LocalToAncestorTransform) {
+TEST_F(MapCoordinatesTest, LocalToAncestorTransform) {
SetBodyInnerHTML(R"HTML(
<div id='container'>
<div id='rotate1' style='transform: rotate(45deg); transform-origin:
@@ -1652,7 +1643,7 @@ TEST_P(MapCoordinatesTest, LocalToAncestorTransform) {
LayoutUnit::Epsilon());
}
-TEST_P(MapCoordinatesTest, LocalToAbsoluteTransformFlattens) {
+TEST_F(MapCoordinatesTest, LocalToAbsoluteTransformFlattens) {
GetDocument().GetFrame()->GetSettings()->SetAcceleratedCompositingEnabled(
true);
SetBodyInnerHTML(R"HTML(
@@ -1701,4 +1692,150 @@ TEST_P(MapCoordinatesTest, LocalToAbsoluteTransformFlattens) {
LayoutUnit::Epsilon());
}
+// This test verifies that the mapped location of a div within a scroller
+// remains the same after scroll when ignoring scroll offset.
+TEST_F(MapCoordinatesTest, IgnoreScrollOffset) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body { margin: 0; }
+ .scroller { overflow: scroll; height: 100px; width: 100px;
+ top: 100px; position: absolute; }
+ .box { width: 10px; height: 10px; top: 10px; position: absolute; }
+ .spacer { height: 2000px; }
+ </style>
+ <div class='scroller' id='scroller'>
+ <div class='box' id='box'></div>
+ <div class='spacer'></div>
+ </div>
+ )HTML");
+
+ LayoutBox* scroller = ToLayoutBox(GetLayoutObjectByElementId("scroller"));
+ LayoutBox* box = ToLayoutBox(GetLayoutObjectByElementId("box"));
+
+ EXPECT_EQ(FloatPoint(0, 10), MapLocalToAncestor(box, scroller, FloatPoint()));
+ EXPECT_EQ(FloatPoint(0, 10), MapLocalToAncestor(box, scroller, FloatPoint(),
+ kIgnoreScrollOffset));
+
+ scroller->ScrollToPosition(FloatPoint(0, 50));
+
+ EXPECT_EQ(FloatPoint(0, -40),
+ MapLocalToAncestor(box, scroller, FloatPoint()));
+ EXPECT_EQ(FloatPoint(0, 10), MapLocalToAncestor(box, scroller, FloatPoint(),
+ kIgnoreScrollOffset));
+}
+
+// This test verifies that the mapped location of an inline div within a
+// scroller remains the same after scroll when ignoring scroll offset.
+TEST_F(MapCoordinatesTest, IgnoreScrollOffsetForInline) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body { margin: 0; }
+ .scroller { overflow: scroll; width: 100px; height: 100px; top: 100px;
+ position: absolute; }
+ .box { width: 10px; height: 10px; top: 10px; position: sticky; }
+ .inline { display: inline; }
+ .spacer { height: 2000px; }
+ </style>
+ <div class='scroller' id='scroller'>
+ <div class='inline box' id='box'></div>
+ <div class='spacer'></div>
+ </div>
+ )HTML");
+
+ LayoutBox* scroller = ToLayoutBox(GetLayoutObjectByElementId("scroller"));
+ LayoutInline* box = ToLayoutInline(GetLayoutObjectByElementId("box"));
+
+ EXPECT_EQ(FloatPoint(0, 10), MapLocalToAncestor(box, scroller, FloatPoint()));
+ EXPECT_EQ(FloatPoint(0, 10), MapLocalToAncestor(box, scroller, FloatPoint(),
+ kIgnoreScrollOffset));
+
+ scroller->ScrollToPosition(FloatPoint(0, 50));
+
+ EXPECT_EQ(FloatPoint(0, 10), MapLocalToAncestor(box, scroller, FloatPoint()));
+ EXPECT_EQ(FloatPoint(0, 60), MapLocalToAncestor(box, scroller, FloatPoint(),
+ kIgnoreScrollOffset));
+}
+
+// This test verifies that ignoring scroll offset works with writing modes.
+TEST_F(MapCoordinatesTest, IgnoreScrollOffsetWithWritingModes) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body { margin: 0; }
+ .scroller { writing-mode: vertical-rl; overflow: scroll; height: 100px;
+ width: 100px; top: 100px; position: absolute; }
+ .box { width: 10px; height: 10px; top: 10px; position: absolute; }
+ .spacer { width: 2000px; height: 2000px; }
+ </style>
+ <div class='scroller' id='scroller'>
+ <div class='box' id='box'></div>
+ <div class='spacer'></div>
+ </div>
+ )HTML");
+
+ LayoutBox* scroller = ToLayoutBox(GetLayoutObjectByElementId("scroller"));
+ LayoutBox* box = ToLayoutBox(GetLayoutObjectByElementId("box"));
+
+ EXPECT_EQ(FloatPoint(90, 10),
+ MapLocalToAncestor(box, scroller, FloatPoint()));
+ EXPECT_EQ(
+ FloatPoint(1990, 10),
+ MapLocalToAncestor(box, scroller, FloatPoint(), kIgnoreScrollOffset));
+
+ scroller->ScrollToPosition(FloatPoint(0, 50));
+
+ EXPECT_EQ(FloatPoint(1990, -40),
+ MapLocalToAncestor(box, scroller, FloatPoint()));
+ EXPECT_EQ(
+ FloatPoint(1990, 10),
+ MapLocalToAncestor(box, scroller, FloatPoint(), kIgnoreScrollOffset));
+
+ scroller->ScrollToPosition(FloatPoint(1900, 50));
+
+ EXPECT_EQ(FloatPoint(90, -40),
+ MapLocalToAncestor(box, scroller, FloatPoint()));
+ EXPECT_EQ(
+ FloatPoint(1990, 10),
+ MapLocalToAncestor(box, scroller, FloatPoint(), kIgnoreScrollOffset));
+}
+
+// This test verifies that ignoring scroll offset works with writing modes and
+// non-overlay scrollbar.
+TEST_F(MapCoordinatesTest,
+ IgnoreScrollOffsetWithWritingModesAndNonOverlayScrollbar) {
+ ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body { margin: 0; }
+ .scroller { writing-mode: vertical-rl; overflow: scroll; height: 100px;
+ width: 100px; top: 100px; position: absolute; }
+ .box { width: 10px; height: 10px; top: 10px; position: absolute; }
+ .spacer { width: 2000px; height: 2000px; }
+ </style>
+ <div class='scroller' id='scroller'>
+ <div class='box' id='box'></div>
+ <div class='spacer'></div>
+ </div>
+ )HTML");
+
+ LayoutBox* scroller = ToLayoutBox(GetLayoutObjectByElementId("scroller"));
+ LayoutBox* box = ToLayoutBox(GetLayoutObjectByElementId("box"));
+
+ // The box is on the left of the scrollbar so the width of the scrollbar
+ // affects the location of the box.
+ EXPECT_EQ(FloatPoint(75, 10),
+ MapLocalToAncestor(box, scroller, FloatPoint()));
+ EXPECT_EQ(
+ FloatPoint(1990, 10),
+ MapLocalToAncestor(box, scroller, FloatPoint(), kIgnoreScrollOffset));
+
+ scroller->ScrollToPosition(FloatPoint(0, 0));
+ // The box is now on the right of the scrollbar therefore there is nothing
+ // between the box and the right border of the content.
+ EXPECT_EQ(FloatPoint(1990, 10),
+ MapLocalToAncestor(box, scroller, FloatPoint()));
+ EXPECT_EQ(
+ FloatPoint(1990, 10),
+ MapLocalToAncestor(box, scroller, FloatPoint(), kIgnoreScrollOffset));
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc b/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc
index 50da8b67790..869820da343 100644
--- a/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc
+++ b/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.cc
@@ -62,6 +62,7 @@ LayoutUnit MultiColumnFragmentainerGroup::LogicalHeightInFlowThreadAt(
}
void MultiColumnFragmentainerGroup::ResetColumnHeight() {
+ actual_column_count_allowance_ = 0;
max_logical_height_ = CalculateMaxColumnHeight();
LayoutMultiColumnFlowThread* flow_thread =
@@ -137,6 +138,24 @@ bool MultiColumnFragmentainerGroup::RecalculateColumnHeight(
// height.
is_logical_height_known_ = true;
+ unsigned column_count = UnclampedActualColumnCount();
+ if (column_count > LayoutMultiColumnFlowThread::ColumnCountClampMax() ||
+ (column_count > LayoutMultiColumnFlowThread::ColumnCountClampMin() &&
+ column_count > column_set_.UsedColumnCount())) {
+ // That's a lot of columns! We have either exceeded the maximum value, or we
+ // have overflowing columns, and the proposed count is within clamping
+ // range. Calculate allowance to make sure we have a legitimate reason for
+ // it, or else clamp it. We have quadratic performance complexity for
+ // painting columns.
+ if (!actual_column_count_allowance_) {
+ const auto* flow_thread = column_set_.MultiColumnFlowThread();
+ unsigned allowance = flow_thread->CalculateActualColumnCountAllowance();
+ DCHECK_GE(allowance, LayoutMultiColumnFlowThread::ColumnCountClampMin());
+ DCHECK_LE(allowance, LayoutMultiColumnFlowThread::ColumnCountClampMax());
+ actual_column_count_allowance_ = allowance;
+ }
+ }
+
if (logical_height_ == old_column_height)
return false; // No change. We're done.
@@ -309,36 +328,9 @@ LayoutRect MultiColumnFragmentainerGroup::CalculateOverflow() const {
}
unsigned MultiColumnFragmentainerGroup::ActualColumnCount() const {
- // We must always return a value of 1 or greater. Column count = 0 is a
- // meaningless situation, and will confuse and cause problems in other parts
- // of the code.
- if (!IsLogicalHeightKnown())
- return 1;
- // Our flow thread portion determines our column count. We have as many
- // columns as needed to fit all the content.
- LayoutUnit flow_thread_portion_height = LogicalHeightInFlowThread();
- if (!flow_thread_portion_height)
- return 1;
-
- LayoutUnit column_height = ColumnLogicalHeight();
- unsigned count = (flow_thread_portion_height / column_height).Floor();
- // flowThreadPortionHeight may be saturated, so detect the remainder manually.
- if (count * column_height < flow_thread_portion_height)
- count++;
-
- static const unsigned kColumnCountClampMin = 10;
- static const unsigned kColumnCountClampMax = 500;
- if (count > kColumnCountClampMin) {
- // To avoid performance problems, limit the maximum number of columns. Try
- // to identify legitimate reasons for creating many columns, and allow many
- // columns in such cases. We currently use a function of column height to
- // determine this (limit the column count to the column height in pixels,
- // but never clamp to less than 10 columns).
- unsigned max_count = column_height.ToInt();
- count = std::min(count, std::max(std::min(max_count, kColumnCountClampMax),
- kColumnCountClampMin));
- }
-
+ unsigned count = UnclampedActualColumnCount();
+ if (actual_column_count_allowance_)
+ count = std::min(count, actual_column_count_allowance_);
DCHECK_GE(count, 1u);
return count;
}
@@ -648,6 +640,28 @@ void MultiColumnFragmentainerGroup::ColumnIntervalForVisualRect(
DCHECK_LE(first_column, last_column);
}
+unsigned MultiColumnFragmentainerGroup::UnclampedActualColumnCount() const {
+ // We must always return a value of 1 or greater. Column count = 0 is a
+ // meaningless situation, and will confuse and cause problems in other parts
+ // of the code.
+ if (!IsLogicalHeightKnown())
+ return 1;
+ // Our flow thread portion determines our column count. We have as many
+ // columns as needed to fit all the content.
+ LayoutUnit flow_thread_portion_height = LogicalHeightInFlowThread();
+ if (!flow_thread_portion_height)
+ return 1;
+
+ LayoutUnit column_height = ColumnLogicalHeight();
+ unsigned count = (flow_thread_portion_height / column_height).Floor();
+ // flowThreadPortionHeight may be saturated, so detect the remainder manually.
+ if (count * column_height < flow_thread_portion_height)
+ count++;
+
+ DCHECK_GE(count, 1u);
+ return count;
+}
+
MultiColumnFragmentainerGroupList::MultiColumnFragmentainerGroupList(
LayoutMultiColumnSet& column_set)
: column_set_(column_set) {
diff --git a/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.h b/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.h
index 3387bc15308..13aedea607f 100644
--- a/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.h
+++ b/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group.h
@@ -193,6 +193,8 @@ class CORE_EXPORT MultiColumnFragmentainerGroup {
// to a column, even if said point is not inside any of the columns.
unsigned ColumnIndexAtVisualPoint(const LayoutPoint& visual_point) const;
+ unsigned UnclampedActualColumnCount() const;
+
const LayoutMultiColumnSet& column_set_;
LayoutUnit logical_top_;
@@ -207,6 +209,8 @@ class CORE_EXPORT MultiColumnFragmentainerGroup {
// Maximum logical height allowed.
LayoutUnit max_logical_height_;
+ unsigned actual_column_count_allowance_ = 0;
+
bool is_logical_height_known_ = false;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group_test.cc b/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group_test.cc
index fd0e4967fc8..1d9420faff2 100644
--- a/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/multi_column_fragmentainer_group_test.cc
@@ -100,9 +100,9 @@ TEST_F(MultiColumnFragmentainerGroupTest,
// The following test tests that we restrict actual column count, to not run
// into unnecessary performance problems. The code that applies this limitation
// is in MultiColumnFragmentainerGroup::ActualColumnCount().
-TEST_F(MultiColumnFragmentainerGroupTest, ShortColumnTallContent) {
+TEST_F(MultiColumnFragmentainerGroupTest, TallEmptyContent) {
SetBodyInnerHTML(R"HTML(
- <div id="multicol" style="columns:3; column-gap:1px; width:101px; height:1px;">
+ <div id="multicol" style="columns:3; column-gap:1px; width:101px; line-height:50px; height:200px;">
<div style="height:1000000px;"></div>
</div>
)HTML");
@@ -115,23 +115,28 @@ TEST_F(MultiColumnFragmentainerGroupTest, ShortColumnTallContent) {
const auto& fragmentainer_group =
ToLayoutMultiColumnSet(column_set)->FirstFragmentainerGroup();
EXPECT_EQ(fragmentainer_group.ActualColumnCount(), 10U);
- EXPECT_EQ(fragmentainer_group.GroupLogicalHeight(), LayoutUnit(1));
+ EXPECT_EQ(fragmentainer_group.GroupLogicalHeight(), LayoutUnit(200));
auto overflow = ToLayoutBox(multicol)->LayoutOverflowRect();
EXPECT_EQ(ToLayoutBox(multicol)->LogicalWidth(), LayoutUnit(101));
- EXPECT_EQ(ToLayoutBox(multicol)->LogicalHeight(), LayoutUnit(1));
+ EXPECT_EQ(ToLayoutBox(multicol)->LogicalHeight(), LayoutUnit(200));
EXPECT_EQ(overflow.Width(), LayoutUnit(339));
- EXPECT_EQ(overflow.Height(), LayoutUnit(999991));
+ EXPECT_EQ(overflow.Height(), LayoutUnit(998200));
}
-// The following test tests that we restrict actual column count, to not run
-// into unnecessary performance problems. The code that applies this limitation
-// is in MultiColumnFragmentainerGroup::ActualColumnCount().
-TEST_F(MultiColumnFragmentainerGroupTest, MediumTallColumnTallContent) {
- SetBodyInnerHTML(R"HTML(
- <div id="multicol" style="columns:3; column-gap:1px; width:101px; height:100px;">
- <div style="height:1000000px;"></div>
- </div>
- )HTML");
+// The following test tests that we DON'T restrict actual column count, when
+// there's a legitimate reason to use many columns. The code that checks the
+// allowance and potentially applies this limitation is in
+// MultiColumnFragmentainerGroup::ActualColumnCount().
+TEST_F(MultiColumnFragmentainerGroupTest, LotsOfContent) {
+ StringBuilder builder;
+ builder.Append(
+ "<div id='multicol' style='columns:3; column-gap:1px; width:101px; "
+ "line-height:50px; orphans:1; widows:1; height:60px;'>");
+ for (int i = 0; i < 100; i++)
+ builder.Append("line<br>");
+ builder.Append("</div>");
+ String html;
+ SetBodyInnerHTML(builder.ToString());
const auto* multicol = GetLayoutObjectByElementId("multicol");
ASSERT_TRUE(multicol);
ASSERT_TRUE(multicol->IsLayoutBlockFlow());
@@ -141,23 +146,28 @@ TEST_F(MultiColumnFragmentainerGroupTest, MediumTallColumnTallContent) {
const auto& fragmentainer_group =
ToLayoutMultiColumnSet(column_set)->FirstFragmentainerGroup();
EXPECT_EQ(fragmentainer_group.ActualColumnCount(), 100U);
- EXPECT_EQ(fragmentainer_group.GroupLogicalHeight(), LayoutUnit(100));
+ EXPECT_EQ(fragmentainer_group.GroupLogicalHeight(), LayoutUnit(60));
auto overflow = ToLayoutBox(multicol)->LayoutOverflowRect();
EXPECT_EQ(ToLayoutBox(multicol)->LogicalWidth(), LayoutUnit(101));
- EXPECT_EQ(ToLayoutBox(multicol)->LogicalHeight(), LayoutUnit(100));
+ EXPECT_EQ(ToLayoutBox(multicol)->LogicalHeight(), LayoutUnit(60));
EXPECT_EQ(overflow.Width(), LayoutUnit(3399));
- EXPECT_EQ(overflow.Height(), LayoutUnit(990100));
+ EXPECT_EQ(overflow.Height(), LayoutUnit(60));
}
-// The following test tests that we restrict actual column count, to not run
-// into unnecessary performance problems. The code that applies this limitation
-// is in MultiColumnFragmentainerGroup::ActualColumnCount().
-TEST_F(MultiColumnFragmentainerGroupTest, TallColumnTallContent) {
- SetBodyInnerHTML(R"HTML(
- <div id="multicol" style="columns:3; column-gap:1px; width:101px; height:1000px;">
- <div style="height:1000000px;"></div>
- </div>
- )HTML");
+// The following test tests that we DON'T restrict actual column count, when
+// there's a legitimate reason to use many columns. The code that checks the
+// allowance and potentially applies this limitation is in
+// MultiColumnFragmentainerGroup::ActualColumnCount().
+TEST_F(MultiColumnFragmentainerGroupTest, LotsOfNestedBlocksWithText) {
+ StringBuilder builder;
+ builder.Append(
+ "<div id='multicol' style='columns:3; column-gap:1px; width:101px; "
+ "line-height:50px; height:200px;'>");
+ for (int i = 0; i < 1000; i++)
+ builder.Append("<div><div><div>line</div></div></div>");
+ builder.Append("</div>");
+ String html;
+ SetBodyInnerHTML(builder.ToString());
const auto* multicol = GetLayoutObjectByElementId("multicol");
ASSERT_TRUE(multicol);
ASSERT_TRUE(multicol->IsLayoutBlockFlow());
@@ -166,13 +176,44 @@ TEST_F(MultiColumnFragmentainerGroupTest, TallColumnTallContent) {
ASSERT_TRUE(column_set->IsLayoutMultiColumnSet());
const auto& fragmentainer_group =
ToLayoutMultiColumnSet(column_set)->FirstFragmentainerGroup();
- EXPECT_EQ(fragmentainer_group.ActualColumnCount(), 500U);
- EXPECT_EQ(fragmentainer_group.GroupLogicalHeight(), LayoutUnit(1000));
+ EXPECT_EQ(fragmentainer_group.ActualColumnCount(), 250U);
+ EXPECT_EQ(fragmentainer_group.GroupLogicalHeight(), LayoutUnit(200));
auto overflow = ToLayoutBox(multicol)->LayoutOverflowRect();
EXPECT_EQ(ToLayoutBox(multicol)->LogicalWidth(), LayoutUnit(101));
- EXPECT_EQ(ToLayoutBox(multicol)->LogicalHeight(), LayoutUnit(1000));
- EXPECT_EQ(overflow.Width(), LayoutUnit(16999));
- EXPECT_EQ(overflow.Height(), LayoutUnit(501000));
+ EXPECT_EQ(ToLayoutBox(multicol)->LogicalHeight(), LayoutUnit(200));
+ EXPECT_EQ(overflow.Width(), LayoutUnit(8499));
+ EXPECT_EQ(overflow.Height(), LayoutUnit(200));
+}
+
+// The following test tests that we DON'T restrict actual column count, when
+// there's a legitimate reason to use many columns. The code that checks the
+// allowance and potentially applies this limitation is in
+// MultiColumnFragmentainerGroup::ActualColumnCount().
+TEST_F(MultiColumnFragmentainerGroupTest, NestedBlocksWithLotsOfContent) {
+ StringBuilder builder;
+ builder.Append(
+ "<div id='multicol' style='columns:3; column-gap:1px; width:101px; "
+ "line-height:50px; orphans:1; widows:1; height:60px;'><div><div><div>");
+ for (int i = 0; i < 100; i++)
+ builder.Append("line<br>");
+ builder.Append("</div></div></div></div>");
+ String html;
+ SetBodyInnerHTML(builder.ToString());
+ const auto* multicol = GetLayoutObjectByElementId("multicol");
+ ASSERT_TRUE(multicol);
+ ASSERT_TRUE(multicol->IsLayoutBlockFlow());
+ const auto* column_set = multicol->SlowLastChild();
+ ASSERT_TRUE(column_set);
+ ASSERT_TRUE(column_set->IsLayoutMultiColumnSet());
+ const auto& fragmentainer_group =
+ ToLayoutMultiColumnSet(column_set)->FirstFragmentainerGroup();
+ EXPECT_EQ(fragmentainer_group.ActualColumnCount(), 100U);
+ EXPECT_EQ(fragmentainer_group.GroupLogicalHeight(), LayoutUnit(60));
+ auto overflow = ToLayoutBox(multicol)->LayoutOverflowRect();
+ EXPECT_EQ(ToLayoutBox(multicol)->LogicalWidth(), LayoutUnit(101));
+ EXPECT_EQ(ToLayoutBox(multicol)->LogicalHeight(), LayoutUnit(60));
+ EXPECT_EQ(overflow.Width(), LayoutUnit(3399));
+ EXPECT_EQ(overflow.Height(), LayoutUnit(60));
}
} // anonymous namespace
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc
index cff6ef8c505..3c572fb11eb 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.cc
@@ -101,10 +101,18 @@ bool Intersects(const NGLayoutOpportunity& opportunity,
bool Intersects(const NGExclusionSpace::NGShelf& shelf,
const NGBfcOffset& offset,
const LayoutUnit inline_size) {
- return (shelf.line_right == LayoutUnit::Max() ||
- shelf.line_right >= offset.line_offset) &&
- (shelf.line_left == LayoutUnit::Min() ||
- shelf.line_left <= offset.line_offset + inline_size);
+ if (shelf.line_right >= offset.line_offset &&
+ shelf.line_left <= offset.line_offset + inline_size)
+ return true;
+ // Negative available space creates a zero-width opportunity at the inline-end
+ // of the shelf. Consider such shelf intersects.
+ // TODO(kojii): This is correct to find layout opportunities for zero-width
+ // in-flow inline or block objects (e.g., <br>,) but not correct for
+ // zero-width floats.
+ if (UNLIKELY(shelf.line_left > offset.line_offset ||
+ shelf.line_right < offset.line_offset + inline_size))
+ return true;
+ return false;
}
// Creates a new layout opportunity. The given layout opportunity *must*
@@ -122,7 +130,8 @@ NGLayoutOpportunity CreateLayoutOpportunity(const NGLayoutOpportunity& other,
std::min(other.rect.LineEndOffset(), offset.line_offset + inline_size),
other.rect.BlockEndOffset());
- return NGLayoutOpportunity(NGBfcRect(start_offset, end_offset));
+ return NGLayoutOpportunity(NGBfcRect(start_offset, end_offset),
+ other.shape_exclusions);
}
// Creates a new layout opportunity. The given shelf *must* intersect with the
@@ -136,11 +145,18 @@ NGLayoutOpportunity CreateLayoutOpportunity(
NGBfcOffset start_offset(std::max(shelf.line_left, offset.line_offset),
std::max(shelf.block_offset, offset.block_offset));
+ // Max with |start_offset.line_offset| in case the shelf has a negative
+ // inline-size.
NGBfcOffset end_offset(
- std::min(shelf.line_right, offset.line_offset + inline_size),
+ std::max(std::min(shelf.line_right, offset.line_offset + inline_size),
+ start_offset.line_offset),
LayoutUnit::Max());
- return NGLayoutOpportunity(NGBfcRect(start_offset, end_offset));
+ return NGLayoutOpportunity(
+ NGBfcRect(start_offset, end_offset),
+ shelf.has_shape_exclusions
+ ? base::AdoptRef(new NGShapeExclusions(*shelf.shape_exclusions))
+ : nullptr);
}
} // namespace
@@ -148,9 +164,7 @@ NGLayoutOpportunity CreateLayoutOpportunity(
NGExclusionSpace::NGExclusionSpace()
: last_float_block_start_(LayoutUnit::Min()),
left_float_clear_offset_(LayoutUnit::Min()),
- right_float_clear_offset_(LayoutUnit::Min()),
- has_left_float_(false),
- has_right_float_(false) {
+ right_float_clear_offset_(LayoutUnit::Min()) {
// The exclusion space must always have at least one shelf, at -Infinity.
shelves_.push_back(NGShelf(/* block_offset */ LayoutUnit::Min()));
}
@@ -163,11 +177,9 @@ void NGExclusionSpace::Add(scoped_refptr<const NGExclusion> exclusion) {
// Update the members used for clearance calculations.
if (exclusion->type == EFloat::kLeft) {
- has_left_float_ = true;
left_float_clear_offset_ =
std::max(left_float_clear_offset_, exclusion->rect.BlockEndOffset());
} else if (exclusion->type == EFloat::kRight) {
- has_right_float_ = true;
right_float_clear_offset_ =
std::max(right_float_clear_offset_, exclusion->rect.BlockEndOffset());
}
@@ -266,10 +278,14 @@ void NGExclusionSpace::Add(scoped_refptr<const NGExclusion> exclusion) {
// Insert a closed-off layout opportunity if needed.
if (has_solid_edges && is_overlapping) {
- NGLayoutOpportunity opportunity(NGBfcRect(
- /* start_offset */ {shelf.line_left, shelf.block_offset},
- /* end_offset */ {shelf.line_right,
- exclusion->rect.BlockStartOffset()}));
+ NGLayoutOpportunity opportunity(
+ NGBfcRect(
+ /* start_offset */ {shelf.line_left, shelf.block_offset},
+ /* end_offset */ {shelf.line_right,
+ exclusion->rect.BlockStartOffset()}),
+ shelf.has_shape_exclusions ? base::AdoptRef(new NGShapeExclusions(
+ *shelf.shape_exclusions))
+ : nullptr);
InsertOpportunity(opportunity, &opportunities_);
}
@@ -322,6 +338,7 @@ void NGExclusionSpace::Add(scoped_refptr<const NGExclusion> exclusion) {
shelf.line_left = exclusion->rect.LineEndOffset();
shelf.line_left_edges.push_back(exclusion);
}
+ shelf.shape_exclusions->line_left_shapes.push_back(exclusion);
} else {
DCHECK_EQ(exclusion->type, EFloat::kRight);
if (exclusion->rect.LineStartOffset() <= shelf.line_right) {
@@ -331,8 +348,20 @@ void NGExclusionSpace::Add(scoped_refptr<const NGExclusion> exclusion) {
shelf.line_right = exclusion->rect.LineStartOffset();
shelf.line_right_edges.push_back(exclusion);
}
+ shelf.shape_exclusions->line_right_shapes.push_back(exclusion);
}
+ // We collect all exclusions in shape_exclusions (even if they don't
+ // have any shape data associated with them - normal floats need to be
+ // included in the shape line algorithm). We use this bool to track
+ // if the shape exclusions should be copied to the resulting layout
+ // opportunity.
+ if (exclusion->shape_data)
+ shelf.has_shape_exclusions = true;
+
+ // Just in case the shelf has a negative inline-size.
+ shelf.line_right = std::max(shelf.line_left, shelf.line_right);
+
// We can end up in a situation where a shelf is the same as the
// previous one. For example:
//
@@ -351,12 +380,7 @@ void NGExclusionSpace::Add(scoped_refptr<const NGExclusion> exclusion) {
bool is_same_as_previous =
(i > 0) && shelf.line_left == shelves_[i - 1].line_left &&
shelf.line_right == shelves_[i - 1].line_right;
-
- // The shelf also may now be non-existent. Note that zero inline size is
- // allowed, since subsequent zero-size content may still fit there.
- bool shelf_disappearing = shelf.line_right < shelf.line_left;
-
- if (is_same_as_previous || shelf_disappearing) {
+ if (is_same_as_previous) {
shelves_.EraseAt(i);
removed_shelf = true;
}
@@ -440,11 +464,11 @@ Vector<NGLayoutOpportunity> NGExclusionSpace::AllLayoutOpportunities(
const LayoutUnit available_inline_size) const {
Vector<NGLayoutOpportunity> opportunities;
- auto shelves_it = shelves_.begin();
- auto opps_it = opportunities_.begin();
+ auto* shelves_it = shelves_.begin();
+ auto* opps_it = opportunities_.begin();
- const auto shelves_end = shelves_.end();
- const auto opps_end = opportunities_.end();
+ auto* const shelves_end = shelves_.end();
+ auto* const opps_end = opportunities_.end();
while (shelves_it != shelves_end || opps_it != opps_end) {
// We should never exhaust the opportunities list before the shelves list,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h
index 5af897497e8..190a934ae6e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h
@@ -47,9 +47,6 @@ class CORE_EXPORT NGExclusionSpace {
// Returns the block start offset of the last float added.
LayoutUnit LastFloatBlockStart() const { return last_float_block_start_; }
- bool HasLeftFloat() const { return has_left_float_; }
- bool HasRightFloat() const { return has_right_float_; }
-
bool operator==(const NGExclusionSpace& other) const;
bool operator!=(const NGExclusionSpace& other) const {
return !(*this == other);
@@ -90,7 +87,21 @@ class CORE_EXPORT NGExclusionSpace {
explicit NGShelf(LayoutUnit block_offset)
: block_offset(block_offset),
line_left(LayoutUnit::Min()),
- line_right(LayoutUnit::Max()) {}
+ line_right(LayoutUnit::Max()),
+ shape_exclusions(base::AdoptRef(new NGShapeExclusions)),
+ has_shape_exclusions(false) {}
+
+ // The copy constructor explicitly copies the shape_exclusions member,
+ // instead of just incrementing the ref.
+ NGShelf(const NGShelf& other)
+ : block_offset(other.block_offset),
+ line_left(other.line_left),
+ line_right(other.line_right),
+ line_left_edges(other.line_left_edges),
+ line_right_edges(other.line_right_edges),
+ shape_exclusions(
+ base::AdoptRef(new NGShapeExclusions(*other.shape_exclusions))),
+ has_shape_exclusions(other.has_shape_exclusions) {}
LayoutUnit block_offset;
LayoutUnit line_left;
@@ -98,6 +109,13 @@ class CORE_EXPORT NGExclusionSpace {
Vector<scoped_refptr<const NGExclusion>, 1> line_left_edges;
Vector<scoped_refptr<const NGExclusion>, 1> line_right_edges;
+
+ // shape_exclusions contains all the floats which sit below this shelf. The
+ // has_shape_exclusions member will be true if shape_exclusions contains an
+ // exclusion with shape-outside specified (and therefore should be copied
+ // to any layout opportunity).
+ scoped_refptr<NGShapeExclusions> shape_exclusions;
+ bool has_shape_exclusions;
};
private:
@@ -147,9 +165,6 @@ class CORE_EXPORT NGExclusionSpace {
// type of float. This is used for implementing float clearance.
LayoutUnit left_float_clear_offset_;
LayoutUnit right_float_clear_offset_;
-
- unsigned has_left_float_ : 1;
- unsigned has_right_float_ : 1;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space_test.cc
index 40c283b3c8a..68c61fe092d 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space_test.cc
@@ -97,16 +97,18 @@ TEST(NGExclusionSpaceTest, SingleExclusion) {
TEST_OPPORTUNITY(opportunites[2], NGBfcOffset(LayoutUnit(10), LayoutUnit(90)),
NGBfcOffset(LayoutUnit(60), LayoutUnit::Max()));
- // This will only produce two opportunities, as the RHS opportunity will be
- // outside the search area.
+ // This will also produce three opportunities, as the RHS opportunity outside
+ // the search area creates a zero-width opportunity.
opportunites = exclusion_space.AllLayoutOpportunities(
/* offset */ {LayoutUnit(10), LayoutUnit(10)},
/* available_size */ LayoutUnit(49));
- EXPECT_EQ(2u, opportunites.size());
+ EXPECT_EQ(3u, opportunites.size());
TEST_OPPORTUNITY(opportunites[0], NGBfcOffset(LayoutUnit(10), LayoutUnit(10)),
NGBfcOffset(LayoutUnit(59), LayoutUnit(20)));
- TEST_OPPORTUNITY(opportunites[1], NGBfcOffset(LayoutUnit(10), LayoutUnit(90)),
+ TEST_OPPORTUNITY(opportunites[1], NGBfcOffset(LayoutUnit(60), LayoutUnit(10)),
+ NGBfcOffset(LayoutUnit(60), LayoutUnit::Max()));
+ TEST_OPPORTUNITY(opportunites[2], NGBfcOffset(LayoutUnit(10), LayoutUnit(90)),
NGBfcOffset(LayoutUnit(59), LayoutUnit::Max()));
}
@@ -127,12 +129,14 @@ TEST(NGExclusionSpaceTest, TwoExclusions) {
/* offset */ {LayoutUnit(), LayoutUnit()},
/* available_size */ LayoutUnit(400));
- EXPECT_EQ(3u, opportunites.size());
+ EXPECT_EQ(4u, opportunites.size());
TEST_OPPORTUNITY(opportunites[0], NGBfcOffset(LayoutUnit(150), LayoutUnit()),
NGBfcOffset(LayoutUnit(400), LayoutUnit(75)));
- TEST_OPPORTUNITY(opportunites[1], NGBfcOffset(LayoutUnit(), LayoutUnit(75)),
+ TEST_OPPORTUNITY(opportunites[1], NGBfcOffset(LayoutUnit(150), LayoutUnit()),
+ NGBfcOffset(LayoutUnit(150), LayoutUnit::Max()));
+ TEST_OPPORTUNITY(opportunites[2], NGBfcOffset(LayoutUnit(), LayoutUnit(75)),
NGBfcOffset(LayoutUnit(100), LayoutUnit::Max()));
- TEST_OPPORTUNITY(opportunites[2], NGBfcOffset(LayoutUnit(), LayoutUnit(150)),
+ TEST_OPPORTUNITY(opportunites[3], NGBfcOffset(LayoutUnit(), LayoutUnit(150)),
NGBfcOffset(LayoutUnit(400), LayoutUnit::Max()));
}
@@ -286,5 +290,65 @@ TEST(NGExclusionSpaceTest, InsertBetweenShelves) {
NGBfcOffset(LayoutUnit(60), LayoutUnit::Max()));
}
+TEST(NGExclusionSpaceTest, ZeroInlineSizeOpportunity) {
+ NGExclusionSpace exclusion_space;
+
+ exclusion_space.Add(NGExclusion::Create(
+ NGBfcRect(NGBfcOffset(LayoutUnit(), LayoutUnit()),
+ NGBfcOffset(LayoutUnit(100), LayoutUnit(10))),
+ EFloat::kLeft));
+
+ Vector<NGLayoutOpportunity> opportunites =
+ exclusion_space.AllLayoutOpportunities(
+ /* offset */ {LayoutUnit(), LayoutUnit()},
+ /* available_size */ LayoutUnit(100));
+
+ EXPECT_EQ(2u, opportunites.size());
+ TEST_OPPORTUNITY(opportunites[0], NGBfcOffset(LayoutUnit(100), LayoutUnit()),
+ NGBfcOffset(LayoutUnit(100), LayoutUnit::Max()));
+ TEST_OPPORTUNITY(opportunites[1], NGBfcOffset(LayoutUnit(), LayoutUnit(10)),
+ NGBfcOffset(LayoutUnit(100), LayoutUnit::Max()));
+}
+
+TEST(NGExclusionSpaceTest, NegativeInlineSizeOpportunityLeft) {
+ NGExclusionSpace exclusion_space;
+
+ exclusion_space.Add(NGExclusion::Create(
+ NGBfcRect(NGBfcOffset(LayoutUnit(), LayoutUnit()),
+ NGBfcOffset(LayoutUnit(120), LayoutUnit(10))),
+ EFloat::kLeft));
+
+ Vector<NGLayoutOpportunity> opportunites =
+ exclusion_space.AllLayoutOpportunities(
+ /* offset */ {LayoutUnit(), LayoutUnit()},
+ /* available_size */ LayoutUnit(100));
+
+ EXPECT_EQ(2u, opportunites.size());
+ TEST_OPPORTUNITY(opportunites[0], NGBfcOffset(LayoutUnit(120), LayoutUnit()),
+ NGBfcOffset(LayoutUnit(120), LayoutUnit::Max()));
+ TEST_OPPORTUNITY(opportunites[1], NGBfcOffset(LayoutUnit(), LayoutUnit(10)),
+ NGBfcOffset(LayoutUnit(100), LayoutUnit::Max()));
+}
+
+TEST(NGExclusionSpaceTest, NegativeInlineSizeOpportunityRight) {
+ NGExclusionSpace exclusion_space;
+
+ exclusion_space.Add(NGExclusion::Create(
+ NGBfcRect(NGBfcOffset(LayoutUnit(-20), LayoutUnit()),
+ NGBfcOffset(LayoutUnit(100), LayoutUnit(10))),
+ EFloat::kRight));
+
+ Vector<NGLayoutOpportunity> opportunites =
+ exclusion_space.AllLayoutOpportunities(
+ /* offset */ {LayoutUnit(), LayoutUnit()},
+ /* available_size */ LayoutUnit(100));
+
+ EXPECT_EQ(2u, opportunites.size());
+ TEST_OPPORTUNITY(opportunites[0], NGBfcOffset(LayoutUnit(), LayoutUnit()),
+ NGBfcOffset(LayoutUnit(), LayoutUnit::Max()));
+ TEST_OPPORTUNITY(opportunites[1], NGBfcOffset(LayoutUnit(), LayoutUnit(10)),
+ NGBfcOffset(LayoutUnit(100), LayoutUnit::Max()));
+}
+
} // namespace
} // namespace blink
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
new file mode 100644
index 00000000000..34d8691aac6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.cc
@@ -0,0 +1,172 @@
+// 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/exclusions/ng_layout_opportunity.h"
+
+#include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
+#include "third_party/blink/renderer/core/layout/shapes/shape_outside_info.h"
+
+namespace blink {
+
+namespace {
+
+// Returns how far a line can "fit" into a given exclusion based on its shape
+// area. If the exclusion does not obstruct the line, then the returned
+// LineSegment will be "invalid".
+LineSegment ExcludedSegment(const NGExclusion& exclusion,
+ LayoutUnit bfc_block_offset,
+ LayoutUnit line_block_size) {
+ DCHECK(exclusion.shape_data);
+ const NGExclusionShapeData& shape_data = *exclusion.shape_data;
+ const Shape& shape =
+ shape_data.layout_box->GetShapeOutsideInfo()->ComputedShape();
+
+ // Determine the block offset (relative to the shape) at which we need to
+ // test for.
+ LayoutUnit shape_relative_block_offset =
+ bfc_block_offset -
+ (exclusion.rect.BlockStartOffset() + shape_data.margins.block_start +
+ shape_data.shape_insets.block_start);
+
+ // At the block-start/end of shapes it is possible for a line to just touch,
+ // and GetExcludedInterval will return a valid segment.
+ // This check skips the shape when this happens.
+ if (!shape.LineOverlapsShapeMarginBounds(shape_relative_block_offset,
+ line_block_size))
+ return LineSegment();
+
+ // Clamp the line size to the size of the shape.
+ LayoutUnit clamped_line_block_size =
+ std::min(line_block_size, exclusion.rect.BlockSize() -
+ shape_data.shape_insets.BlockSum() -
+ shape_data.margins.BlockSum());
+
+ LineSegment segment = shape.GetExcludedInterval(shape_relative_block_offset,
+ clamped_line_block_size);
+
+ // Adjust the segment offsets to be relative to the line-left margin edge.
+ LayoutUnit margin_delta =
+ shape_data.margins.LineLeft(TextDirection::kLtr) +
+ shape_data.shape_insets.LineLeft(TextDirection::kLtr);
+ segment.logical_left += margin_delta;
+ segment.logical_right += margin_delta;
+
+ // Clamp the segment offsets to the size of the exclusion.
+ segment.logical_left = clampTo<LayoutUnit>(segment.logical_left, LayoutUnit(),
+ exclusion.rect.InlineSize());
+ segment.logical_right = clampTo<LayoutUnit>(
+ segment.logical_right, LayoutUnit(), exclusion.rect.InlineSize());
+
+ // Make the segment offsets relative to the BFC coordinate space.
+ segment.logical_left += exclusion.rect.LineStartOffset();
+ segment.logical_right += exclusion.rect.LineStartOffset();
+
+ return segment;
+}
+
+// Returns if the given line block-size and offset intersects with the given
+// exclusion.
+bool IntersectsExclusion(const NGExclusion& exclusion,
+ LayoutUnit bfc_block_offset,
+ LayoutUnit line_block_size) {
+ return bfc_block_offset < exclusion.rect.BlockEndOffset() &&
+ bfc_block_offset + line_block_size > exclusion.rect.BlockStartOffset();
+}
+
+} // namespace
+
+bool NGLayoutOpportunity::IsBlockDeltaBelowShapes(
+ LayoutUnit block_delta) const {
+ DCHECK(shape_exclusions);
+
+ for (const auto& exclusion : shape_exclusions->line_left_shapes) {
+ if (rect.BlockStartOffset() + block_delta <
+ exclusion->rect.BlockEndOffset())
+ return false;
+ }
+
+ for (const auto& exclusion : shape_exclusions->line_right_shapes) {
+ if (rect.BlockStartOffset() + block_delta <
+ exclusion->rect.BlockEndOffset())
+ return false;
+ }
+
+ 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,
+ LayoutUnit block_delta) const {
+ if (!shape_exclusions || shape_exclusions->line_left_shapes.IsEmpty())
+ return rect.LineStartOffset();
+
+ LayoutUnit bfc_block_offset = rect.BlockStartOffset() + block_delta;
+
+ // Step through each exclusion and re-build the line_left_offset. Without
+ // shapes this would be the same as the opportunity offset.
+ //
+ // We rebuild this offset from the line-left end, checking each exclusion and
+ // increasing the line_left when an exclusion intersects.
+ LayoutUnit line_left = space.BfcOffset().line_offset;
+ for (auto& exclusion : shape_exclusions->line_left_shapes) {
+ if (exclusion->shape_data) {
+ LineSegment segment =
+ ExcludedSegment(*exclusion, bfc_block_offset, line_block_size);
+ if (segment.is_valid)
+ line_left = std::max(line_left, segment.logical_right);
+ } else {
+ if (IntersectsExclusion(*exclusion, bfc_block_offset, line_block_size))
+ line_left = std::max(line_left, exclusion->rect.LineEndOffset());
+ }
+ }
+
+ return std::min(line_left, rect.LineEndOffset());
+}
+
+LayoutUnit NGLayoutOpportunity::ComputeLineRightOffset(
+ const NGConstraintSpace& space,
+ LayoutUnit line_block_size,
+ LayoutUnit block_delta) const {
+ if (!shape_exclusions || shape_exclusions->line_right_shapes.IsEmpty())
+ return rect.LineEndOffset();
+
+ LayoutUnit bfc_block_offset = rect.BlockStartOffset() + block_delta;
+
+ LayoutUnit line_right =
+ space.BfcOffset().line_offset + space.AvailableSize().inline_size;
+
+ // Step through each exclusion and re-build the line_right_offset. Without
+ // shapes this would be the same as the opportunity offset.
+ //
+ // We rebuild this offset from the line-right end, checking each exclusion and
+ // reducing the line_right when an exclusion intersects.
+ for (auto& exclusion : shape_exclusions->line_right_shapes) {
+ if (exclusion->shape_data) {
+ LineSegment segment =
+ ExcludedSegment(*exclusion, bfc_block_offset, line_block_size);
+ if (segment.is_valid)
+ line_right = std::min(line_right, segment.logical_left);
+ } else {
+ if (IntersectsExclusion(*exclusion, bfc_block_offset, line_block_size))
+ line_right = std::min(line_right, exclusion->rect.LineStartOffset());
+ }
+ }
+
+ return std::max(line_right, rect.LineStartOffset());
+}
+
+} // namespace blink
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 87e23b39c98..226f01d89df 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
@@ -6,23 +6,58 @@
#define NGLayoutOpportunity_h
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h"
+#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_shape_exclusions.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_rect.h"
namespace blink {
+class NGConstraintSpace;
+
+// This struct represents an 2D-area where a NGFragment can fit within the
+// exclusion space. A layout opportunity is produced by the exclusion space by
+// calling FindLayoutOpportunity, or AllLayoutOpportunities.
+//
+// Its coordinates are relative to the BFC.
struct CORE_EXPORT NGLayoutOpportunity {
NGLayoutOpportunity()
: rect(NGBfcOffset(LayoutUnit::Min(), LayoutUnit::Min()),
NGBfcOffset(LayoutUnit::Max(), LayoutUnit::Max())) {}
- explicit NGLayoutOpportunity(const NGBfcRect& rect) : rect(rect) {}
+ NGLayoutOpportunity(
+ const NGBfcRect& rect,
+ scoped_refptr<const NGShapeExclusions> shape_exclusions = nullptr)
+ : rect(rect), shape_exclusions(std::move(shape_exclusions)) {}
// Rectangle in BFC coordinates that represents this opportunity.
NGBfcRect rect;
- // TODO(ikilpatrick): This will also need to hold all the adjacent exclusions
- // on each edge for implementing css-shapes correctly. It'll need to have
- // methods which use these adjacent exclusions to determine the available
- // inline-size for a line-box.
+ // The shape exclusions hold all of the adjacent exclusions which may affect
+ // the line layout opportunity when queried. May be null if no shapes are
+ // present.
+ scoped_refptr<const NGShapeExclusions> shape_exclusions;
+
+ // Returns if the opportunity has any shapes which may affect a line layout
+ // opportunity.
+ bool HasShapeExclusions() const { return shape_exclusions.get(); }
+
+ // Returns if the given delta (relative to the start of the opportunity) will
+ // be below any shapes.
+ bool IsBlockDeltaBelowShapes(LayoutUnit block_delta) const;
+
+ // 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&,
+ LayoutUnit line_block_size,
+ LayoutUnit block_delta) const;
+
+ private:
+ LayoutUnit ComputeLineLeftOffset(const NGConstraintSpace&,
+ LayoutUnit line_block_size,
+ LayoutUnit block_delta) const;
+ LayoutUnit ComputeLineRightOffset(const NGConstraintSpace&,
+ LayoutUnit line_block_size,
+ LayoutUnit block_delta) const;
};
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h
new file mode 100644
index 00000000000..ee9f8b10141
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h
@@ -0,0 +1,66 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_LINE_LAYOUT_OPPORTUNITY_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_LINE_LAYOUT_OPPORTUNITY_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+
+namespace blink {
+
+// This struct represents a 1D-area where a line can fit. It is only used for
+// representing the inline size.
+struct CORE_EXPORT NGLineLayoutOpportunity {
+ STACK_ALLOCATED();
+
+ NGLineLayoutOpportunity() {}
+ NGLineLayoutOpportunity(LayoutUnit inline_size)
+ : line_right_offset(inline_size), float_line_right_offset(inline_size) {}
+ NGLineLayoutOpportunity(LayoutUnit line_left_offset,
+ LayoutUnit line_right_offset,
+ LayoutUnit float_line_left_offset,
+ LayoutUnit float_line_right_offset,
+ LayoutUnit bfc_block_offset,
+ LayoutUnit line_block_size)
+ : line_left_offset(line_left_offset),
+ line_right_offset(line_right_offset),
+ float_line_left_offset(float_line_left_offset),
+ float_line_right_offset(float_line_right_offset),
+ bfc_block_offset(bfc_block_offset),
+ line_block_size(line_block_size) {}
+
+ // The available inline-size of the line, taking shapes into account. Both
+ // offsets are relative to the BFC coordinate system.
+ LayoutUnit line_left_offset;
+ LayoutUnit line_right_offset;
+
+ // The available inline-size of the line *for floats*. This is the same size
+ // as the layout opportunity which generated this object. Both offsets are
+ // relative to the BFC coordinate system.
+ LayoutUnit float_line_left_offset;
+ LayoutUnit float_line_right_offset;
+
+ LayoutUnit bfc_block_offset;
+
+ // The block-size this line layout opportunity was created with. Should
+ // *only* be used for re-querying for a new line layout opportunity with the
+ // same block-size.
+ LayoutUnit line_block_size;
+
+ LayoutUnit AvailableInlineSize() const {
+ DCHECK_GE(line_right_offset, line_left_offset);
+ return line_right_offset - line_left_offset;
+ }
+
+ LayoutUnit AvailableFloatInlineSize() const {
+ DCHECK_GE(float_line_right_offset, float_line_left_offset);
+ return float_line_right_offset - float_line_left_offset;
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_LINE_LAYOUT_OPPORTUNITY_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_shape_exclusions.h b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_shape_exclusions.h
new file mode 100644
index 00000000000..8130c956c7f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/exclusions/ng_shape_exclusions.h
@@ -0,0 +1,35 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_SHAPE_EXCLUSIONS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_SHAPE_EXCLUSIONS_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_exclusion.h"
+#include "third_party/blink/renderer/platform/layout_unit.h"
+#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+// This struct represents exclusions which have shape data associated with them.
+// As shapes are relatively uncommon we store these as a separate struct, and
+// allocate only when necessary.
+//
+// This struct can belong to either a NGShelf within the exclusion space, or on
+// NGLayoutOpportunity. Outside these classes normal code shouldn't interact
+// with this class.
+class CORE_EXPORT NGShapeExclusions : public RefCounted<NGShapeExclusions> {
+ public:
+ NGShapeExclusions() {}
+ NGShapeExclusions(const NGShapeExclusions& other)
+ : line_left_shapes(other.line_left_shapes),
+ line_right_shapes(other.line_right_shapes) {}
+ Vector<scoped_refptr<const NGExclusion>> line_left_shapes;
+ Vector<scoped_refptr<const NGExclusion>> line_right_shapes;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_EXCLUSIONS_NG_SHAPE_EXCLUSIONS_H_
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 2c1f86493be..c6566b7652c 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
@@ -60,6 +60,20 @@ struct CORE_EXPORT NGBoxStrut {
return result;
}
+ NGBoxStrut& operator-=(const NGBoxStrut& other) {
+ inline_start -= other.inline_start;
+ inline_end -= other.inline_end;
+ block_start -= other.block_start;
+ block_end -= other.block_end;
+ return *this;
+ }
+
+ NGBoxStrut operator-(const NGBoxStrut& other) {
+ NGBoxStrut result(*this);
+ result -= other;
+ return result;
+ }
+
bool operator==(const NGBoxStrut& other) const;
String ToString() const;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_edge.h b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_edge.h
deleted file mode 100644
index e68fec28352..00000000000
--- a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_edge.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 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 NGEdge_h
-#define NGEdge_h
-
-#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
-
-namespace blink {
-
-// Struct to represent a simple edge that has start and end.
-struct CORE_EXPORT NGEdge {
- LayoutUnit start;
- LayoutUnit end;
-};
-
-} // namespace blink
-
-#endif // NGEdge_h
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.cc b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.cc
index dab6bf141fa..37dc6f0a2da 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.cc
@@ -4,7 +4,8 @@
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h"
-#include "third_party/blink/renderer/platform/geometry/float_rect.h"
+#include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -35,6 +36,23 @@ void NGPhysicalOffsetRect::Unite(const NGPhysicalOffsetRect& other) {
size = {right - left, bottom - top};
}
+void NGPhysicalOffsetRect::Expand(const NGPhysicalBoxStrut& strut) {
+ if (strut.top) {
+ offset.top -= strut.top;
+ size.height += strut.top;
+ }
+ if (strut.bottom) {
+ size.height += strut.bottom;
+ }
+ if (strut.left) {
+ offset.left -= strut.left;
+ size.width += strut.left;
+ }
+ if (strut.right) {
+ size.width += strut.right;
+ }
+}
+
NGPhysicalOffsetRect::NGPhysicalOffsetRect(const LayoutRect& source)
: NGPhysicalOffsetRect({source.X(), source.Y()},
{source.Width(), source.Height()}) {}
@@ -43,6 +61,15 @@ LayoutRect NGPhysicalOffsetRect::ToLayoutRect() const {
return {offset.left, offset.top, size.width, size.height};
}
+LayoutRect NGPhysicalOffsetRect::ToLayoutFlippedRect(
+ const ComputedStyle& style,
+ const NGPhysicalSize& container_size) const {
+ if (!style.IsFlippedBlocksWritingMode())
+ return {offset.left, offset.top, size.width, size.height};
+ return {container_size.width - offset.left - size.width, offset.top,
+ size.width, size.height};
+}
+
FloatRect NGPhysicalOffsetRect::ToFloatRect() const {
return {offset.left, offset.top, size.width, size.height};
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h
index c41a79ddaf4..723c8961491 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h
@@ -12,8 +12,10 @@
namespace blink {
+class ComputedStyle;
class FloatRect;
class LayoutRect;
+struct NGPhysicalBoxStrut;
// NGPhysicalOffsetRect is the position and size of a rect (typically a
// fragment) relative to its parent rect in the physical coordinate system.
@@ -36,10 +38,15 @@ struct CORE_EXPORT NGPhysicalOffsetRect {
void Unite(const NGPhysicalOffsetRect&);
+ void Expand(const NGPhysicalBoxStrut&);
+
// Conversions from/to existing code. New code prefers type safety for
// logical/physical distinctions.
explicit NGPhysicalOffsetRect(const LayoutRect&);
LayoutRect ToLayoutRect() const;
+ LayoutRect ToLayoutFlippedRect(const ComputedStyle&,
+ const NGPhysicalSize&) const;
+
FloatRect ToFloatRect() const;
String ToString() const;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h
new file mode 100644
index 00000000000..8ea80821037
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.h
@@ -0,0 +1,64 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_LAYOUT_NG_TEXT_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_LAYOUT_NG_TEXT_H_
+
+#include "third_party/blink/renderer/core/layout/layout_text.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
+
+namespace blink {
+
+class NGInlineItem;
+
+// This overrides the default LayoutText to reference LayoutNGInlineItems
+// instead of InlineTextBoxes.
+//
+// ***** INLINE ITEMS OWNERSHIP *****
+// NGInlineItems in items_ are not owned by LayoutText but are pointers into the
+// LayoutNGBlockFlow's items_. Should not be accessed outside of layout.
+class CORE_EXPORT LayoutNGText : public LayoutText {
+ public:
+ LayoutNGText(Node* node, scoped_refptr<StringImpl> text)
+ : LayoutText(node, text) {}
+
+ bool IsOfType(LayoutObjectType type) const override {
+ return type == kLayoutObjectNGText || LayoutText::IsOfType(type);
+ }
+
+ bool HasValidLayout() const { return valid_ng_items_; }
+ const Vector<NGInlineItem*>& InlineItems() const {
+ DCHECK(valid_ng_items_);
+ return inline_items_;
+ }
+
+ // Inline items depends on context. It needs to be invalidated not only when
+ // it was inserted/changed but also it was moved.
+ void InvalidateInlineItems() { valid_ng_items_ = false; }
+
+ void ClearInlineItems() {
+ inline_items_.clear();
+ valid_ng_items_ = false;
+ }
+
+ void AddInlineItem(NGInlineItem* item) {
+ inline_items_.push_back(item);
+ valid_ng_items_ = true;
+ }
+
+ protected:
+ void InsertedIntoTree() override {
+ valid_ng_items_ = false;
+ LayoutText::InsertedIntoTree();
+ }
+
+ private:
+ Vector<NGInlineItem*> inline_items_;
+};
+
+DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGText, IsLayoutNGText());
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_LAYOUT_NG_TEXT_H_
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
new file mode 100644
index 00000000000..cadd9c38992
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.cc
@@ -0,0 +1,313 @@
+// 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_caret_position.h"
+
+#include "third_party/blink/renderer/core/editing/inline_box_traversal.h"
+#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
+#include "third_party/blink/renderer/core/editing/text_affinity.h"
+#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.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"
+#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h"
+
+namespace blink {
+
+namespace {
+
+void AssertValidPositionForCaretPositionComputation(
+ const PositionWithAffinity& position) {
+#if DCHECK_IS_ON()
+ DCHECK(NGOffsetMapping::AcceptsPosition(position.GetPosition()));
+ const LayoutObject* layout_object = position.AnchorNode()->GetLayoutObject();
+ DCHECK(layout_object);
+ DCHECK(layout_object->IsText() || layout_object->IsAtomicInlineLevel());
+#endif
+}
+
+// The calculation takes the following input:
+// - An inline formatting context as a |LayoutBlockFlow|
+// - An offset in the |text_content_| string of the above context
+// - A TextAffinity
+//
+// The calculation iterates all inline fragments in the context, and tries to
+// compute an NGCaretPosition using the "caret resolution process" below:
+//
+// The (offset, affinity) pair is compared against each inline fragment to see
+// if the corresponding caret should be placed in the fragment, using the
+// |TryResolveCaretPositionInXXX()| functions. These functions may return:
+// - Failed, indicating that the caret must not be placed in the fragment;
+// - Resolved, indicating that the care should be placed in the fragment, and
+// no further search is required. The result NGCaretPosition is returned
+// together.
+// - FoundCandidate, indicating that the caret may be placed in the fragment;
+// however, further search may find a better position. The candidate
+// NGCaretPosition is also returned together.
+
+enum class ResolutionType { kFailed, kFoundCandidate, kResolved };
+struct CaretPositionResolution {
+ ResolutionType type = ResolutionType::kFailed;
+ NGCaretPosition caret_position;
+};
+
+bool CanResolveCaretPositionBeforeFragment(const NGPaintFragment& fragment,
+ TextAffinity affinity) {
+ if (affinity == TextAffinity::kDownstream)
+ return true;
+ const NGPaintFragment* current_line_paint = fragment.ContainerLineBox();
+ const NGPhysicalLineBoxFragment& current_line =
+ ToNGPhysicalLineBoxFragment(current_line_paint->PhysicalFragment());
+ // A fragment after line wrap must be the first logical leaf in its line.
+ if (&fragment.PhysicalFragment() != current_line.FirstLogicalLeaf())
+ return true;
+ const NGPaintFragment* last_line_paint =
+ NGPaintFragmentTraversal::PreviousLineOf(*current_line_paint);
+ return !last_line_paint ||
+ !ToNGPhysicalLineBoxFragment(last_line_paint->PhysicalFragment())
+ .HasSoftWrapToNextLine();
+}
+
+bool CanResolveCaretPositionAfterFragment(const NGPaintFragment& fragment,
+ TextAffinity affinity) {
+ if (affinity == TextAffinity::kUpstream)
+ return true;
+ const NGPaintFragment* current_line_paint = fragment.ContainerLineBox();
+ const NGPhysicalLineBoxFragment& current_line =
+ ToNGPhysicalLineBoxFragment(current_line_paint->PhysicalFragment());
+ // A fragment before line wrap must be the last logical leaf in its line.
+ if (&fragment.PhysicalFragment() != current_line.LastLogicalLeaf())
+ return true;
+ return !current_line.HasSoftWrapToNextLine();
+}
+
+// Returns a |kFailed| resolution if |offset| doesn't belong to the text
+// fragment. Otherwise, return either |kFoundCandidate| or |kResolved| depending
+// on |affinity|.
+CaretPositionResolution TryResolveCaretPositionInTextFragment(
+ const NGPaintFragment& paint_fragment,
+ unsigned offset,
+ TextAffinity affinity) {
+ DCHECK(paint_fragment.PhysicalFragment().IsText());
+ const NGPhysicalTextFragment& fragment =
+ ToNGPhysicalTextFragment(paint_fragment.PhysicalFragment());
+ if (fragment.IsAnonymousText())
+ return CaretPositionResolution();
+
+ const NGOffsetMapping& mapping =
+ *NGOffsetMapping::GetFor(paint_fragment.GetLayoutObject());
+
+ // A text fragment natually allows caret placement in offset range
+ // [StartOffset(), EndOffset()], i.e., from before the first character to
+ // after the last character.
+ // Besides, leading/trailing bidi control characters are ignored since their
+ // two sides are considered the same caret position. Hence, if there are n and
+ // m leading and trailing bidi control characters, then the allowed offset
+ // range is [StartOffset() - n, EndOffset() + m].
+ // 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.
+ if (offset < fragment.StartOffset() &&
+ !mapping.HasBidiControlCharactersOnly(offset, fragment.StartOffset()))
+ return CaretPositionResolution();
+ if (offset > fragment.EndOffset() &&
+ !mapping.HasBidiControlCharactersOnly(fragment.EndOffset(), offset))
+ return CaretPositionResolution();
+
+ offset = std::max(offset, fragment.StartOffset());
+ offset = std::min(offset, fragment.EndOffset());
+ NGCaretPosition candidate = {&paint_fragment,
+ NGCaretPositionType::kAtTextOffset, offset};
+
+ // Offsets in the interior of a fragment can be resolved directly.
+ if (offset > fragment.StartOffset() && offset < fragment.EndOffset())
+ return {ResolutionType::kResolved, candidate};
+
+ if (offset == fragment.StartOffset() &&
+ CanResolveCaretPositionBeforeFragment(paint_fragment, affinity)) {
+ return {ResolutionType::kResolved, candidate};
+ }
+
+ if (offset == fragment.EndOffset() && !fragment.IsLineBreak() &&
+ CanResolveCaretPositionAfterFragment(paint_fragment, affinity)) {
+ return {ResolutionType::kResolved, candidate};
+ }
+
+ // We may have a better candidate
+ return {ResolutionType::kFoundCandidate, candidate};
+}
+
+unsigned GetTextOffsetBefore(const NGPhysicalFragment& fragment) {
+ // TODO(xiaochengh): Design more straightforward way to get text offset of
+ // atomic inline box.
+ DCHECK(fragment.IsAtomicInline());
+ const Node* node = fragment.GetNode();
+ DCHECK(node);
+ const Position before_node = Position::BeforeNode(*node);
+ base::Optional<unsigned> maybe_offset_before =
+ NGOffsetMapping::GetFor(before_node)->GetTextContentOffset(before_node);
+ // We should have offset mapping for atomic inline boxes.
+ DCHECK(maybe_offset_before.has_value());
+ return maybe_offset_before.value();
+}
+
+// Returns a |kFailed| resolution if |offset| doesn't belong to the atomic
+// inline box fragment. Otherwise, return either |kFoundCandidate| or
+// |kResolved| depending on |affinity|.
+CaretPositionResolution TryResolveCaretPositionByBoxFragmentSide(
+ const NGPaintFragment& fragment,
+ unsigned offset,
+ TextAffinity affinity) {
+ if (!fragment.GetNode()) {
+ // TODO(xiaochengh): This leads to false negatives for, e.g., RUBY, where an
+ // anonymous wrapping inline block is created.
+ return CaretPositionResolution();
+ }
+
+ const unsigned offset_before =
+ GetTextOffsetBefore(fragment.PhysicalFragment());
+ const unsigned offset_after = offset_before + 1;
+ // TODO(xiaochengh): Ignore bidi control characters before & after the box.
+ if (offset != offset_before && offset != offset_after)
+ return CaretPositionResolution();
+ const NGCaretPositionType position_type =
+ offset == offset_before ? NGCaretPositionType::kBeforeBox
+ : NGCaretPositionType::kAfterBox;
+ NGCaretPosition candidate{&fragment, position_type, base::nullopt};
+
+ if (offset == offset_before &&
+ CanResolveCaretPositionBeforeFragment(fragment, affinity)) {
+ return {ResolutionType::kResolved, candidate};
+ }
+
+ if (offset == offset_after &&
+ CanResolveCaretPositionAfterFragment(fragment, affinity)) {
+ return {ResolutionType::kResolved, candidate};
+ }
+
+ return {ResolutionType::kFoundCandidate, candidate};
+}
+
+CaretPositionResolution TryResolveCaretPositionWithFragment(
+ const NGPaintFragment& paint_fragment,
+ unsigned offset,
+ TextAffinity affinity) {
+ const NGPhysicalFragment& fragment = paint_fragment.PhysicalFragment();
+ if (fragment.IsText()) {
+ return TryResolveCaretPositionInTextFragment(paint_fragment, offset,
+ affinity);
+ }
+ if (fragment.IsBox() && fragment.IsAtomicInline()) {
+ return TryResolveCaretPositionByBoxFragmentSide(paint_fragment, offset,
+ affinity);
+ }
+ return CaretPositionResolution();
+}
+
+bool NeedsBidiAdjustment(const NGCaretPosition& caret_position) {
+ if (caret_position.IsNull())
+ return false;
+ if (caret_position.position_type != NGCaretPositionType::kAtTextOffset)
+ return true;
+ DCHECK(caret_position.text_offset.has_value());
+ DCHECK(caret_position.fragment->PhysicalFragment().IsText());
+ const NGPhysicalTextFragment& text_fragment =
+ ToNGPhysicalTextFragment(caret_position.fragment->PhysicalFragment());
+ DCHECK_GE(*caret_position.text_offset, text_fragment.StartOffset());
+ DCHECK_LE(*caret_position.text_offset, text_fragment.EndOffset());
+ // Bidi adjustment is needed only for caret positions at bidi boundaries.
+ // Caret positions in the middle of a text fragment can't be at bidi
+ // boundaries, and hence, don't need any adjustment.
+ return *caret_position.text_offset == text_fragment.StartOffset() ||
+ *caret_position.text_offset == text_fragment.EndOffset();
+}
+
+NGCaretPosition AdjustCaretPositionForBidiText(
+ const NGCaretPosition& caret_position) {
+ if (!NeedsBidiAdjustment(caret_position))
+ return caret_position;
+ return BidiAdjustment::AdjustForCaretPositionResolution(caret_position);
+}
+
+} // namespace
+
+// The main function for compute an NGCaretPosition. See the comments at the top
+// of this file for details.
+NGCaretPosition ComputeNGCaretPosition(const LayoutBlockFlow& context,
+ unsigned offset,
+ TextAffinity affinity) {
+ const NGPaintFragment* root_fragment = context.PaintFragment();
+ DCHECK(root_fragment) << "no paint fragment on layout object " << &context;
+
+ NGCaretPosition candidate;
+ for (const auto& child :
+ NGPaintFragmentTraversal::InlineDescendantsOf(*root_fragment)) {
+ const CaretPositionResolution resolution =
+ TryResolveCaretPositionWithFragment(*child.fragment, offset, affinity);
+
+ if (resolution.type == ResolutionType::kFailed)
+ continue;
+
+ // TODO(xiaochengh): Handle caret poisition in empty container (e.g. empty
+ // line box).
+
+ if (resolution.type == ResolutionType::kResolved)
+ return AdjustCaretPositionForBidiText(resolution.caret_position);
+
+ DCHECK_EQ(ResolutionType::kFoundCandidate, resolution.type);
+ // TODO(xiaochengh): We are not sure if we can ever find multiple
+ // candidates. Handle it once reached.
+ DCHECK(candidate.IsNull());
+ candidate = resolution.caret_position;
+ }
+
+ return AdjustCaretPositionForBidiText(candidate);
+}
+
+NGCaretPosition ComputeNGCaretPosition(const PositionWithAffinity& position) {
+ AssertValidPositionForCaretPositionComputation(position);
+ const LayoutBlockFlow* context =
+ NGInlineFormattingContextOf(position.GetPosition());
+ if (!context)
+ return NGCaretPosition();
+
+ const NGOffsetMapping* mapping = NGOffsetMapping::GetFor(context);
+ DCHECK(mapping);
+ const base::Optional<unsigned> maybe_offset =
+ mapping->GetTextContentOffset(position.GetPosition());
+ if (!maybe_offset.has_value()) {
+ // TODO(xiaochengh): Investigate if we reach here.
+ NOTREACHED();
+ return NGCaretPosition();
+ }
+
+ const unsigned offset = maybe_offset.value();
+ const TextAffinity affinity = position.Affinity();
+ return ComputeNGCaretPosition(*context, offset, affinity);
+}
+
+Position NGCaretPosition::ToPositionInDOMTree() const {
+ if (!fragment)
+ return Position();
+ switch (position_type) {
+ case NGCaretPositionType::kBeforeBox:
+ if (!fragment->GetNode())
+ return Position();
+ return Position::BeforeNode(*fragment->GetNode());
+ case NGCaretPositionType::kAfterBox:
+ if (!fragment->GetNode())
+ return Position();
+ return Position::AfterNode(*fragment->GetNode());
+ case NGCaretPositionType::kAtTextOffset:
+ DCHECK(text_offset.has_value());
+ const NGOffsetMapping* mapping =
+ NGOffsetMapping::GetFor(fragment->GetLayoutObject());
+ return mapping->GetFirstPosition(*text_offset);
+ }
+ NOTREACHED();
+ return Position();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h
new file mode 100644
index 00000000000..e6a963099c6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_CARET_POSITION_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_CARET_POSITION_H_
+
+#include "base/optional.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/editing/forward.h"
+#include "third_party/blink/renderer/platform/wtf/allocator.h"
+
+namespace blink {
+
+class NGPaintFragment;
+class LayoutBlockFlow;
+
+// An NGCaretPosition indicates a caret position relative to an inline
+// NGPaintFragment:
+// - When |fragment| is box, |position_type| is either |kBeforeBox| or
+// |kAfterBox|, indicating either of the two caret positions by the box sides;
+// |text_offset| is |nullopt| in this case.
+// - When |fragment| is text, |position_type| is |kAtTextOffset|, and
+// |text_offset| is in the text offset range of the fragment.
+//
+// TODO(xiaochengh): Support "in empty container" caret type
+
+enum class NGCaretPositionType { kBeforeBox, kAfterBox, kAtTextOffset };
+struct NGCaretPosition {
+ DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
+
+ bool IsNull() const { return !fragment; }
+
+ Position ToPositionInDOMTree() const;
+
+ const NGPaintFragment* fragment = nullptr; // owned by root LayoutNGMixin
+ NGCaretPositionType position_type;
+ base::Optional<unsigned> text_offset;
+};
+
+// Given an inline formatting context, a text offset in the context and a text
+// affinity, returns the corresponding NGCaretPosition, or null if not found.
+// Note that in many cases, null result indicates that we have reached an
+// unexpected case that is not properly handled.
+CORE_EXPORT NGCaretPosition ComputeNGCaretPosition(const LayoutBlockFlow&,
+ unsigned,
+ TextAffinity);
+
+// Shorthand of the above when the input is a position instead of a
+// (context, offset) pair.
+NGCaretPosition ComputeNGCaretPosition(const PositionWithAffinity&);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_CARET_POSITION_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position_test.cc
index 1ed9a35639e..da232c2bf83 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_position_test.cc
@@ -2,8 +2,9 @@
// 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_caret_rect.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h"
+#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.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_offset_mapping.h"
@@ -14,9 +15,9 @@
namespace blink {
-class NGCaretRectTest : public NGLayoutTest {
+class NGCaretPositionTest : public NGLayoutTest {
public:
- NGCaretRectTest() : NGLayoutTest() {}
+ NGCaretPositionTest() : NGLayoutTest() {}
void SetUp() override {
NGLayoutTest::SetUp();
@@ -69,31 +70,31 @@ class NGCaretRectTest : public NGLayoutTest {
EXPECT_EQ(caret.text_offset, offset_) << caret.text_offset.value_or(-1); \
}
-TEST_F(NGCaretRectTest, CaretPositionInOneLineOfText) {
+TEST_F(NGCaretPositionTest, CaretPositionInOneLineOfText) {
SetInlineFormattingContext("t", "foo", 3);
const Node* text = container_->firstChild();
const NGPhysicalFragment* text_fragment = FragmentOf(text);
// Beginning of line
TEST_CARET(ComputeNGCaretPosition(0, TextAffinity::kDownstream),
- text_fragment, kAtTextOffset, Optional<unsigned>(0));
+ text_fragment, kAtTextOffset, base::Optional<unsigned>(0));
TEST_CARET(ComputeNGCaretPosition(0, TextAffinity::kUpstream), text_fragment,
- kAtTextOffset, Optional<unsigned>(0));
+ kAtTextOffset, base::Optional<unsigned>(0));
// Middle in the line
TEST_CARET(ComputeNGCaretPosition(1, TextAffinity::kDownstream),
- text_fragment, kAtTextOffset, Optional<unsigned>(1));
+ text_fragment, kAtTextOffset, base::Optional<unsigned>(1));
TEST_CARET(ComputeNGCaretPosition(1, TextAffinity::kUpstream), text_fragment,
- kAtTextOffset, Optional<unsigned>(1));
+ kAtTextOffset, base::Optional<unsigned>(1));
// End of line
TEST_CARET(ComputeNGCaretPosition(3, TextAffinity::kDownstream),
- text_fragment, kAtTextOffset, Optional<unsigned>(3));
+ text_fragment, kAtTextOffset, base::Optional<unsigned>(3));
TEST_CARET(ComputeNGCaretPosition(3, TextAffinity::kUpstream), text_fragment,
- kAtTextOffset, Optional<unsigned>(3));
+ kAtTextOffset, base::Optional<unsigned>(3));
}
-TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrap) {
+TEST_F(NGCaretPositionTest, CaretPositionAtSoftLineWrap) {
SetInlineFormattingContext("t", "foobar", 3);
const Node* text = container_->firstChild();
const auto text_fragments = NGInlineFragmentTraversal::SelfFragmentsOf(
@@ -102,12 +103,12 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrap) {
const NGPhysicalFragment* bar_fragment = text_fragments[1].fragment.get();
TEST_CARET(ComputeNGCaretPosition(3, TextAffinity::kDownstream), bar_fragment,
- kAtTextOffset, Optional<unsigned>(3));
+ kAtTextOffset, base::Optional<unsigned>(3));
TEST_CARET(ComputeNGCaretPosition(3, TextAffinity::kUpstream), foo_fragment,
- kAtTextOffset, Optional<unsigned>(3));
+ kAtTextOffset, base::Optional<unsigned>(3));
}
-TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapWithSpace) {
+TEST_F(NGCaretPositionTest, CaretPositionAtSoftLineWrapWithSpace) {
SetInlineFormattingContext("t", "foo bar", 3);
const Node* text = container_->firstChild();
const auto text_fragments = NGInlineFragmentTraversal::SelfFragmentsOf(
@@ -117,18 +118,18 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapWithSpace) {
// Before the space
TEST_CARET(ComputeNGCaretPosition(3, TextAffinity::kDownstream), foo_fragment,
- kAtTextOffset, Optional<unsigned>(3));
+ kAtTextOffset, base::Optional<unsigned>(3));
TEST_CARET(ComputeNGCaretPosition(3, TextAffinity::kUpstream), foo_fragment,
- kAtTextOffset, Optional<unsigned>(3));
+ kAtTextOffset, base::Optional<unsigned>(3));
// After the space
TEST_CARET(ComputeNGCaretPosition(4, TextAffinity::kDownstream), bar_fragment,
- kAtTextOffset, Optional<unsigned>(4));
+ kAtTextOffset, base::Optional<unsigned>(4));
TEST_CARET(ComputeNGCaretPosition(4, TextAffinity::kUpstream), bar_fragment,
- kAtTextOffset, Optional<unsigned>(4));
+ kAtTextOffset, base::Optional<unsigned>(4));
}
-TEST_F(NGCaretRectTest, CaretPositionAtForcedLineBreak) {
+TEST_F(NGCaretPositionTest, CaretPositionAtForcedLineBreak) {
SetInlineFormattingContext("t", "foo<br>bar", 3);
const Node* foo = container_->firstChild();
const Node* br = foo->nextSibling();
@@ -138,18 +139,18 @@ TEST_F(NGCaretRectTest, CaretPositionAtForcedLineBreak) {
// Before the BR
TEST_CARET(ComputeNGCaretPosition(3, TextAffinity::kDownstream), foo_fragment,
- kAtTextOffset, Optional<unsigned>(3));
+ kAtTextOffset, base::Optional<unsigned>(3));
TEST_CARET(ComputeNGCaretPosition(3, TextAffinity::kUpstream), foo_fragment,
- kAtTextOffset, Optional<unsigned>(3));
+ kAtTextOffset, base::Optional<unsigned>(3));
// After the BR
TEST_CARET(ComputeNGCaretPosition(4, TextAffinity::kDownstream), bar_fragment,
- kAtTextOffset, Optional<unsigned>(4));
+ kAtTextOffset, base::Optional<unsigned>(4));
TEST_CARET(ComputeNGCaretPosition(4, TextAffinity::kUpstream), bar_fragment,
- kAtTextOffset, Optional<unsigned>(4));
+ kAtTextOffset, base::Optional<unsigned>(4));
}
-TEST_F(NGCaretRectTest, CaretPositionAtEmptyLine) {
+TEST_F(NGCaretPositionTest, CaretPositionAtEmptyLine) {
SetInlineFormattingContext("f", "foo<br><br>bar", 3);
const Node* foo = container_->firstChild();
const Node* br1 = foo->nextSibling();
@@ -157,30 +158,30 @@ TEST_F(NGCaretRectTest, CaretPositionAtEmptyLine) {
const NGPhysicalFragment* br2_fragment = FragmentOf(br2);
TEST_CARET(ComputeNGCaretPosition(4, TextAffinity::kDownstream), br2_fragment,
- kAtTextOffset, Optional<unsigned>(4));
+ kAtTextOffset, base::Optional<unsigned>(4));
TEST_CARET(ComputeNGCaretPosition(4, TextAffinity::kUpstream), br2_fragment,
- kAtTextOffset, Optional<unsigned>(4));
+ kAtTextOffset, base::Optional<unsigned>(4));
}
-TEST_F(NGCaretRectTest, CaretPositionInOneLineOfImage) {
+TEST_F(NGCaretPositionTest, CaretPositionInOneLineOfImage) {
SetInlineFormattingContext("t", "<img>", 3);
const Node* img = container_->firstChild();
const NGPhysicalFragment* img_fragment = FragmentOf(img);
// Before the image
TEST_CARET(ComputeNGCaretPosition(0, TextAffinity::kDownstream), img_fragment,
- kBeforeBox, WTF::nullopt);
+ kBeforeBox, base::nullopt);
TEST_CARET(ComputeNGCaretPosition(0, TextAffinity::kUpstream), img_fragment,
- kBeforeBox, WTF::nullopt);
+ kBeforeBox, base::nullopt);
// After the image
TEST_CARET(ComputeNGCaretPosition(1, TextAffinity::kDownstream), img_fragment,
- kAfterBox, WTF::nullopt);
+ kAfterBox, base::nullopt);
TEST_CARET(ComputeNGCaretPosition(1, TextAffinity::kUpstream), img_fragment,
- kAfterBox, WTF::nullopt);
+ kAfterBox, base::nullopt);
}
-TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenImages) {
+TEST_F(NGCaretPositionTest, CaretPositionAtSoftLineWrapBetweenImages) {
SetInlineFormattingContext("t",
"<img id=img1><img id=img2>"
"<style>img{width: 1em; height: 1em}</style>",
@@ -191,12 +192,13 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenImages) {
const NGPhysicalFragment* img2_fragment = FragmentOf(img2);
TEST_CARET(ComputeNGCaretPosition(1, TextAffinity::kDownstream),
- img2_fragment, kBeforeBox, WTF::nullopt);
+ img2_fragment, kBeforeBox, base::nullopt);
TEST_CARET(ComputeNGCaretPosition(1, TextAffinity::kUpstream), img1_fragment,
- kAfterBox, WTF::nullopt);
+ kAfterBox, base::nullopt);
}
-TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenMultipleTextNodes) {
+TEST_F(NGCaretPositionTest,
+ CaretPositionAtSoftLineWrapBetweenMultipleTextNodes) {
SetInlineFormattingContext("t",
"<span>A</span>"
"<span>B</span>"
@@ -216,12 +218,12 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenMultipleTextNodes) {
mapping.GetTextContentOffset(wrap_position).value();
TEST_CARET(ComputeNGCaretPosition(wrap_offset, TextAffinity::kUpstream),
- fragment_c, kAtTextOffset, Optional<unsigned>(wrap_offset));
+ fragment_c, kAtTextOffset, base::Optional<unsigned>(wrap_offset));
TEST_CARET(ComputeNGCaretPosition(wrap_offset, TextAffinity::kDownstream),
- fragment_d, kAtTextOffset, Optional<unsigned>(wrap_offset));
+ fragment_d, kAtTextOffset, base::Optional<unsigned>(wrap_offset));
}
-TEST_F(NGCaretRectTest,
+TEST_F(NGCaretPositionTest,
CaretPositionAtSoftLineWrapBetweenMultipleTextNodesRtl) {
SetInlineFormattingContext("t",
"<span>A</span>"
@@ -242,12 +244,12 @@ TEST_F(NGCaretRectTest,
mapping.GetTextContentOffset(wrap_position).value();
TEST_CARET(ComputeNGCaretPosition(wrap_offset, TextAffinity::kUpstream),
- fragment_c, kAtTextOffset, Optional<unsigned>(wrap_offset));
+ fragment_c, kAtTextOffset, base::Optional<unsigned>(wrap_offset));
TEST_CARET(ComputeNGCaretPosition(wrap_offset, TextAffinity::kDownstream),
- fragment_d, kAtTextOffset, Optional<unsigned>(wrap_offset));
+ fragment_d, kAtTextOffset, base::Optional<unsigned>(wrap_offset));
}
-TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenDeepTextNodes) {
+TEST_F(NGCaretPositionTest, CaretPositionAtSoftLineWrapBetweenDeepTextNodes) {
SetInlineFormattingContext(
"t",
"<style>span {border: 1px solid black}</style>"
@@ -269,9 +271,9 @@ TEST_F(NGCaretRectTest, CaretPositionAtSoftLineWrapBetweenDeepTextNodes) {
mapping.GetTextContentOffset(wrap_position).value();
TEST_CARET(ComputeNGCaretPosition(wrap_offset, TextAffinity::kUpstream),
- fragment_c, kAtTextOffset, Optional<unsigned>(wrap_offset));
+ fragment_c, kAtTextOffset, base::Optional<unsigned>(wrap_offset));
TEST_CARET(ComputeNGCaretPosition(wrap_offset, TextAffinity::kDownstream),
- fragment_d, kAtTextOffset, Optional<unsigned>(wrap_offset));
+ fragment_d, kAtTextOffset, base::Optional<unsigned>(wrap_offset));
}
} // namespace blink
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 7b009be5ee1..b0e7e25ba52 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
@@ -5,187 +5,18 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h"
#include "third_party/blink/renderer/core/editing/local_caret_rect.h"
-#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
-#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.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_caret_position.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment_traversal.h"
-#include "third_party/blink/renderer/platform/fonts/character_range.h"
namespace blink {
namespace {
-// -------------------------------------
-
-// Caret position calculation and its helpers.
-
-// The calculation takes the following input:
-// - An inline formatting context as a |LayoutBlockFlow|
-// - An offset in the |text_content_| string of the above context
-// - A TextAffinity
-//
-// The calculation iterates all inline fragments in the context, and tries to
-// compute an NGCaretPosition using the "caret resolution process" below:
-//
-// The (offset, affinity) pair is compared against each inline fragment to see
-// if the corresponding caret should be placed in the fragment, using the
-// |TryResolveCaretPositionInXXX()| functions. These functions may return:
-// - Failed, indicating that the caret must not be placed in the fragment;
-// - Resolved, indicating that the care should be placed in the fragment, and
-// no further search is required. The result NGCaretPosition is returned
-// together.
-// - FoundCandidate, indicating that the caret may be placed in the fragment;
-// however, further search may find a better position. The candidate
-// NGCaretPosition is also returned together.
-
-enum class ResolutionType { kFailed, kFoundCandidate, kResolved };
-struct CaretPositionResolution {
- ResolutionType type = ResolutionType::kFailed;
- NGCaretPosition caret_position;
-};
-
-bool CanResolveCaretPositionBeforeFragment(const NGPaintFragment& fragment,
- TextAffinity affinity) {
- if (affinity == TextAffinity::kDownstream)
- return true;
- const NGPaintFragment* current_line_paint = fragment.ContainerLineBox();
- const NGPhysicalLineBoxFragment& current_line =
- ToNGPhysicalLineBoxFragment(current_line_paint->PhysicalFragment());
- // A fragment after line wrap must be the first logical leaf in its line.
- if (&fragment.PhysicalFragment() != current_line.FirstLogicalLeaf())
- return true;
- const NGPaintFragment* last_line_paint =
- NGPaintFragmentTraversal::PreviousLineOf(*current_line_paint);
- return !last_line_paint ||
- !ToNGPhysicalLineBoxFragment(last_line_paint->PhysicalFragment())
- .HasSoftWrapToNextLine();
-}
-
-bool CanResolveCaretPositionAfterFragment(const NGPaintFragment& fragment,
- TextAffinity affinity) {
- if (affinity == TextAffinity::kUpstream)
- return true;
- const NGPaintFragment* current_line_paint = fragment.ContainerLineBox();
- const NGPhysicalLineBoxFragment& current_line =
- ToNGPhysicalLineBoxFragment(current_line_paint->PhysicalFragment());
- // A fragment before line wrap must be the last logical leaf in its line.
- if (&fragment.PhysicalFragment() != current_line.LastLogicalLeaf())
- return true;
- return !current_line.HasSoftWrapToNextLine();
-}
-
-CaretPositionResolution TryResolveCaretPositionInTextFragment(
- const NGPaintFragment& paint_fragment,
- unsigned offset,
- TextAffinity affinity) {
- DCHECK(paint_fragment.PhysicalFragment().IsText());
- const NGPhysicalTextFragment& fragment =
- ToNGPhysicalTextFragment(paint_fragment.PhysicalFragment());
- if (fragment.IsAnonymousText())
- return CaretPositionResolution();
-
- // [StartOffset(), EndOffset()] is the range allowing caret placement.
- // For example, "foo" has 4 offsets allowing caret placement.
- if (offset < fragment.StartOffset() || offset > fragment.EndOffset()) {
- // TODO(xiaochengh): This may introduce false negatives. Investigate.
- return CaretPositionResolution();
- }
- NGCaretPosition candidate = {&paint_fragment,
- NGCaretPositionType::kAtTextOffset, offset};
-
- // Offsets in the interior of a fragment can be resolved directly.
- if (offset > fragment.StartOffset() && offset < fragment.EndOffset())
- return {ResolutionType::kResolved, candidate};
-
- if (offset == fragment.StartOffset() &&
- CanResolveCaretPositionBeforeFragment(paint_fragment, affinity)) {
- return {ResolutionType::kResolved, candidate};
- }
-
- if (offset == fragment.EndOffset() && !fragment.IsLineBreak() &&
- CanResolveCaretPositionAfterFragment(paint_fragment, affinity)) {
- return {ResolutionType::kResolved, candidate};
- }
-
- // We may have a better candidate
- return {ResolutionType::kFoundCandidate, candidate};
-}
-
-unsigned GetTextOffsetBefore(const NGPhysicalFragment& fragment) {
- // TODO(xiaochengh): Design more straightforward way to get text offset of
- // atomic inline box.
- DCHECK(fragment.IsAtomicInline());
- const Node* node = fragment.GetNode();
- DCHECK(node);
- const Position before_node = Position::BeforeNode(*node);
- Optional<unsigned> maybe_offset_before =
- NGOffsetMapping::GetFor(before_node)->GetTextContentOffset(before_node);
- // We should have offset mapping for atomic inline boxes.
- DCHECK(maybe_offset_before.has_value());
- return maybe_offset_before.value();
-}
-
-CaretPositionResolution TryResolveCaretPositionByBoxFragmentSide(
- const NGPaintFragment& fragment,
- unsigned offset,
- TextAffinity affinity) {
- if (!fragment.GetNode()) {
- // TODO(xiaochengh): This leads to false negatives for, e.g., RUBY, where an
- // anonymous wrapping inline block is created.
- return CaretPositionResolution();
- }
-
- const unsigned offset_before =
- GetTextOffsetBefore(fragment.PhysicalFragment());
- const unsigned offset_after = offset_before + 1;
- if (offset != offset_before && offset != offset_after)
- return CaretPositionResolution();
- const NGCaretPositionType position_type =
- offset == offset_before ? NGCaretPositionType::kBeforeBox
- : NGCaretPositionType::kAfterBox;
- NGCaretPosition candidate{&fragment, position_type, WTF::nullopt};
-
- if (offset == offset_before &&
- CanResolveCaretPositionBeforeFragment(fragment, affinity)) {
- return {ResolutionType::kResolved, candidate};
- }
-
- if (offset == offset_after &&
- CanResolveCaretPositionAfterFragment(fragment, affinity)) {
- return {ResolutionType::kResolved, candidate};
- }
-
- return {ResolutionType::kFoundCandidate, candidate};
-}
-
-CaretPositionResolution TryResolveCaretPositionWithFragment(
- const NGPaintFragment& paint_fragment,
- unsigned offset,
- TextAffinity affinity) {
- const NGPhysicalFragment& fragment = paint_fragment.PhysicalFragment();
- if (fragment.IsText()) {
- return TryResolveCaretPositionInTextFragment(paint_fragment, offset,
- affinity);
- }
- if (fragment.IsBox() && fragment.IsAtomicInline()) {
- return TryResolveCaretPositionByBoxFragmentSide(paint_fragment, offset,
- affinity);
- }
- return CaretPositionResolution();
-}
-
-// -------------------------------------
-
-// Helpers for converting NGCaretPositions to caret rects.
-
NGPhysicalOffsetRect ComputeLocalCaretRectByBoxSide(
- const LayoutBlockFlow& context,
const NGPaintFragment& fragment,
NGCaretPositionType position_type) {
const bool is_horizontal = fragment.Style().IsHorizontalWritingMode();
@@ -203,7 +34,7 @@ NGPhysicalOffsetRect ComputeLocalCaretRectByBoxSide(
fragment.GetLayoutObject()->GetDocument().View();
LayoutUnit caret_width = frame_view->CaretWidth();
- const bool is_ltr = fragment.Style().Direction() == TextDirection::kLtr;
+ const bool is_ltr = IsLtr(fragment.PhysicalFragment().ResolvedDirection());
LayoutUnit caret_left;
if (is_ltr != (position_type == NGCaretPositionType::kBeforeBox)) {
if (is_horizontal)
@@ -223,7 +54,6 @@ NGPhysicalOffsetRect ComputeLocalCaretRectByBoxSide(
}
NGPhysicalOffsetRect ComputeLocalCaretRectAtTextOffset(
- const LayoutBlockFlow& context,
const NGPaintFragment& paint_fragment,
unsigned offset) {
const NGPhysicalTextFragment& fragment =
@@ -255,7 +85,8 @@ NGPhysicalOffsetRect ComputeLocalCaretRectAtTextOffset(
paint_fragment.InlineOffsetToContainerBox();
NGPhysicalSize caret_size(caret_width, caret_height);
- const NGPhysicalBoxFragment& context_fragment = *context.CurrentFragment();
+ const NGPaintFragment& context_fragment =
+ *NGPaintFragment::GetForInlineContainer(fragment.GetLayoutObject());
const NGPaintFragment* line_box = paint_fragment.ContainerLineBox();
const NGPhysicalOffset line_box_offset =
line_box->InlineOffsetToContainerBox();
@@ -284,101 +115,48 @@ NGPhysicalOffsetRect ComputeLocalCaretRectAtTextOffset(
return NGPhysicalOffsetRect(caret_location, caret_size);
}
-LocalCaretRect ComputeLocalCaretRect(const LayoutBlockFlow& context,
- const NGCaretPosition& caret_position) {
+LocalCaretRect ComputeLocalCaretRect(const NGCaretPosition& caret_position) {
if (caret_position.IsNull())
return LocalCaretRect();
+ const NGPaintFragment& fragment = *caret_position.fragment;
+ const LayoutObject* layout_object = fragment.GetLayoutObject();
switch (caret_position.position_type) {
case NGCaretPositionType::kBeforeBox:
case NGCaretPositionType::kAfterBox: {
- DCHECK(caret_position.fragment->PhysicalFragment().IsBox());
+ DCHECK(fragment.PhysicalFragment().IsBox());
const NGPhysicalOffsetRect fragment_local_rect =
- ComputeLocalCaretRectByBoxSide(context, *caret_position.fragment,
+ ComputeLocalCaretRectByBoxSide(fragment,
caret_position.position_type);
- return {caret_position.fragment->GetLayoutObject(),
- fragment_local_rect.ToLayoutRect()};
+ return {layout_object, fragment_local_rect.ToLayoutRect()};
}
case NGCaretPositionType::kAtTextOffset: {
- DCHECK(caret_position.fragment->PhysicalFragment().IsText());
+ DCHECK(fragment.PhysicalFragment().IsText());
DCHECK(caret_position.text_offset.has_value());
const NGPhysicalOffsetRect caret_rect = ComputeLocalCaretRectAtTextOffset(
- context, *caret_position.fragment, *caret_position.text_offset);
-
- return {caret_position.fragment->GetLayoutObject(),
- caret_rect.ToLayoutRect()};
+ fragment, *caret_position.text_offset);
+ LayoutRect layout_rect = caret_rect.ToLayoutRect();
+
+ // For vertical-rl, convert to "flipped block-flow" coordinates space.
+ // See core/layout/README.md#coordinate-spaces for details.
+ if (fragment.Style().IsFlippedBlocksWritingMode()) {
+ const LayoutBlockFlow* container =
+ layout_object->EnclosingNGBlockFlow();
+ container->FlipForWritingMode(layout_rect);
+ }
+
+ return {layout_object, layout_rect};
}
}
NOTREACHED();
- return {caret_position.fragment->GetLayoutObject(), LayoutRect()};
-}
-
-// -------------------------------------
-
-void AssertValidPositionForCaretRectComputation(
- const PositionWithAffinity& position) {
-#if DCHECK_IS_ON()
- DCHECK(NGOffsetMapping::AcceptsPosition(position.GetPosition()));
- const LayoutObject* layout_object = position.AnchorNode()->GetLayoutObject();
- DCHECK(layout_object);
- DCHECK(layout_object->IsText() || layout_object->IsAtomicInlineLevel());
-#endif
+ return {layout_object, LayoutRect()};
}
} // namespace
-// The main function for compute an NGCaretPosition. See the comments at the top
-// of this file for details.
-NGCaretPosition ComputeNGCaretPosition(const LayoutBlockFlow& context,
- unsigned offset,
- TextAffinity affinity) {
- const NGPaintFragment* root_fragment = context.PaintFragment();
- DCHECK(root_fragment);
-
- NGCaretPosition candidate;
- for (const auto& child :
- NGPaintFragmentTraversal::InlineDescendantsOf(*root_fragment)) {
- const CaretPositionResolution resolution =
- TryResolveCaretPositionWithFragment(*child.fragment, offset, affinity);
-
- if (resolution.type == ResolutionType::kFailed)
- continue;
-
- // TODO(xiaochengh): Handle caret poisition in empty container (e.g. empty
- // line box).
-
- if (resolution.type == ResolutionType::kResolved)
- return resolution.caret_position;
-
- DCHECK_EQ(ResolutionType::kFoundCandidate, resolution.type);
- // TODO(xiaochengh): We are not sure if we can ever find multiple
- // candidates. Handle it once reached.
- DCHECK(candidate.IsNull());
- candidate = resolution.caret_position;
- }
-
- return candidate;
-}
-
-LocalCaretRect ComputeNGLocalCaretRect(const LayoutBlockFlow& context,
- const PositionWithAffinity& position) {
- AssertValidPositionForCaretRectComputation(position);
- DCHECK_EQ(&context, NGInlineFormattingContextOf(position.GetPosition()));
- const NGOffsetMapping* mapping = NGOffsetMapping::GetFor(&context);
- DCHECK(mapping);
- const Optional<unsigned> maybe_offset =
- mapping->GetTextContentOffset(position.GetPosition());
- if (!maybe_offset.has_value()) {
- // TODO(xiaochengh): Investigate if we reach here.
- NOTREACHED();
- return LocalCaretRect();
- }
-
- const unsigned offset = maybe_offset.value();
- const TextAffinity affinity = position.Affinity();
- return ComputeLocalCaretRect(
- context, ComputeNGCaretPosition(context, offset, affinity));
+LocalCaretRect ComputeNGLocalCaretRect(const PositionWithAffinity& position) {
+ return ComputeLocalCaretRect(ComputeNGCaretPosition(position));
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h
index 2268a8220c8..4215ef0d6f5 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_caret_rect.h
@@ -5,53 +5,20 @@
#ifndef NGCaretRect_h
#define NGCaretRect_h
+#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/editing/forward.h"
-#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h"
-#include "third_party/blink/renderer/platform/wtf/forward.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink {
// This file provides utility functions for computing caret rect in LayoutNG.
-class NGPaintFragment;
-class LayoutBlockFlow;
struct LocalCaretRect;
-// Given an inline formatting context and a position in the context, returns the
-// caret rect if a caret should be placed at the position, with the given
-// affinity. The caret rect location is local to the given formatting context.
-CORE_EXPORT LocalCaretRect ComputeNGLocalCaretRect(const LayoutBlockFlow&,
- const PositionWithAffinity&);
-
-// An NGCaretPosition indicates a caret position relative to an inline
-// NGPaintFragment:
-// - When |fragment| is box, |position_type| is either |kBeforeBox| or
-// |kAfterBox|, indicating either of the two caret positions by the box sides;
-// |text_offset| is |nullopt| in this case.
-// - When |fragment| is text, |position_type| is |kAtTextOffset|, and
-// |text_offset| is in the text offset range of the fragment.
-//
-// TODO(xiaochengh): Support "in empty container" caret type
-
-enum class NGCaretPositionType { kBeforeBox, kAfterBox, kAtTextOffset };
-struct NGCaretPosition {
- DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
-
- bool IsNull() const { return !fragment; }
-
- const NGPaintFragment* fragment = nullptr; // owned by root LayoutNGMixin
- NGCaretPositionType position_type;
- Optional<unsigned> text_offset;
-};
-
-// Given an inline formatting context, a text offset in the context and a text
-// affinity, returns the corresponding NGCaretPosition, or null if not found.
-// Note that in many cases, null result indicates that we have reached an
-// unexpected case that is not properly handled.
-CORE_EXPORT NGCaretPosition ComputeNGCaretPosition(const LayoutBlockFlow&,
- unsigned,
- TextAffinity);
+// Given a position with affinity, returns the caret rect if the position is
+// laid out with LayoutNG, and a caret can be placed at the position with the
+// given affinity. The caret rect location is local to the containing inline
+// formatting context.
+CORE_EXPORT LocalCaretRect ComputeNGLocalCaretRect(const PositionWithAffinity&);
} // namespace blink
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 3cffb0aab2c..fca16e8c347 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
@@ -274,10 +274,13 @@ void NGInlineLayoutStateStack::AddBoxFragmentPlaceholder(
// 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.
- scoped_refptr<NGLayoutResult> layout_result =
- box_data.CreateBoxFragment(line_box);
offset.inline_offset += box_data.margin_line_left;
- line_box->AddChild(layout_result, offset, box_data.size.inline_size, 0);
+ 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,
+ 0);
box_data_list_.pop_back();
}
}
@@ -365,55 +368,67 @@ LayoutUnit NGInlineLayoutStateStack::ComputeInlinePositions(
if (box_data_list_.IsEmpty())
return position;
- // Create box fragments.
+ // Compute inline positions of inline boxes.
for (auto& box_data : box_data_list_) {
unsigned start = box_data.fragment_start;
unsigned end = box_data.fragment_end;
DCHECK_GT(end, start);
NGLineBoxFragmentBuilder::Child& start_child = (*line_box)[start];
+
// Clamping left offset is not defined, match to the existing behavior.
LayoutUnit line_left_offset =
start_child.offset.inline_offset.ClampNegativeToZero();
LayoutUnit line_right_offset = end < line_box->size()
? (*line_box)[end].offset.inline_offset
: position;
- box_data.offset.inline_offset = line_left_offset;
- box_data.size.inline_size = line_right_offset - line_left_offset;
+ box_data.offset.inline_offset =
+ line_left_offset + box_data.margin_line_left;
+ box_data.size.inline_size =
+ line_right_offset - line_left_offset +
+ box_data.margin_border_padding_line_left - box_data.margin_line_left +
+ box_data.margin_border_padding_line_right - box_data.margin_line_right;
+
+ // Adjust child offsets for margin/border/padding.
+ if (box_data.margin_border_padding_line_left) {
+ line_box->MoveInInlineDirection(box_data.margin_border_padding_line_left,
+ start, line_box->size());
+ position += box_data.margin_border_padding_line_left;
+ }
+
+ if (box_data.margin_border_padding_line_right) {
+ line_box->MoveInInlineDirection(box_data.margin_border_padding_line_right,
+ end, line_box->size());
+ position += box_data.margin_border_padding_line_right;
+ }
+ }
+
+ return position;
+}
+
+void NGInlineLayoutStateStack::CreateBoxFragments(
+ NGLineBoxFragmentBuilder::ChildList* line_box) {
+ DCHECK(!box_data_list_.IsEmpty());
+
+ for (auto& box_data : box_data_list_) {
+ unsigned start = box_data.fragment_start;
+ unsigned end = box_data.fragment_end;
+ DCHECK_GT(end, start);
+ NGLineBoxFragmentBuilder::Child& start_child = (*line_box)[start];
scoped_refptr<NGLayoutResult> box_fragment =
box_data.CreateBoxFragment(line_box);
- NGLogicalOffset offset(line_left_offset + box_data.margin_line_left,
- box_data.offset.block_offset);
if (!start_child.HasFragment()) {
start_child.layout_result = std::move(box_fragment);
- start_child.offset = offset;
+ start_child.offset = box_data.offset;
} 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.
- line_box->InsertChild(start, std::move(box_fragment), offset,
+ line_box->InsertChild(start, std::move(box_fragment), box_data.offset,
LayoutUnit(), 0);
}
-
- // Out-of-flow fragments are left in (start + 1, end). Move them by the left
- // margin/border/padding.
- if (box_data.margin_border_padding_line_left) {
- line_box->MoveInInlineDirection(box_data.margin_border_padding_line_left,
- start + 1, end);
- }
- // Move the rest of children by the inline size the box consumes.
- LayoutUnit margin_border_padding =
- box_data.margin_border_padding_line_left +
- box_data.margin_border_padding_line_right;
- if (margin_border_padding) {
- line_box->MoveInInlineDirection(margin_border_padding, end,
- line_box->size());
- position += margin_border_padding;
- }
}
box_data_list_.clear();
-
- return position;
}
scoped_refptr<NGLayoutResult>
@@ -427,17 +442,12 @@ NGInlineLayoutStateStack::BoxData::CreateBoxFragment(
NGFragmentBuilder box(item->GetLayoutObject(), &style, style.GetWritingMode(),
TextDirection::kLtr);
box.SetBoxType(NGPhysicalFragment::kInlineBox);
+ box.SetStyleVariant(item->StyleVariant());
// Inline boxes have block start/end borders, even when its containing block
// was fragmented. Fragmenting a line box in block direction is not
// supported today.
box.SetBorderEdges({true, has_line_right_edge, true, has_line_left_edge});
- LayoutUnit border_padding_line_left =
- margin_border_padding_line_left - margin_line_left;
- LayoutUnit border_padding_line_right =
- margin_border_padding_line_right - margin_line_right;
- offset.inline_offset -= border_padding_line_left;
- size.inline_size += border_padding_line_left + border_padding_line_right;
box.SetInlineSize(size.inline_size.ClampNegativeToZero());
box.SetBlockSize(size.block_size);
box.SetPadding(padding);
@@ -462,7 +472,9 @@ NGInlineLayoutStateStack::ApplyBaselineShift(
NGInlineBoxState* box,
NGLineBoxFragmentBuilder::ChildList* line_box,
FontBaseline baseline_type) {
- // Compute descendants that depend on the layout size of this box if any.
+ // Some 'vertical-align' values require the size of their parents. Align all
+ // such descendant boxes that require the size of this box; they are queued in
+ // |pending_descendants|.
LayoutUnit baseline_shift;
if (!box->pending_descendants.IsEmpty()) {
for (auto& child : box->pending_descendants) {
@@ -514,9 +526,15 @@ NGInlineLayoutStateStack::ApplyBaselineShift(
if (vertical_align == EVerticalAlign::kBaseline)
return kPositionNotPending;
- // 'vertical-align' aplies only to inline-level elements.
+ // 'vertical-align' aligns boxes relative to themselves, to their parent
+ // boxes, or to the line box, depends on the value.
+ // Because |box| is an item in |stack_|, |box[-1]| is its parent box.
+ // If this box doesn't have a parent; i.e., this box is a line box,
+ // 'vertical-align' has no effect.
+ DCHECK(box >= stack_.begin() && box < stack_.end());
if (box == stack_.begin())
return kPositionNotPending;
+ NGInlineBoxState& parent_box = box[-1];
// Check if there are any fragments to move.
unsigned fragment_end = line_box->size();
@@ -525,10 +543,10 @@ NGInlineLayoutStateStack::ApplyBaselineShift(
switch (vertical_align) {
case EVerticalAlign::kSub:
- baseline_shift = style.ComputedFontSizeAsFixed() / 5 + 1;
+ baseline_shift = parent_box.style->ComputedFontSizeAsFixed() / 5 + 1;
break;
case EVerticalAlign::kSuper:
- baseline_shift = -(style.ComputedFontSizeAsFixed() / 3 + 1);
+ baseline_shift = -(parent_box.style->ComputedFontSizeAsFixed() / 3 + 1);
break;
case EVerticalAlign::kLength: {
// 'Percentages: refer to the 'line-height' of the element itself'.
@@ -542,9 +560,10 @@ NGInlineLayoutStateStack::ApplyBaselineShift(
}
case EVerticalAlign::kMiddle:
baseline_shift = (box->metrics.ascent - box->metrics.descent) / 2;
- if (const SimpleFontData* font_data = style.GetFont().PrimaryFont()) {
+ if (const SimpleFontData* parent_font_data =
+ parent_box.style->GetFont().PrimaryFont()) {
baseline_shift -= LayoutUnit::FromFloatRound(
- font_data->GetFontMetrics().XHeight() / 2);
+ parent_font_data->GetFontMetrics().XHeight() / 2);
}
break;
case EVerticalAlign::kBaselineMiddle:
@@ -558,8 +577,7 @@ NGInlineLayoutStateStack::ApplyBaselineShift(
return kPositionPending;
default:
// Other values require the layout size of the parent box.
- SECURITY_CHECK(box != stack_.begin());
- box[-1].pending_descendants.push_back(NGPendingPositions{
+ parent_box.pending_descendants.push_back(NGPendingPositions{
box->fragment_start, fragment_end, box->metrics, vertical_align});
return kPositionPending;
}
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 68fd6c23673..626ad129d87 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,6 @@
#ifndef NGInlineBoxState_h
#define NGInlineBoxState_h
-#include "third_party/blink/renderer/core/layout/ng/geometry/ng_border_edges.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.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"
@@ -140,10 +139,13 @@ class CORE_EXPORT NGInlineLayoutStateStack {
// reordering.
void UpdateAfterReorder(NGLineBoxFragmentBuilder::ChildList*);
- // Compute inline positions of fragments. Also creates box fragments if
- // needed.
+ // Compute inline positions of fragments and boxes.
LayoutUnit ComputeInlinePositions(NGLineBoxFragmentBuilder::ChildList*);
+ // Create box fragments. This function turns a flat list of children into
+ // a box tree.
+ void CreateBoxFragments(NGLineBoxFragmentBuilder::ChildList*);
+
private:
// End of a box state, either explicitly by close tag, or implicitly at the
// end of a line.
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 870af1c1802..353acbabc68 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
@@ -24,6 +24,9 @@ void CollectInlineFragments(const NGPhysicalContainerFragment& container,
NGPhysicalOffset offset_to_container_box,
Filter& filter,
Vector<Result, inline_capacity>* results) {
+ DCHECK(container.IsInline() || container.IsLineBox() ||
+ (container.IsBlockFlow() &&
+ ToNGPhysicalBoxFragment(container).ChildrenInline()));
for (const auto& child : container.Children()) {
NGPhysicalOffset child_offset = child->Offset() + offset_to_container_box;
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 fe68677cdc2..40bf8c8431a 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
@@ -64,7 +64,7 @@ TEST_F(NGInlineFragmentTraversalTest, DescendantsOf) {
"<div id=t>foo<b id=b>bar</b><br>baz</div>");
const auto descendants =
NGInlineFragmentTraversal::DescendantsOf(GetRootFragmentById("t"));
- auto iter = descendants.begin();
+ auto* iter = descendants.begin();
EXPECT_NEXT_LINE_BOX(iter);
EXPECT_NEXT_TEXT(iter, "foo");
@@ -82,7 +82,7 @@ TEST_F(NGInlineFragmentTraversalTest, InclusiveDescendantsOf) {
"<div id=t>foo<b id=b>bar</b><br>baz</div>");
auto descendants = NGInlineFragmentTraversal::InclusiveDescendantsOf(
GetRootFragmentById("t"));
- auto iter = descendants.begin();
+ auto* iter = descendants.begin();
EXPECT_NEXT_BOX(iter, "t");
EXPECT_NEXT_LINE_BOX(iter);
@@ -102,7 +102,7 @@ TEST_F(NGInlineFragmentTraversalTest, SelfFragmentsOf) {
const auto descendants = NGInlineFragmentTraversal::SelfFragmentsOf(
GetRootFragmentById("t"), GetLayoutObjectByElementId("filter"));
- auto iter = descendants.begin();
+ auto* iter = descendants.begin();
// <b> generates two box fragments since its content is in two lines.
EXPECT_NEXT_BOX(iter, "filter");
@@ -123,7 +123,7 @@ TEST_F(NGInlineFragmentTraversalTest, AncestorsOf) {
const NGPhysicalFragment& target =
GetFragmentOfNode(root, GetElementById("target")->firstChild());
auto ancestors = NGInlineFragmentTraversal::AncestorsOf(root, target);
- auto iter = ancestors.begin();
+ auto* iter = ancestors.begin();
EXPECT_NEXT_BOX(iter, "target");
EXPECT_NEXT_BOX(iter, "i");
@@ -143,7 +143,7 @@ TEST_F(NGInlineFragmentTraversalTest, InclusiveAncestorsOf) {
GetFragmentOfNode(root, GetElementById("target")->firstChild());
auto ancestors =
NGInlineFragmentTraversal::InclusiveAncestorsOf(root, target);
- auto iter = ancestors.begin();
+ auto* iter = ancestors.begin();
EXPECT_NEXT_TEXT(iter, "foo");
EXPECT_NEXT_BOX(iter, "target");
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 42fd483de3d..8e5a6288ddf 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
@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
-#include "third_party/blink/renderer/platform/fonts/character_range.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_buffer.h"
namespace blink {
@@ -44,7 +43,8 @@ NGInlineItem::NGInlineItem(NGInlineItemType type,
unsigned start,
unsigned end,
const ComputedStyle* style,
- LayoutObject* layout_object)
+ LayoutObject* layout_object,
+ bool end_may_collapse)
: start_offset_(start),
end_offset_(end),
script_(USCRIPT_INVALID_CODE),
@@ -56,11 +56,33 @@ NGInlineItem::NGInlineItem(NGInlineItemType type,
is_empty_item_(false),
should_create_box_fragment_(false),
style_variant_(static_cast<unsigned>(NGStyleVariant::kStandard)),
- end_collapse_type_(kNotCollapsible) {
+ end_collapse_type_(kNotCollapsible),
+ end_may_collapse_(end_may_collapse) {
DCHECK_GE(end, start);
ComputeBoxProperties();
}
+NGInlineItem::NGInlineItem(const NGInlineItem& other,
+ unsigned start,
+ unsigned end,
+ scoped_refptr<const ShapeResult> shape_result)
+ : start_offset_(start),
+ end_offset_(end),
+ script_(other.script_),
+ shape_result_(shape_result),
+ style_(other.style_),
+ layout_object_(other.layout_object_),
+ type_(other.type_),
+ bidi_level_(other.bidi_level_),
+ shape_options_(other.shape_options_),
+ is_empty_item_(other.is_empty_item_),
+ should_create_box_fragment_(other.should_create_box_fragment_),
+ style_variant_(other.style_variant_),
+ end_collapse_type_(other.end_collapse_type_),
+ end_may_collapse_(other.end_may_collapse_) {
+ DCHECK_GE(end, start);
+}
+
NGInlineItem::~NGInlineItem() = default;
void NGInlineItem::ComputeBoxProperties() {
@@ -82,7 +104,7 @@ void NGInlineItem::ComputeBoxProperties() {
should_create_box_fragment_ =
ToLayoutBoxModelObject(layout_object_)->HasSelfPaintingLayer() ||
style_->HasOutline() || style_->CanContainAbsolutePositionObjects() ||
- style_->CanContainFixedPositionObjects();
+ style_->CanContainFixedPositionObjects(false);
}
return;
}
@@ -99,6 +121,13 @@ const char* NGInlineItem::NGInlineItemTypeToString(int val) const {
return kNGInlineItemTypeStrings[val];
}
+void NGInlineItem::SetBidiLevel(UBiDiLevel level) {
+ // Invalidate ShapeResult because it depends on the resolved direction.
+ if (DirectionFromLevel(level) != DirectionFromLevel(bidi_level_))
+ shape_result_ = nullptr;
+ bidi_level_ = level;
+}
+
// Set bidi level to a list of NGInlineItem from |index| to the item that ends
// with |end_offset|.
// If |end_offset| is mid of an item, the item is split to ensure each item has
@@ -113,14 +142,14 @@ unsigned NGInlineItem::SetBidiLevel(Vector<NGInlineItem>& items,
unsigned end_offset,
UBiDiLevel level) {
for (; items[index].end_offset_ < end_offset; index++)
- items[index].bidi_level_ = level;
- items[index].bidi_level_ = level;
+ items[index].SetBidiLevel(level);
+ items[index].SetBidiLevel(level);
if (items[index].end_offset_ == end_offset) {
// Let close items have the same bidi-level as the previous item.
while (index + 1 < items.size() &&
items[index + 1].Type() == NGInlineItem::kCloseTag) {
- items[++index].bidi_level_ = level;
+ items[++index].SetBidiLevel(level);
}
} else {
Split(items, index, end_offset);
@@ -152,6 +181,7 @@ void NGInlineItem::Split(Vector<NGInlineItem>& items,
unsigned offset) {
DCHECK_GT(offset, items[index].start_offset_);
DCHECK_LT(offset, items[index].end_offset_);
+ items[index].shape_result_ = nullptr;
items.insert(index + 1, items[index]);
items[index].end_offset_ = offset;
items[index + 1].start_offset_ = offset;
@@ -161,11 +191,15 @@ void NGInlineItem::SetOffset(unsigned start, unsigned end) {
DCHECK_GE(end, start);
start_offset_ = start;
end_offset_ = end;
+ // Any modification to the offset will invalidate the shape result.
+ shape_result_ = nullptr;
}
void NGInlineItem::SetEndOffset(unsigned end_offset) {
DCHECK_GE(end_offset, start_offset_);
end_offset_ = end_offset;
+ // Any modification to the offset will invalidate the shape result.
+ shape_result_ = nullptr;
}
bool NGInlineItem::HasStartEdge() const {
@@ -181,14 +215,4 @@ bool NGInlineItem::HasEndEdge() const {
!ToLayoutInline(GetLayoutObject())->Continuation();
}
-NGInlineItemRange::NGInlineItemRange(Vector<NGInlineItem>* items,
- unsigned start_index,
- unsigned end_index)
- : start_item_(&(*items)[start_index]),
- size_(end_index - start_index),
- start_index_(start_index) {
- CHECK_LE(start_index, end_index);
- CHECK_LE(end_index, items->size());
-}
-
} // 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 d9b183b3e0b..1b40a3a53d7 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
@@ -6,19 +6,17 @@
#define NGInlineItem_h
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
#include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
-#include "third_party/blink/renderer/platform/fonts/font_fallback_priority.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
-#include "third_party/blink/renderer/platform/fonts/simple_font_data.h"
-#include "third_party/blink/renderer/platform/layout_unit.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
#include <unicode/ubidi.h>
+#include <unicode/uscript.h>
namespace blink {
-class ComputedStyle;
class LayoutObject;
// Class representing a single text node or styled inline element with text
@@ -66,9 +64,16 @@ class CORE_EXPORT NGInlineItem {
unsigned start,
unsigned end,
const ComputedStyle* style = nullptr,
- LayoutObject* layout_object = nullptr);
+ LayoutObject* layout_object = nullptr,
+ bool end_may_collapse = false);
~NGInlineItem();
+ // Copy constructor adjusting start/end and shape results.
+ NGInlineItem(const NGInlineItem&,
+ unsigned adjusted_start,
+ unsigned adjusted_end,
+ scoped_refptr<const ShapeResult>);
+
NGInlineItemType Type() const { return static_cast<NGInlineItemType>(type_); }
const char* NGInlineItemTypeToString(int val) const;
@@ -118,7 +123,13 @@ class CORE_EXPORT NGInlineItem {
}
void SetEndCollapseType(NGCollapseType type) { end_collapse_type_ = type; }
+ // Whether the item may be affected by whitespace collapsing. Unlike the
+ // EndCollapseType() method this returns true even if a trailing space has
+ // been removed.
+ bool EndMayCollapse() const { return end_may_collapse_; }
+
static void Split(Vector<NGInlineItem>&, unsigned index, unsigned offset);
+ void SetBidiLevel(UBiDiLevel);
static unsigned SetBidiLevel(Vector<NGInlineItem>&,
unsigned index,
unsigned end_offset,
@@ -146,6 +157,7 @@ class CORE_EXPORT NGInlineItem {
unsigned should_create_box_fragment_ : 1;
unsigned style_variant_ : 2;
unsigned end_collapse_type_ : 2; // NGCollapseType
+ unsigned end_may_collapse_ : 1;
friend class NGInlineNode;
};
@@ -159,41 +171,23 @@ inline void NGInlineItem::AssertEndOffset(unsigned offset) const {
DCHECK_LE(offset, end_offset_);
}
-// A vector-like object that points to a subset of an array of |NGInlineItem|.
-// The source vector must keep alive and must not resize while this object
-// is alive.
-class NGInlineItemRange {
- STACK_ALLOCATED();
-
- public:
- NGInlineItemRange(Vector<NGInlineItem>*,
- unsigned start_index,
- unsigned end_index);
+// Represents a text content with a list of NGInlineItem. A node may have an
+// additional NGInlineItemsData for ::first-line pseudo element.
+struct CORE_EXPORT NGInlineItemsData {
+ // Text content for all inline items represented by a single NGInlineNode.
+ // Encoded either as UTF-16 or latin-1 depending on the content.
+ String text_content;
+ Vector<NGInlineItem> items;
- unsigned StartIndex() const { return start_index_; }
- unsigned EndIndex() const { return start_index_ + size_; }
- unsigned Size() const { return size_; }
+ // The DOM to text content offset mapping of this inline node.
+ std::unique_ptr<NGOffsetMapping> offset_mapping;
- NGInlineItem& operator[](unsigned index) {
- CHECK_LT(index, size_);
- return start_item_[index];
+ void AssertOffset(unsigned index, unsigned offset) const {
+ items[index].AssertOffset(offset);
}
- const NGInlineItem& operator[](unsigned index) const {
- CHECK_LT(index, size_);
- return start_item_[index];
+ void AssertEndOffset(unsigned index, unsigned offset) const {
+ items[index].AssertEndOffset(offset);
}
-
- using iterator = NGInlineItem*;
- using const_iterator = const NGInlineItem*;
- iterator begin() { return start_item_; }
- iterator end() { return start_item_ + size_; }
- const_iterator begin() const { return start_item_; }
- const_iterator end() const { return start_item_ + size_; }
-
- private:
- NGInlineItem* start_item_;
- unsigned size_;
- unsigned start_index_;
};
} // namespace blink
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 74e3e3ca598..43cdd7b803a 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
@@ -19,14 +19,14 @@ NGInlineItemResult::NGInlineItemResult(const NGInlineItem* item,
: item(item), item_index(index), start_offset(start), end_offset(end) {}
void NGLineInfo::SetLineStyle(const NGInlineNode& node,
+ const NGInlineItemsData& items_data,
const NGConstraintSpace& constraint_space,
bool is_first_line,
+ bool use_first_line_style,
bool is_after_forced_break) {
- LayoutObject* layout_object = node.GetLayoutObject();
- use_first_line_style_ =
- is_first_line &&
- layout_object->GetDocument().GetStyleEngine().UsesFirstLineRules();
- line_style_ = layout_object->Style(use_first_line_style_);
+ use_first_line_style_ = use_first_line_style;
+ items_data_ = &items_data;
+ line_style_ = node.GetLayoutObject()->Style(use_first_line_style_);
if (line_style_->ShouldUseTextIndent(is_first_line, is_after_forced_break)) {
// 'text-indent' applies to block container, and percentage is of its
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 401e52a0a54..514ae11066d 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
@@ -19,6 +19,8 @@ class NGConstraintSpace;
class NGInlineItem;
class NGInlineNode;
+struct NGInlineItemsData;
+
// The result of measuring NGInlineItem.
//
// This is a transient context object only while building line boxes.
@@ -106,14 +108,21 @@ class CORE_EXPORT NGLineInfo {
NGLineInfo() = default;
explicit NGLineInfo(size_t capacity) : results_(capacity) {}
+ const NGInlineItemsData& ItemsData() const {
+ DCHECK(items_data_);
+ return *items_data_;
+ }
+
// The style to use for the line.
const ComputedStyle& LineStyle() const {
DCHECK(line_style_);
return *line_style_;
}
void SetLineStyle(const NGInlineNode&,
+ const NGInlineItemsData&,
const NGConstraintSpace&,
- bool is_first_line,
+ bool is_first_formatted_line,
+ bool use_first_line_style,
bool is_after_forced_break);
// Use ::first-line style if true.
@@ -158,6 +167,7 @@ class CORE_EXPORT NGLineInfo {
void SetLineEndFragment(scoped_refptr<NGPhysicalTextFragment>);
private:
+ const NGInlineItemsData* items_data_ = nullptr;
const ComputedStyle* line_style_ = nullptr;
NGInlineItemResults results_;
scoped_refptr<NGPhysicalTextFragment> line_end_fragment_;
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 be19e467b59..7fad403e72e 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
@@ -20,27 +20,46 @@ NGInlineItemsBuilderTemplate<
template <typename OffsetMappingBuilder>
String NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::ToString() {
- // Segment Break Transformation Rules[1] defines to keep trailing new lines,
- // but it will be removed in Phase II[2]. We prefer not to add trailing new
- // lines and collapsible spaces in Phase I.
+ // Segment Break Transformation Rules[1] defines to keep trailing new lines in
+ // Phase I, but to remove after line break, in Phase II[2]. Although the spec
+ // defines so, trailing collapsible spaces at the end of an inline formatting
+ // context will be removed in Phase II and that removing here makes no
+ // differences.
+ //
+ // However, doing so reduces the opportunities to re-use NGInlineItem a lot in
+ // appending scenario, which is quite common. In order to re-use NGInlineItem
+ // as much as posssible, trailing spaces are removed in Phase II, exactly as
+ // defined in the spec.
+ //
// [1] https://drafts.csswg.org/css-text-3/#line-break-transform
// [2] https://drafts.csswg.org/css-text-3/#white-space-phase-2
+ return text_.ToString();
+}
+
+template <>
+String NGInlineItemsBuilderTemplate<NGOffsetMappingBuilder>::ToString() {
+ // While trailing collapsible space is kept as above, NGOffsetMappingBuilder
+ // assumes NGLineBreaker does not remove it. For now, remove only for
+ // NGOffsetMappingBuilder.
+ // TODO(kojii): Consider NGOffsetMappingBuilder to support NGLineBreaker to
+ // remove trailing spaces.
RemoveTrailingCollapsibleSpaceIfExists();
return text_.ToString();
}
+namespace {
// Determine "Ambiguous" East Asian Width is Wide or Narrow.
// Unicode East Asian Width
// http://unicode.org/reports/tr11/
-static bool IsAmbiguosEastAsianWidthWide(const ComputedStyle* style) {
+bool IsAmbiguosEastAsianWidthWide(const ComputedStyle* style) {
UScriptCode script = style->GetFontDescription().GetScript();
return script == USCRIPT_KATAKANA_OR_HIRAGANA ||
script == USCRIPT_SIMPLIFIED_HAN || script == USCRIPT_TRADITIONAL_HAN;
}
// Determine if a character has "Wide" East Asian Width.
-static bool IsEastAsianWidthWide(UChar32 c, const ComputedStyle* style) {
+bool IsEastAsianWidthWide(UChar32 c, const ComputedStyle* style) {
UEastAsianWidth eaw = static_cast<UEastAsianWidth>(
u_getIntPropertyValue(c, UCHAR_EAST_ASIAN_WIDTH));
return eaw == U_EA_WIDE || eaw == U_EA_FULLWIDTH || eaw == U_EA_HALFWIDTH ||
@@ -51,11 +70,11 @@ static bool IsEastAsianWidthWide(UChar32 c, const ComputedStyle* style) {
// Determine whether a newline should be removed or not.
// CSS Text, Segment Break Transformation Rules
// https://drafts.csswg.org/css-text-3/#line-break-transform
-static bool ShouldRemoveNewlineSlow(const StringBuilder& before,
- unsigned space_index,
- const ComputedStyle* before_style,
- const StringView& after,
- const ComputedStyle* after_style) {
+bool ShouldRemoveNewlineSlow(const StringBuilder& before,
+ unsigned space_index,
+ const ComputedStyle* before_style,
+ const StringView& after,
+ const ComputedStyle* after_style) {
// Remove if either before/after the newline is zeroWidthSpaceCharacter.
UChar32 last = 0;
DCHECK(space_index == before.length() ||
@@ -95,27 +114,29 @@ static bool ShouldRemoveNewlineSlow(const StringBuilder& before,
return false;
}
-static bool ShouldRemoveNewline(const StringBuilder& before,
- unsigned space_index,
- const ComputedStyle* before_style,
- const StringView& after,
- const ComputedStyle* after_style) {
+bool ShouldRemoveNewline(const StringBuilder& before,
+ unsigned space_index,
+ const ComputedStyle* before_style,
+ const StringView& after,
+ const ComputedStyle* after_style) {
// All characters before/after removable newline are 16 bits.
return (!before.Is8Bit() || !after.Is8Bit()) &&
ShouldRemoveNewlineSlow(before, space_index, before_style, after,
after_style);
}
-static void AppendItem(Vector<NGInlineItem>* items,
- NGInlineItem::NGInlineItemType type,
- unsigned start,
- unsigned end,
- const ComputedStyle* style = nullptr,
- LayoutObject* layout_object = nullptr) {
- items->push_back(NGInlineItem(type, start, end, style, layout_object));
+void AppendItem(Vector<NGInlineItem>* items,
+ NGInlineItem::NGInlineItemType type,
+ unsigned start,
+ unsigned end,
+ const ComputedStyle* style = nullptr,
+ LayoutObject* layout_object = nullptr,
+ bool end_may_collapse = false) {
+ items->push_back(
+ NGInlineItem(type, start, end, style, layout_object, end_may_collapse));
}
-static inline bool ShouldIgnore(UChar c) {
+inline bool ShouldIgnore(UChar c) {
// Ignore carriage return and form feed.
// https://drafts.csswg.org/css-text-3/#white-space-processing
// https://github.com/w3c/csswg-drafts/issues/855
@@ -126,14 +147,14 @@ static inline bool ShouldIgnore(UChar c) {
return c == kCarriageReturnCharacter || c == kFormFeedCharacter;
}
-static inline bool IsCollapsibleSpace(UChar c) {
+inline bool IsCollapsibleSpace(UChar c) {
return c == kSpaceCharacter || c == kNewlineCharacter ||
c == kTabulationCharacter || c == kCarriageReturnCharacter;
}
// Characters needing a separate control item than other text items.
// It makes the line breaker easier to handle.
-static inline bool IsControlItemCharacter(UChar c) {
+inline bool IsControlItemCharacter(UChar c) {
return c == kNewlineCharacter || c == kTabulationCharacter ||
// Include ignorable character here to avoids shaping/rendering
// these glyphs, and to help the line breaker to ignore them.
@@ -143,9 +164,9 @@ static inline bool IsControlItemCharacter(UChar c) {
// Find the end of the collapsible spaces.
// Returns whether this space run contains a newline or not, because it changes
// the collapsing behavior.
-static inline bool MoveToEndOfCollapsibleSpaces(const StringView& string,
- unsigned* offset,
- UChar* c) {
+inline bool MoveToEndOfCollapsibleSpaces(const StringView& string,
+ unsigned* offset,
+ UChar* c) {
DCHECK_EQ(*c, string[*offset]);
DCHECK(IsCollapsibleSpace(*c));
bool space_run_has_newline = *c == kNewlineCharacter;
@@ -161,7 +182,7 @@ static inline bool MoveToEndOfCollapsibleSpaces(const StringView& string,
// Find the last item to compute collapsing with. Opaque items such as
// open/close or bidi controls are ignored.
// Returns nullptr if there were no previous items.
-static NGInlineItem* LastItemToCollapseWith(Vector<NGInlineItem>* items) {
+NGInlineItem* LastItemToCollapseWith(Vector<NGInlineItem>* items) {
for (auto it = items->rbegin(); it != items->rend(); it++) {
NGInlineItem& item = *it;
if (item.EndCollapseType() != NGInlineItem::kOpaqueToCollapsing)
@@ -170,6 +191,66 @@ static NGInlineItem* LastItemToCollapseWith(Vector<NGInlineItem>* items) {
return nullptr;
}
+inline bool MayCollapseWithLast(const NGInlineItem* item) {
+ return item && item->EndMayCollapse();
+}
+
+} // anonymous namespace
+
+template <typename OffsetMappingBuilder>
+bool NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::Append(
+ const String& original_string,
+ LayoutObject* layout_object,
+ const Vector<NGInlineItem*>& items) {
+ // Don't reuse existing items if they might be affected by whitespace
+ // collapsing.
+ // TODO(layout-dev): This could likely be optimized further.
+ // TODO(layout-dev): Handle cases where the old items are not consecutive.
+ if (MayCollapseWithLast(LastItemToCollapseWith(items_)) ||
+ IsCollapsibleSpace(original_string[items[0]->StartOffset()]))
+ return false;
+
+ for (const NGInlineItem* item : items) {
+ unsigned start = text_.length();
+ text_.Append(original_string, item->StartOffset(), item->Length());
+
+ // If the item's position within the container remains unchanged the item
+ // itself may be reused.
+ if (item->StartOffset() == start) {
+ items_->push_back(*item);
+ is_empty_inline_ &= item->IsEmptyItem();
+ continue;
+ }
+
+ // If the position has shifted the item and the shape result needs to be
+ // adjusted to reflect the new start and end offsets.
+ unsigned end = start + item->Length();
+ DCHECK(item->TextShapeResult());
+ NGInlineItem adjusted_item(
+ *item, start, end, item->TextShapeResult()->CopyAdjustedOffset(start));
+
+ DCHECK(adjusted_item.TextShapeResult());
+ DCHECK_EQ(start, adjusted_item.StartOffset());
+ DCHECK_EQ(start, adjusted_item.TextShapeResult()->StartIndexForResult());
+ DCHECK_EQ(end, adjusted_item.EndOffset());
+ DCHECK_EQ(end, adjusted_item.TextShapeResult()->EndIndexForResult());
+ DCHECK_EQ(item->IsEmptyItem(), adjusted_item.IsEmptyItem());
+
+ items_->push_back(adjusted_item);
+ is_empty_inline_ &= adjusted_item.IsEmptyItem();
+ }
+ return true;
+}
+
+template <>
+bool NGInlineItemsBuilderTemplate<NGOffsetMappingBuilder>::Append(
+ const String&,
+ LayoutObject*,
+ const Vector<NGInlineItem*>&) {
+ NOTREACHED();
+ return false;
+}
+
template <typename OffsetMappingBuilder>
void NGInlineItemsBuilderTemplate<OffsetMappingBuilder>::Append(
const String& string,
@@ -371,7 +452,7 @@ void NGInlineItemsBuilderTemplate<
if (text_.length() > start_offset) {
AppendItem(items_, NGInlineItem::kText, start_offset, text_.length(), style,
- layout_object);
+ layout_object, end_collapse != NGInlineItem::kNotCollapsible);
NGInlineItem& item = items_->back();
item.SetEndCollapseType(end_collapse);
is_empty_inline_ &= item.IsEmptyItem();
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 f041c6b9f63..53e34b6cef3 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
@@ -19,7 +19,6 @@ namespace blink {
class ComputedStyle;
class LayoutObject;
class LayoutText;
-class NGInlineItem;
// NGInlineItemsBuilder builds a string and a list of NGInlineItem from inlines.
//
@@ -54,6 +53,12 @@ class CORE_TEMPLATE_CLASS_EXPORT NGInlineItemsBuilderTemplate {
// <span></span> or <span><float></float></span>.
bool IsEmptyInline() const { return is_empty_inline_; }
+ // Append existing items from an unchanged LayoutObject.
+ // Returns whether the existing items could be reused.
+ // NOTE: The state of the builder remains unchanged if the append operation
+ // fails (i.e. if it returns false).
+ bool Append(const String&, LayoutObject*, const Vector<NGInlineItem*>&);
+
// Append a string.
// When appending, spaces are collapsed according to CSS Text, The white space
// processing rules
@@ -149,6 +154,15 @@ class CORE_TEMPLATE_CLASS_EXPORT NGInlineItemsBuilderTemplate {
void Exit(LayoutObject*);
};
+template <>
+String NGInlineItemsBuilderTemplate<NGOffsetMappingBuilder>::ToString();
+
+template <>
+bool NGInlineItemsBuilderTemplate<NGOffsetMappingBuilder>::Append(
+ const String&,
+ LayoutObject*,
+ const Vector<NGInlineItem*>&);
+
extern template class CORE_EXTERN_TEMPLATE_EXPORT
NGInlineItemsBuilderTemplate<EmptyOffsetMappingBuilder>;
extern template class CORE_EXTERN_TEMPLATE_EXPORT
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 d3b4b9eff09..ae5a273962c 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
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/core/testing/page_test_base.h"
namespace blink {
@@ -18,13 +19,6 @@ namespace {
EXPECT_EQ(start, (item).StartOffset()); \
EXPECT_EQ(end, (item).EndOffset());
-static scoped_refptr<ComputedStyle> CreateWhitespaceStyle(
- EWhiteSpace whitespace) {
- scoped_refptr<ComputedStyle> style(ComputedStyle::Create());
- style->SetWhiteSpace(whitespace);
- return style;
-}
-
static String GetCollapsed(const NGOffsetMappingBuilder& builder) {
Vector<unsigned> mapping = builder.DumpOffsetMappingForTesting();
@@ -47,40 +41,60 @@ static String GetCollapsed(const NGOffsetMappingBuilder& builder) {
return result.ToString();
}
-class NGInlineItemsBuilderTest : public testing::Test {
+class NGInlineItemsBuilderTest : public PageTestBase {
protected:
- void SetUp() override { style_ = ComputedStyle::Create(); }
+ void SetUp() override {
+ PageTestBase::SetUp();
+ style_ = ComputedStyle::Create();
+ }
void SetWhiteSpace(EWhiteSpace whitespace) {
style_->SetWhiteSpace(whitespace);
}
- const String& TestAppend(const String inputs[], int size) {
+ scoped_refptr<ComputedStyle> GetStyle(EWhiteSpace whitespace) {
+ if (whitespace == EWhiteSpace::kNormal)
+ return style_;
+ scoped_refptr<ComputedStyle> style(ComputedStyle::Create());
+ style->SetWhiteSpace(whitespace);
+ return style;
+ }
+
+ struct Input {
+ const String text;
+ EWhiteSpace whitespace = EWhiteSpace::kNormal;
+ LayoutText* layout_text = nullptr;
+ };
+
+ const String& TestAppend(Vector<Input> inputs) {
items_.clear();
NGInlineItemsBuilderForOffsetMapping builder(&items_);
- for (int i = 0; i < size; i++)
- builder.Append(inputs[i], style_.get());
+ for (Input& input : inputs) {
+ if (!input.layout_text)
+ input.layout_text = LayoutText::CreateEmptyAnonymous(GetDocument());
+ builder.Append(input.text, GetStyle(input.whitespace).get(),
+ input.layout_text);
+ }
text_ = builder.ToString();
collapsed_ = GetCollapsed(builder.GetOffsetMappingBuilder());
ValidateItems();
+ CheckReuseItemsProducesSameResult(inputs);
return text_;
}
const String& TestAppend(const String& input) {
- String inputs[] = {input};
- return TestAppend(inputs, 1);
+ return TestAppend({Input{input}});
+ }
+ const String& TestAppend(const Input& input1, const Input& input2) {
+ return TestAppend({input1, input2});
}
-
const String& TestAppend(const String& input1, const String& input2) {
- String inputs[] = {input1, input2};
- return TestAppend(inputs, 2);
+ return TestAppend(Input{input1}, Input{input2});
}
-
const String& TestAppend(const String& input1,
const String& input2,
const String& input3) {
- String inputs[] = {input1, input2, input3};
- return TestAppend(inputs, 3);
+ return TestAppend({{input1}, {input2}, {input3}});
}
void ValidateItems() {
@@ -94,6 +108,35 @@ class NGInlineItemsBuilderTest : public testing::Test {
EXPECT_EQ(current_offset, text_.length());
}
+ void CheckReuseItemsProducesSameResult(Vector<Input> inputs) {
+ Vector<NGInlineItem> reuse_items;
+ NGInlineItemsBuilder reuse_builder(&reuse_items);
+ for (Input& input : inputs) {
+ // Collect items for this LayoutObject.
+ DCHECK(input.layout_text);
+ Vector<NGInlineItem*> previous_items;
+ for (auto& item : items_) {
+ if (item.GetLayoutObject() == input.layout_text)
+ previous_items.push_back(&item);
+ }
+
+ // Try to re-use previous items, or Append if it was not re-usable.
+ bool reused = !previous_items.IsEmpty() &&
+ reuse_builder.Append(text_, nullptr, previous_items);
+ if (!reused)
+ reuse_builder.Append(input.text, style_.get());
+ }
+
+ // Currently, NGInlineItemsBuilder does not strip trailing spaces while
+ // NGInlineItemsBuilderForOffsetMapping does. See
+ // NGInlineItemsBuilderTemplate<NGOffsetMappingBuilder>::ToString().
+ String reuse_text = reuse_builder.ToString();
+ if (!reuse_text.IsEmpty() && reuse_text != text_ &&
+ reuse_text[reuse_text.length() - 1] == kSpaceCharacter)
+ reuse_text = reuse_text.Substring(0, reuse_text.length() - 1);
+ EXPECT_EQ(text_, reuse_text);
+ }
+
Vector<NGInlineItem> items_;
String text_;
String collapsed_;
@@ -254,15 +297,11 @@ TEST_F(NGInlineItemsBuilderTest, CollapseBeforeAndAfterNewline) {
TEST_F(NGInlineItemsBuilderTest,
CollapsibleSpaceAfterNonCollapsibleSpaceAcrossElements) {
- NGInlineItemsBuilderForOffsetMapping builder(&items_);
- scoped_refptr<ComputedStyle> pre_wrap(
- CreateWhitespaceStyle(EWhiteSpace::kPreWrap));
- builder.Append("text ", pre_wrap.get());
- builder.Append(" text", style_.get());
- EXPECT_EQ("text text", builder.ToString())
+ EXPECT_EQ("text text",
+ TestAppend({"text ", EWhiteSpace::kPreWrap}, {" text"}))
<< "The whitespace in constructions like '<span style=\"white-space: "
"pre-wrap\">text <span><span> text</span>' does not collapse.";
- EXPECT_EQ("{}", GetCollapsed(builder.GetOffsetMappingBuilder()));
+ EXPECT_EQ("{}", collapsed_);
}
TEST_F(NGInlineItemsBuilderTest, CollapseZeroWidthSpaces) {
@@ -419,16 +458,11 @@ INSTANTIATE_TEST_CASE_P(NGInlineItemsBuilderTest,
TEST_P(CollapsibleSpaceTest, CollapsedSpaceAfterNoWrap) {
UChar space = GetParam();
- Vector<NGInlineItem> items;
- NGInlineItemsBuilderForOffsetMapping builder(&items);
- scoped_refptr<ComputedStyle> nowrap_style(ComputedStyle::Create());
- nowrap_style->SetWhiteSpace(EWhiteSpace::kNowrap);
- builder.Append(String("nowrap") + space, nowrap_style.get());
- builder.Append(" wrap", style_.get());
- EXPECT_EQ(String("nowrap "
- u"\u200B"
- "wrap"),
- builder.ToString());
+ EXPECT_EQ(
+ String("nowrap "
+ u"\u200B"
+ "wrap"),
+ TestAppend({String("nowrap") + space, EWhiteSpace::kNowrap}, {" wrap"}));
}
TEST_F(NGInlineItemsBuilderTest, BidiBlockOverride) {
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 5b4a1d99f34..0d04530a405 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
@@ -4,30 +4,27 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_layout_algorithm.h"
-#include <algorithm>
-#include <limits>
#include <memory>
-#include <utility>
#include "third_party/blink/renderer/core/layout/ng/inline/ng_baseline.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"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.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_box_fragment.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_breaker.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment.h"
+#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/ng_unpositioned_list_marker.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.h"
#include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_fragment_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_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/style/computed_style.h"
@@ -42,8 +39,12 @@ struct NGLineAlign {
NGLineAlign(const NGLineInfo&);
NGLineAlign() = delete;
+ // The space to align or justify. This includes trailing spaces if exists.
LayoutUnit space;
+
+ // The end offset with trailing spaces excluded.
unsigned end_offset;
+ LayoutUnit trailing_spaces_width;
};
NGLineAlign::NGLineAlign(const NGLineInfo& line_info) {
@@ -55,14 +56,16 @@ NGLineAlign::NGLineAlign(const NGLineInfo& line_info) {
const NGInlineItemResult& item_result = *it;
if (!item_result.has_only_trailing_spaces) {
end_offset = item_result.end_offset;
+ space += trailing_spaces_width;
return;
}
- space += item_result.inline_size;
+ trailing_spaces_width += item_result.inline_size;
}
// An empty line, or only trailing spaces.
DCHECK_EQ(space, line_info.AvailableWidth() - line_info.TextIndent());
end_offset = line_info.StartOffset();
+ space += trailing_spaces_width;
}
} // namespace
@@ -80,15 +83,16 @@ NGInlineLayoutAlgorithm::NGInlineLayoutAlgorithm(
// lays out in visual order.
TextDirection::kLtr,
break_token),
+ baseline_type_(container_builder_.Style().GetFontBaseline()),
is_horizontal_writing_mode_(
blink::IsHorizontalWritingMode(space.GetWritingMode())) {
quirks_mode_ = inline_node.InLineHeightQuirksMode();
- unpositioned_floats_ = ConstraintSpace().UnpositionedFloats();
-
- if (!is_horizontal_writing_mode_)
- baseline_type_ = FontBaseline::kIdeographicBaseline;
}
+// Define the destructor here, so that we can forward-declare more in the
+// header.
+NGInlineLayoutAlgorithm::~NGInlineLayoutAlgorithm() = default;
+
NGInlineBoxState* NGInlineLayoutAlgorithm::HandleOpenTag(
const NGInlineItem& item,
const NGInlineItemResult& item_result) {
@@ -127,7 +131,7 @@ void NGInlineLayoutAlgorithm::PrepareBoxStates(
DCHECK(break_token->UseFirstLineStyle());
// Compute which tags are not closed at the beginning of this line.
- const Vector<NGInlineItem>& items = Node().Items();
+ const Vector<NGInlineItem>& items = line_info.ItemsData().items;
Vector<const NGInlineItem*, 16> open_items;
for (unsigned i = 0; i < break_token->ItemIndex(); i++) {
const NGInlineItem& item = items[i];
@@ -191,12 +195,13 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
baseline_type_);
}
- text_builder.SetItem(NGPhysicalTextFragment::kNormalText, &item_result,
+ text_builder.SetItem(NGPhysicalTextFragment::kNormalText,
+ line_info->ItemsData(), &item_result,
box->text_height);
line_box_.AddChild(text_builder.ToTextFragment(), box->text_top,
item_result.inline_size, item.BidiLevel());
} else if (item.Type() == NGInlineItem::kControl) {
- PlaceControlItem(item, &item_result, box);
+ PlaceControlItem(item, *line_info, &item_result, box);
} else if (item.Type() == NGInlineItem::kOpenTag) {
box = HandleOpenTag(item, item_result);
} else if (item.Type() == NGInlineItem::kCloseTag) {
@@ -244,6 +249,19 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
BidiReorder();
box_states_->UpdateAfterReorder(&line_box_);
LayoutUnit inline_size = box_states_->ComputeInlinePositions(&line_box_);
+
+ // Truncate the line if 'text-overflow: ellipsis' is set.
+ if (UNLIKELY(inline_size > line_info->AvailableWidth() &&
+ node_.GetLayoutBlockFlow()->ShouldTruncateOverflowingText())) {
+ inline_size = NGLineTruncator(node_, *line_info)
+ .TruncateLine(inline_size, &line_box_);
+ }
+
+ // Create box fragmetns if needed. After this point forward, |line_box_| is a
+ // tree structure.
+ if (box_states_->HasBoxFragments())
+ box_states_->CreateBoxFragments(&line_box_);
+
const NGLineHeightMetrics& line_box_metrics =
box_states_->LineBoxState().metrics;
@@ -280,6 +298,8 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
if (IsLtr(line_info->BaseDirection()))
line_bfc_offset.line_offset += line_info->TextIndent();
+ if (line_info->UseFirstLineStyle())
+ container_builder_.SetStyleVariant(NGStyleVariant::kFirstLine);
container_builder_.AddChildren(line_box_);
container_builder_.SetInlineSize(inline_size);
container_builder_.SetBaseDirection(line_info->BaseDirection());
@@ -288,12 +308,13 @@ void NGInlineLayoutAlgorithm::CreateLine(NGLineInfo* line_info,
}
void NGInlineLayoutAlgorithm::PlaceControlItem(const NGInlineItem& item,
+ const NGLineInfo& line_info,
NGInlineItemResult* item_result,
NGInlineBoxState* box) {
DCHECK_EQ(item.Type(), NGInlineItem::kControl);
DCHECK_EQ(item.Length(), 1u);
DCHECK(!item.TextShapeResult());
- UChar character = Node().Text()[item.StartOffset()];
+ UChar character = line_info.ItemsData().text_content[item.StartOffset()];
NGPhysicalTextFragment::NGTextType type;
switch (character) {
case kNewlineCharacter:
@@ -321,7 +342,8 @@ void NGInlineLayoutAlgorithm::PlaceControlItem(const NGInlineItem& item,
NGTextFragmentBuilder text_builder(Node(),
ConstraintSpace().GetWritingMode());
- text_builder.SetItem(type, item_result, box->text_height);
+ text_builder.SetItem(type, line_info.ItemsData(), item_result,
+ box->text_height);
line_box_.AddChild(text_builder.ToTextFragment(), box->text_top,
item_result->inline_size, item.BidiLevel());
}
@@ -450,7 +472,9 @@ bool NGInlineLayoutAlgorithm::ApplyJustify(NGLineInfo* line_info) {
// Construct the line text to compute spacing for.
String line_text =
- Node().Text(line_info->StartOffset(), align.end_offset).ToString();
+ StringView(line_info->ItemsData().text_content, line_info->StartOffset(),
+ align.end_offset - line_info->StartOffset())
+ .ToString();
// Append a hyphen if the last word is hyphenated. The hyphen is in
// |ShapeResult|, but not in text. |ShapeResultSpacing| needs the text that
@@ -498,8 +522,9 @@ LayoutUnit NGInlineLayoutAlgorithm::OffsetForTextAlign(
// Justification is applied in earlier phase, see PlaceItems().
DCHECK_NE(text_align, ETextAlign::kJustify);
+ NGLineAlign align(line_info);
return LineOffsetForTextAlign(text_align, line_info.BaseDirection(),
- NGLineAlign(line_info).space);
+ align.space, align.trailing_spaces_width);
}
LayoutUnit NGInlineLayoutAlgorithm::ComputeContentSize(
@@ -538,10 +563,20 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
bool is_empty_inline = Node().IsEmptyInline();
- if (!is_empty_inline) {
- DCHECK(ConstraintSpace().UnpositionedFloats().IsEmpty());
+ if (is_empty_inline) {
+ // We're just going to collapse through this one, so whatever went in on one
+ // side will go out on the other side. The position of the adjoining floats
+ // will be affected by any subsequent block, until the BFC offset is
+ // resolved.
+ container_builder_.AddAdjoiningFloatTypes(
+ ConstraintSpace().AdjoiningFloatTypes());
+ } else {
DCHECK(ConstraintSpace().MarginStrut().IsEmpty());
container_builder_.SetBfcOffset(ConstraintSpace().BfcOffset());
+
+ // The BFC offset was determined before entering this algorithm. This means
+ // that there should be no adjoining floats.
+ DCHECK(!ConstraintSpace().AdjoiningFloatTypes());
}
// In order to get the correct list of layout opportunities, we need to
@@ -552,10 +587,9 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
// If we are an empty inline, we don't have to run the full algorithm, we can
// return now as we should have positioned all of our floats.
if (is_empty_inline) {
- DCHECK_EQ(handled_item_index, Node().Items().size());
+ DCHECK_EQ(handled_item_index, Node().ItemsData(false).items.size());
container_builder_.SwapPositionedFloats(&positioned_floats_);
- container_builder_.SwapUnpositionedFloats(&unpositioned_floats_);
container_builder_.SetEndMarginStrut(ConstraintSpace().MarginStrut());
container_builder_.SetExclusionSpace(std::move(initial_exclusion_space));
@@ -572,7 +606,7 @@ scoped_refptr<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.
- Vector<NGLayoutOpportunity> opportunities =
+ const Vector<NGLayoutOpportunity> opportunities =
initial_exclusion_space->AllLayoutOpportunities(
ConstraintSpace().BfcOffset(),
ConstraintSpace().AvailableSize().inline_size);
@@ -583,7 +617,30 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
std::unique_ptr<NGExclusionSpace> exclusion_space;
NGInlineBreakToken* break_token = BreakToken();
- for (const auto& opportunity : opportunities) {
+ LayoutUnit line_block_size;
+ LayoutUnit block_delta;
+ const auto* opportunities_it = opportunities.begin();
+ while (opportunities_it != opportunities.end()) {
+ const NGLayoutOpportunity& opportunity = *opportunities_it;
+
+#if DCHECK_IS_ON()
+ // Make sure the last opportunity has the correct properties.
+ if (opportunities_it + 1 == opportunities.end()) {
+ // We shouldn't have any shapes affecting the last opportunity.
+ DCHECK(!opportunity.HasShapeExclusions());
+ DCHECK_EQ(line_block_size, LayoutUnit());
+ DCHECK_EQ(block_delta, LayoutUnit());
+
+ // The opportunity should match the given available size, (however need
+ // to check if the inline-size got saturated first).
+ if (opportunity.rect.InlineSize() != LayoutUnit::Max()) {
+ DCHECK_EQ(opportunity.rect.InlineSize(),
+ ConstraintSpace().AvailableSize().inline_size);
+ }
+ DCHECK_EQ(opportunity.rect.BlockSize(), LayoutUnit::Max());
+ }
+#endif
+
// Reset any state that may have been modified in a previous pass.
positioned_floats.clear();
unpositioned_floats_.clear();
@@ -591,24 +648,44 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
exclusion_space =
std::make_unique<NGExclusionSpace>(*initial_exclusion_space);
+ NGLineLayoutOpportunity line_opportunity =
+ opportunity.ComputeLineLayoutOpportunity(ConstraintSpace(),
+ line_block_size, block_delta);
+
NGLineInfo line_info;
- NGLineBreaker line_breaker(Node(), NGLineBreakerMode::kContent,
- constraint_space_, &positioned_floats,
- &unpositioned_floats_, exclusion_space.get(),
- handled_item_index, break_token);
+ NGLineBreaker line_breaker(
+ Node(), NGLineBreakerMode::kContent, constraint_space_,
+ &positioned_floats, &unpositioned_floats_, &container_builder_,
+ exclusion_space.get(), handled_item_index, break_token);
// TODO(ikilpatrick): Does this always succeed when we aren't an empty
// inline?
- if (!line_breaker.NextLine(opportunity, &line_info))
+ if (!line_breaker.NextLine(line_opportunity, &line_info))
break;
// If this fragment will be larger than the inline-size of the opportunity,
- // *and* the opportunity is smaller than the available inline-size,
- // continue to the next opportunity.
- if (line_info.Width() > opportunity.rect.InlineSize() &&
- opportunity.rect.InlineSize() !=
- ConstraintSpace().AvailableSize().inline_size)
+ // *and* the opportunity is smaller than the available inline-size, and the
+ // container autowraps, continue to the next opportunity.
+ if (line_info.Width() > line_opportunity.AvailableInlineSize() &&
+ ConstraintSpace().AvailableSize().inline_size !=
+ line_opportunity.AvailableFloatInlineSize() &&
+ Node().Style().AutoWrap()) {
+ // Shapes are *special*. We need to potentially increment the block-delta
+ // by 1px each loop to properly test each potential position of the line.
+ if (UNLIKELY(opportunity.HasShapeExclusions()) &&
+ block_delta < opportunity.rect.BlockSize() &&
+ !opportunity.IsBlockDeltaBelowShapes(block_delta)) {
+ block_delta += LayoutUnit(1);
+ line_block_size = LayoutUnit();
+ } else {
+ // We've either don't have any shapes, or run out of block-delta space
+ // to test, proceed to the next layout opportunity.
+ block_delta = LayoutUnit();
+ line_block_size = LayoutUnit();
+ ++opportunities_it;
+ }
continue;
+ }
PrepareBoxStates(line_info, break_token);
CreateLine(&line_info, exclusion_space.get());
@@ -616,8 +693,33 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
// We now can check the block-size of the fragment, and it fits within the
// opportunity.
LayoutUnit block_size = container_builder_.ComputeBlockSize();
- if (block_size > opportunity.rect.BlockSize())
+
+ // Now that we have the block-size of the line, we can re-test the layout
+ // opportunity to see if we fit into the (potentially) non-rectangular
+ // shape area.
+ // If the AvailableInlineSize changes we need to run the line breaker again
+ // with the calculated line_block_size. This is *safe* as the line breaker
+ // won't produce a line which has a larger block-size, (as it can only
+ // decrease or stay the same size).
+ if (UNLIKELY(opportunity.HasShapeExclusions())) {
+ NGLineLayoutOpportunity line_opportunity_with_height =
+ opportunity.ComputeLineLayoutOpportunity(ConstraintSpace(),
+ block_size, block_delta);
+
+ if (line_opportunity_with_height.AvailableInlineSize() !=
+ line_opportunity.AvailableInlineSize()) {
+ line_block_size = block_size;
+ continue;
+ }
+ }
+
+ // Check if the line will fit in the current opportunity.
+ if (block_size + block_delta > opportunity.rect.BlockSize()) {
+ block_delta = LayoutUnit();
+ line_block_size = LayoutUnit();
+ ++opportunities_it;
continue;
+ }
if (opportunity.rect.BlockStartOffset() >
ConstraintSpace().BfcOffset().block_offset)
@@ -662,7 +764,7 @@ scoped_refptr<NGLayoutResult> NGInlineLayoutAlgorithm::Layout() {
// TODO(ikilpatrick): Do we need to always add the OOFs here?
unsigned NGInlineLayoutAlgorithm::PositionLeadingItems(
NGExclusionSpace* exclusion_space) {
- const Vector<NGInlineItem>& items = Node().Items();
+ const Vector<NGInlineItem>& items = Node().ItemsData(false).items;
bool is_empty_inline = Node().IsEmptyInline();
LayoutUnit bfc_line_offset = ConstraintSpace().BfcOffset().line_offset;
@@ -675,10 +777,12 @@ unsigned NGInlineLayoutAlgorithm::PositionLeadingItems(
NGBoxStrut margins =
ComputeMarginsForContainer(ConstraintSpace(), node.Style());
- unpositioned_floats_.push_back(NGUnpositionedFloat::Create(
+ auto unpositioned_float = NGUnpositionedFloat::Create(
ConstraintSpace().AvailableSize(),
ConstraintSpace().PercentageResolutionSize(), bfc_line_offset,
- bfc_line_offset, margins, node, /* break_token */ nullptr));
+ bfc_line_offset, margins, node, /* break_token */ nullptr);
+ AddUnpositionedFloat(&unpositioned_floats_, &container_builder_,
+ std::move(unpositioned_float));
} else if (is_empty_inline &&
item.Type() == NGInlineItem::kOutOfFlowPositioned) {
NGBlockNode node(ToLayoutBox(item.GetLayoutObject()));
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 b0c9a2edb91..017544f453a 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
@@ -6,9 +6,6 @@
#define NGInlineLayoutAlgorithm_h
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.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_item_result.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_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
@@ -23,7 +20,10 @@ class NGConstraintSpace;
class NGInlineBreakToken;
class NGInlineNode;
class NGInlineItem;
-class NGLineBoxFragmentBuilder;
+class NGInlineLayoutStateStack;
+class NGLineInfo;
+struct NGInlineBoxState;
+struct NGInlineItemResult;
struct NGPositionedFloat;
// A class for laying out an inline formatting context, i.e. a block with inline
@@ -40,6 +40,7 @@ class CORE_EXPORT NGInlineLayoutAlgorithm final
NGInlineLayoutAlgorithm(NGInlineNode,
const NGConstraintSpace&,
NGInlineBreakToken* = nullptr);
+ ~NGInlineLayoutAlgorithm() override;
void CreateLine(NGLineInfo*, NGExclusionSpace*);
@@ -59,6 +60,7 @@ class CORE_EXPORT NGInlineLayoutAlgorithm final
void BidiReorder();
void PlaceControlItem(const NGInlineItem&,
+ const NGLineInfo&,
NGInlineItemResult*,
NGInlineBoxState*);
void PlaceGeneratedContent(scoped_refptr<NGPhysicalFragment>,
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 ed5f88b97c1..654b7eb887e 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
@@ -5,14 +5,12 @@
#include "third_party/blink/renderer/core/layout/ng/ng_base_layout_algorithm_test.h"
#include "third_party/blink/renderer/core/dom/tag_collection.h"
-#include "third_party/blink/renderer/core/layout/line/inline_text_box.h"
+#include "third_party/blink/renderer/core/layout/layout_block_flow.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"
#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/layout_ng_block_flow.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"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
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 92aabbded97..bf394eba54f 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
@@ -5,39 +5,28 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include <algorithm>
-#include <limits>
#include <memory>
-#include <utility>
+#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_text.h"
-#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/layout_ng_text.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_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_items_builder.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_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_breaker.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.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/inline/ng_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.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/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_fragment_builder.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_physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result_spacing.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/text/character_names.h"
namespace blink {
@@ -49,6 +38,11 @@ template <typename OffsetMappingBuilder>
void ClearNeedsLayoutIfUpdatingLayout(LayoutObject* node) {
node->ClearNeedsLayout();
node->ClearNeedsCollectInlines();
+ // Reset previous items if they cannot be reused to prevent stale items
+ // for subsequent layouts. Items that can be reused have already been
+ // added to the builder.
+ if (node->IsLayoutNGText())
+ ToLayoutNGText(node)->ClearInlineItems();
}
template <>
@@ -67,19 +61,33 @@ void ClearNeedsLayoutIfUpdatingLayout<NGOffsetMappingBuilder>(LayoutObject*) {}
template <typename OffsetMappingBuilder>
void CollectInlinesInternal(
LayoutBlockFlow* block,
- NGInlineItemsBuilderTemplate<OffsetMappingBuilder>* builder) {
+ NGInlineItemsBuilderTemplate<OffsetMappingBuilder>* builder,
+ String* previous_text) {
builder->EnterBlock(block->Style());
LayoutObject* node = GetLayoutObjectForFirstChildNode(block);
while (node) {
if (node->IsText()) {
LayoutText* layout_text = ToLayoutText(node);
- if (UNLIKELY(layout_text->IsWordBreak())) {
- builder->AppendBreakOpportunity(node->Style(), layout_text);
- } else {
- builder->Append(layout_text->GetText(), node->Style(), layout_text);
+
+ // If the LayoutText element hasn't changed, reuse the existing items.
+
+ // if the last ended with space and this starts with space, do not allow
+ // reuse. builder->MightCollapseWithPreceding(*previous_text)
+ bool item_reused = false;
+ if (node->IsLayoutNGText() && ToLayoutNGText(node)->HasValidLayout() &&
+ previous_text) {
+ item_reused = builder->Append(*previous_text, ToLayoutNGText(node),
+ ToLayoutNGText(node)->InlineItems());
}
- ClearNeedsLayoutIfUpdatingLayout<OffsetMappingBuilder>(layout_text);
+ // If not create a new item as needed.
+ if (!item_reused) {
+ if (UNLIKELY(layout_text->IsWordBreak()))
+ builder->AppendBreakOpportunity(node->Style(), layout_text);
+ else
+ builder->Append(layout_text->GetText(), node->Style(), layout_text);
+ }
+ ClearNeedsLayoutIfUpdatingLayout<OffsetMappingBuilder>(layout_text);
} else if (node->IsFloating()) {
// Add floats and positioned objects in the same way as atomic inlines.
@@ -145,6 +153,33 @@ void CollectInlinesInternal(
builder->ExitBlock();
}
+static bool NeedsShaping(const NGInlineItem& item) {
+ return item.Type() == NGInlineItem::kText && !item.TextShapeResult();
+}
+
+// Determine if reshape is needed for ::first-line style.
+bool FirstLineNeedsReshape(const ComputedStyle& first_line_style,
+ const ComputedStyle& base_style) {
+ const Font& base_font = base_style.GetFont();
+ const Font& first_line_font = first_line_style.GetFont();
+ return &base_font != &first_line_font && base_font != first_line_font;
+}
+
+// Make a string to the specified length, either by truncating if longer, or
+// appending space characters if shorter.
+void TruncateOrPadText(String* text, unsigned length) {
+ if (text->length() > length) {
+ *text = text->Substring(0, length);
+ } else if (text->length() < length) {
+ StringBuilder builder;
+ builder.ReserveCapacity(length);
+ builder.Append(*text);
+ while (builder.length() < length)
+ builder.Append(kSpaceCharacter);
+ *text = builder.ToString();
+ }
+}
+
} // namespace
NGInlineNode::NGInlineNode(LayoutBlockFlow* block)
@@ -159,13 +194,29 @@ bool NGInlineNode::InLineHeightQuirksMode() const {
return GetDocument().InLineHeightQuirksMode();
}
+bool NGInlineNode::CanContainFirstFormattedLine() const {
+ // TODO(kojii): In LayoutNG, leading OOF creates an anonymous block box,
+ // and that |LayoutBlockFlow::CanContainFirstFormattedLine()| does not work.
+ // crbug.com/734554
+ LayoutObject* layout_object = GetLayoutBlockFlow();
+ if (!layout_object->IsAnonymousBlock())
+ return true;
+ for (;;) {
+ layout_object = layout_object->PreviousSibling();
+ if (!layout_object)
+ return true;
+ if (!layout_object->IsFloatingOrOutOfFlowPositioned())
+ return false;
+ }
+}
+
NGInlineNodeData* NGInlineNode::MutableData() {
return ToLayoutBlockFlow(box_)->GetNGInlineNodeData();
}
bool NGInlineNode::IsPrepareLayoutFinished() const {
const NGInlineNodeData* data = ToLayoutBlockFlow(box_)->GetNGInlineNodeData();
- return data && !data->text_content_.IsNull();
+ return data && !data->text_content.IsNull();
}
const NGInlineNodeData& NGInlineNode::Data() const {
@@ -174,28 +225,19 @@ const NGInlineNodeData& NGInlineNode::Data() const {
return *ToLayoutBlockFlow(box_)->GetNGInlineNodeData();
}
-const Vector<NGInlineItem>& NGInlineNode::Items(bool is_first_line) const {
- const NGInlineNodeData& data = Data();
- if (!is_first_line || !data.first_line_items_)
- return data.items_;
- return *data.first_line_items_;
-}
-
-NGInlineItemRange NGInlineNode::Items(unsigned start, unsigned end) {
- return NGInlineItemRange(&MutableData()->items_, start, end);
-}
-
-void NGInlineNode::InvalidatePrepareLayout() {
+void NGInlineNode::InvalidatePrepareLayoutForTest() {
GetLayoutBlockFlow()->ResetNGInlineNodeData();
DCHECK(!IsPrepareLayoutFinished());
}
void NGInlineNode::PrepareLayoutIfNeeded() {
+ std::unique_ptr<NGInlineNodeData> previous_data;
LayoutBlockFlow* block_flow = GetLayoutBlockFlow();
if (IsPrepareLayoutFinished()) {
if (!block_flow->NeedsCollectInlines())
return;
+ previous_data.reset(block_flow->TakeNGInlineNodeData());
block_flow->ResetNGInlineNodeData();
}
@@ -203,9 +245,11 @@ void NGInlineNode::PrepareLayoutIfNeeded() {
// NGInlineNode represent a collection of adjacent non-atomic inlines.
NGInlineNodeData* data = MutableData();
DCHECK(data);
- CollectInlines(data);
+ CollectInlines(data, previous_data.get());
SegmentText(data);
- ShapeText(data);
+ ShapeText(data, previous_data.get());
+ ShapeTextForFirstLineIfNeeded(data);
+ AssociateItemsWithInlines(data);
DCHECK_EQ(data, MutableData());
block_flow->ClearNeedsCollectInlines();
@@ -213,10 +257,10 @@ void NGInlineNode::PrepareLayoutIfNeeded() {
#if DCHECK_IS_ON()
// ComputeOffsetMappingIfNeeded() runs some integrity checks as part of
// creating offset mapping. Run the check, and discard the result.
- DCHECK(!data->offset_mapping_);
+ DCHECK(!data->offset_mapping);
ComputeOffsetMappingIfNeeded();
- DCHECK(data->offset_mapping_);
- data->offset_mapping_.reset();
+ DCHECK(data->offset_mapping);
+ data->offset_mapping.reset();
#endif
}
@@ -228,45 +272,56 @@ const NGInlineNodeData& NGInlineNode::EnsureData() {
const NGOffsetMapping* NGInlineNode::ComputeOffsetMappingIfNeeded() {
DCHECK(!GetLayoutBlockFlow()->GetDocument().NeedsLayoutTreeUpdate());
- if (!Data().offset_mapping_) {
+ NGInlineNodeData* data = MutableData();
+ if (!data->offset_mapping) {
// TODO(xiaochengh): ComputeOffsetMappingIfNeeded() discards the
// NGInlineItems and text content built by |builder|, because they are
// already there in NGInlineNodeData. For efficiency, we should make
// |builder| not construct items and text content.
Vector<NGInlineItem> items;
NGInlineItemsBuilderForOffsetMapping builder(&items);
- CollectInlinesInternal(GetLayoutBlockFlow(), &builder);
- builder.ToString();
+ CollectInlinesInternal(GetLayoutBlockFlow(), &builder, nullptr);
+ String text = builder.ToString();
+
+ // The trailing space of the text for offset mapping may be removed. If not,
+ // share the string instance.
+ if (text == data->text_content)
+ text = data->text_content;
// TODO(xiaochengh): This doesn't compute offset mapping correctly when
// text-transform CSS property changes text length.
NGOffsetMappingBuilder& mapping_builder = builder.GetOffsetMappingBuilder();
- mapping_builder.SetDestinationString(Text());
- MutableData()->offset_mapping_ =
+ mapping_builder.SetDestinationString(text);
+ data->offset_mapping =
std::make_unique<NGOffsetMapping>(mapping_builder.Build());
}
- return Data().offset_mapping_.get();
+ return data->offset_mapping.get();
}
// Depth-first-scan of all LayoutInline and LayoutText nodes that make up this
// NGInlineNode object. Collects LayoutText items, merging them up into the
// parent LayoutInline where possible, and joining all text content in a single
// string to allow bidi resolution and shaping of the entire block.
-void NGInlineNode::CollectInlines(NGInlineNodeData* data) {
- DCHECK(data->text_content_.IsNull());
- DCHECK(data->items_.IsEmpty());
+void NGInlineNode::CollectInlines(NGInlineNodeData* data,
+ NGInlineNodeData* previous_data) {
+ DCHECK(data->text_content.IsNull());
+ DCHECK(data->items.IsEmpty());
LayoutBlockFlow* block = GetLayoutBlockFlow();
block->WillCollectInlines();
- NGInlineItemsBuilder builder(&data->items_);
- CollectInlinesInternal(block, &builder);
- data->text_content_ = builder.ToString();
+
+ String* previous_text =
+ previous_data ? &previous_data->text_content : nullptr;
+ NGInlineItemsBuilder builder(&data->items);
+ CollectInlinesInternal(block, &builder, previous_text);
+ 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_ =
- !data->text_content_.Is8Bit() || builder.HasBidiControls();
+ !data->text_content.Is8Bit() || builder.HasBidiControls();
data->is_empty_inline_ = builder.IsEmptyInline();
}
@@ -277,8 +332,8 @@ void NGInlineNode::SegmentText(NGInlineNodeData* data) {
}
NGBidiParagraph bidi;
- data->text_content_.Ensure16Bit();
- if (!bidi.SetParagraph(data->text_content_, Style())) {
+ data->text_content.Ensure16Bit();
+ if (!bidi.SetParagraph(data->text_content, Style())) {
// On failure, give up bidi resolving and reordering.
data->is_bidi_enabled_ = false;
data->SetBaseDirection(TextDirection::kLtr);
@@ -293,9 +348,9 @@ void NGInlineNode::SegmentText(NGInlineNodeData* data) {
return;
}
- Vector<NGInlineItem>& items = data->items_;
+ Vector<NGInlineItem>& items = data->items;
unsigned item_index = 0;
- for (unsigned start = 0; start < data->text_content_.length();) {
+ for (unsigned start = 0; start < data->text_content.length();) {
UBiDiLevel level;
unsigned end = bidi.GetLogicalRun(start, &level);
DCHECK_EQ(items[item_index].start_offset_, start);
@@ -313,19 +368,21 @@ void NGInlineNode::SegmentText(NGInlineNodeData* data) {
#endif
}
-void NGInlineNode::ShapeText(NGInlineNodeData* data) {
+void NGInlineNode::ShapeText(NGInlineItemsData* data,
+ NGInlineItemsData* previous_data) {
// TODO(eae): Add support for shaping latin-1 text?
- data->text_content_.Ensure16Bit();
- ShapeText(data->text_content_, &data->items_);
-
- ShapeTextForFirstLineIfNeeded(data);
+ data->text_content.Ensure16Bit();
+ ShapeText(data->text_content, &data->items,
+ previous_data ? &previous_data->text_content : nullptr);
}
void NGInlineNode::ShapeText(const String& text_content,
- Vector<NGInlineItem>* items) {
- // Shape each item with the full context of the entire node.
+ Vector<NGInlineItem>* items,
+ const String* previous_text) {
+ // Provide full context of the entire node to the shaper.
HarfBuzzShaper shaper(text_content.Characters16(), text_content.length());
ShapeResultSpacing<String> spacing(text_content);
+
for (unsigned index = 0; index < items->size();) {
NGInlineItem& start_item = (*items)[index];
if (start_item.Type() != NGInlineItem::kText) {
@@ -339,6 +396,12 @@ void NGInlineNode::ShapeText(const String& text_content,
unsigned end_offset = start_item.EndOffset();
for (; end_index < items->size(); end_index++) {
const NGInlineItem& item = (*items)[end_index];
+
+ if (item.Type() == NGInlineItem::kControl) {
+ // Do not shape across control characters (line breaks, zero width
+ // spaces, etc).
+ break;
+ }
if (item.Type() == NGInlineItem::kText) {
// Shape adjacent items together if the font and direction matches to
// allow ligatures and kerning to apply.
@@ -359,6 +422,43 @@ void NGInlineNode::ShapeText(const String& text_content,
}
}
+ // Shaping a single item. Skip if the existing results remain valid.
+ if (previous_text && end_offset == start_item.EndOffset() &&
+ !NeedsShaping(start_item)) {
+ DCHECK_EQ(start_item.StartOffset(),
+ start_item.TextShapeResult()->StartIndexForResult());
+ DCHECK_EQ(start_item.EndOffset(),
+ start_item.TextShapeResult()->EndIndexForResult());
+ index++;
+ continue;
+ }
+
+ // Results may only be reused if all items in the range remain valid.
+ bool has_valid_shape_results = true;
+ for (unsigned item_index = index; item_index < end_index; item_index++) {
+ if (NeedsShaping((*items)[item_index])) {
+ has_valid_shape_results = false;
+ break;
+ }
+ }
+
+ // When shaping across multiple items checking whether the individual
+ // items has valid shape results isn't sufficient as items may have been
+ // re-ordered or removed.
+ // TODO(layout-dev): It would probably be faster to check for removed or
+ // moved items but for now comparing the string itself will do.
+ unsigned text_start = start_item.StartOffset();
+ DCHECK_GE(end_offset, text_start);
+ unsigned text_length = end_offset - text_start;
+ if (has_valid_shape_results && previous_text &&
+ end_offset <= previous_text->length() &&
+ StringView(text_content, text_start, text_length) ==
+ StringView(*previous_text, text_start, text_length)) {
+ index = end_index;
+ continue;
+ }
+
+ // Shape each item with the full context of the entire node.
scoped_refptr<ShapeResult> shape_result =
shaper.Shape(&font, direction, start_item.StartOffset(), end_offset);
if (UNLIKELY(spacing.SetSpacing(font.GetFontDescription())))
@@ -404,9 +504,28 @@ void NGInlineNode::ShapeTextForFirstLineIfNeeded(NGInlineNodeData* data) {
if (block_style == first_line_style)
return;
- auto first_line_items = std::make_unique<Vector<NGInlineItem>>();
- first_line_items->AppendVector(data->items_);
- for (auto& item : *first_line_items) {
+ auto first_line_items = std::make_unique<NGInlineItemsData>();
+ first_line_items->text_content = data->text_content;
+ bool needs_reshape = false;
+ if (first_line_style->TextTransform() != block_style->TextTransform()) {
+ // TODO(kojii): This logic assumes that text-transform is applied only to
+ // ::first-line, and does not work when the base style has text-transform
+ // and ::first-line has different text-transform.
+ first_line_style->ApplyTextTransform(&first_line_items->text_content);
+ if (first_line_items->text_content != data->text_content) {
+ // TODO(kojii): When text-transform changes the length, we need to adjust
+ // offset in NGInlineItem, or re-collect inlines. Other classes such as
+ // line breaker need to support the scenario too. For now, we force the
+ // string to be the same length to prevent them from crashing. This may
+ // result in a missing or a duplicate character if the length changes.
+ TruncateOrPadText(&first_line_items->text_content,
+ data->text_content.length());
+ needs_reshape = true;
+ }
+ }
+
+ first_line_items->items.AppendVector(data->items);
+ for (auto& item : first_line_items->items) {
if (item.style_) {
DCHECK(item.layout_object_);
item.style_ = item.layout_object_->FirstLineStyle();
@@ -415,15 +534,26 @@ void NGInlineNode::ShapeTextForFirstLineIfNeeded(NGInlineNodeData* data) {
}
// Re-shape if the font is different.
- const Font& font = block_style->GetFont();
- const Font& first_line_font = first_line_style->GetFont();
- if (&font != &first_line_font && font != first_line_font) {
- ShapeText(data->text_content_, first_line_items.get());
- }
+ if (needs_reshape || FirstLineNeedsReshape(*first_line_style, *block_style))
+ ShapeText(first_line_items.get());
data->first_line_items_ = std::move(first_line_items);
}
+void NGInlineNode::AssociateItemsWithInlines(NGInlineNodeData* data) {
+ LayoutObject* last_object = nullptr;
+ for (auto& item : data->items) {
+ LayoutObject* object = item.GetLayoutObject();
+ if (object && object->IsLayoutNGText()) {
+ LayoutNGText* layout_text = ToLayoutNGText(object);
+ if (object != last_object)
+ layout_text->ClearInlineItems();
+ layout_text->AddInlineItem(&item);
+ }
+ last_object = object;
+ }
+}
+
scoped_refptr<NGLayoutResult> NGInlineNode::Layout(
const NGConstraintSpace& constraint_space,
NGBreakToken* break_token) {
@@ -446,6 +576,7 @@ static LayoutUnit ComputeContentSize(NGInlineNode node,
NGConstraintSpaceBuilder(writing_mode, node.InitialContainingBlockSize())
.SetTextDirection(style.Direction())
.SetAvailableSize({available_inline_size, NGSizeIndefinite})
+ .SetIsIntermediateLayout(true)
.ToConstraintSpace(writing_mode);
Vector<NGPositionedFloat> positioned_floats;
@@ -454,8 +585,7 @@ static LayoutUnit ComputeContentSize(NGInlineNode node,
scoped_refptr<NGInlineBreakToken> break_token;
NGLineInfo line_info;
NGExclusionSpace empty_exclusion_space;
- NGLayoutOpportunity opportunity(NGBfcRect(
- NGBfcOffset(), NGBfcOffset(available_inline_size, LayoutUnit::Max())));
+ NGLineLayoutOpportunity line_opportunity(available_inline_size);
LayoutUnit result;
LayoutUnit previous_floats_inline_size =
input.float_left_inline_size + input.float_right_inline_size;
@@ -463,9 +593,10 @@ static LayoutUnit ComputeContentSize(NGInlineNode node,
unpositioned_floats.clear();
NGLineBreaker line_breaker(node, mode, *space, &positioned_floats,
- &unpositioned_floats, &empty_exclusion_space, 0u,
- break_token.get());
- if (!line_breaker.NextLine(opportunity, &line_info))
+ &unpositioned_floats,
+ nullptr /* container_builder */,
+ &empty_exclusion_space, 0u, break_token.get());
+ if (!line_breaker.NextLine(line_opportunity, &line_info))
break;
break_token = line_breaker.CreateBreakToken(line_info, nullptr);
@@ -490,14 +621,9 @@ static LayoutUnit ComputeContentSize(NGInlineNode node,
NGBlockNode float_node = unpositioned_float->node;
const ComputedStyle& float_style = float_node.Style();
- Optional<MinMaxSize> child_minmax;
- if (NeedMinMaxSizeForContentContribution(float_style)) {
- MinMaxSizeInput zero_input; // Floats don't intrude into floats.
- child_minmax = float_node.ComputeMinMaxSize(zero_input);
- }
-
- MinMaxSize child_sizes =
- ComputeMinAndMaxContentContribution(float_style, child_minmax);
+ MinMaxSizeInput zero_input; // Floats don't intrude into floats.
+ MinMaxSize child_sizes = ComputeMinAndMaxContentContribution(
+ writing_mode, float_node, zero_input);
LayoutUnit child_inline_margins =
ComputeMinMaxMargins(style, float_node).InlineSum();
@@ -560,7 +686,7 @@ MinMaxSize NGInlineNode::ComputeMinMaxSize(const MinMaxSizeInput& input) {
void NGInlineNode::CheckConsistency() const {
#if DCHECK_IS_ON()
- const Vector<NGInlineItem>& items = Data().items_;
+ const Vector<NGInlineItem>& items = Data().items;
for (const NGInlineItem& item : items) {
DCHECK(!item.GetLayoutObject() || !item.Style() ||
item.Style() == item.GetLayoutObject()->Style());
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 333c5b1b092..7685706584d 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
@@ -7,28 +7,19 @@
#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/inline/ng_inline_item.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
-template <typename OffsetMappingBuilder>
-class NGInlineItemsBuilderTemplate;
-
-class EmptyOffsetMappingBuilder;
-class LayoutBlockFlow;
-struct MinMaxSize;
class NGConstraintSpace;
class NGInlineItem;
-class NGInlineItemRange;
-using NGInlineItemsBuilder =
- NGInlineItemsBuilderTemplate<EmptyOffsetMappingBuilder>;
-struct NGInlineNodeData;
class NGLayoutResult;
class NGOffsetMapping;
class NGInlineNodeLegacy;
+struct MinMaxSize;
+struct NGInlineItemsData;
// Represents an anonymous block box to be laid out, that contains consecutive
// inline nodes and their descendants.
@@ -55,17 +46,12 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
MinMaxSize ComputeMinMaxSize(const MinMaxSizeInput&);
// Instruct to re-compute |PrepareLayout| on the next layout.
- void InvalidatePrepareLayout();
+ void InvalidatePrepareLayoutForTest();
- const String& Text() const { return Data().text_content_; }
- StringView Text(unsigned start_offset, unsigned end_offset) const {
- return StringView(Data().text_content_, start_offset,
- end_offset - start_offset);
+ const NGInlineItemsData& ItemsData(bool is_first_line) const {
+ return Data().ItemsData(is_first_line);
}
- const Vector<NGInlineItem>& Items(bool is_first_line = false) const;
- NGInlineItemRange Items(unsigned start_index, unsigned end_index);
-
// Returns the DOM to text content offset mapping of this block. If it is not
// computed before, compute and store it in NGInlineNodeData.
// This funciton must be called with clean layout.
@@ -76,8 +62,10 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
bool IsEmptyInline() { return EnsureData().is_empty_inline_; }
- void AssertOffset(unsigned index, unsigned offset) const;
- void AssertEndOffset(unsigned index, unsigned offset) const;
+ // @return if this node can contain the "first formatted line".
+ // https://www.w3.org/TR/CSS22/selector.html#first-formatted-line
+ bool CanContainFirstFormattedLine() const;
+
void CheckConsistency() const;
String ToString() const;
@@ -89,11 +77,16 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
// calling the Layout method.
void PrepareLayoutIfNeeded();
- void CollectInlines(NGInlineNodeData*);
+ void CollectInlines(NGInlineNodeData*,
+ NGInlineNodeData* previous_data = nullptr);
void SegmentText(NGInlineNodeData*);
- void ShapeText(NGInlineNodeData*);
- void ShapeText(const String&, Vector<NGInlineItem>*);
+ void ShapeText(NGInlineItemsData*,
+ NGInlineItemsData* previous_data = nullptr);
+ void ShapeText(const String& text,
+ Vector<NGInlineItem>*,
+ const String* previous_text);
void ShapeTextForFirstLineIfNeeded(NGInlineNodeData*);
+ void AssociateItemsWithInlines(NGInlineNodeData*);
NGInlineNodeData* MutableData();
const NGInlineNodeData& Data() const;
@@ -103,15 +96,6 @@ class CORE_EXPORT NGInlineNode : public NGLayoutInputNode {
friend class NGInlineNodeLegacy;
};
-inline void NGInlineNode::AssertOffset(unsigned index, unsigned offset) const {
- Data().items_[index].AssertOffset(offset);
-}
-
-inline void NGInlineNode::AssertEndOffset(unsigned index,
- unsigned offset) const {
- Data().items_[index].AssertEndOffset(offset);
-}
-
DEFINE_TYPE_CASTS(NGInlineNode,
NGLayoutInputNode,
node,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.cc
index a45f608f7b5..07eaa48884b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.cc
@@ -4,13 +4,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h"
-#include "third_party/blink/renderer/core/dom/node.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
-
namespace blink {
-NGInlineNodeData::NGInlineNodeData() = default;
-NGInlineNodeData::~NGInlineNodeData() = default;
-
} // namespace blink
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 2d8efffd2d5..dbf328bc9ea 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,16 +11,14 @@
namespace blink {
-class NGOffsetMapping;
-
// Data which is required for inline nodes.
-struct CORE_EXPORT NGInlineNodeData {
- // The constructor and destructor can't be implicit or inlined, because they
- // need full definition of NGOffsetMapping.
- NGInlineNodeData();
- ~NGInlineNodeData();
-
+struct CORE_EXPORT NGInlineNodeData : NGInlineItemsData {
private:
+ const NGInlineItemsData& ItemsData(bool is_first_line) const {
+ return !is_first_line || !first_line_items_
+ ? (const NGInlineItemsData&)*this
+ : *first_line_items_;
+ }
TextDirection BaseDirection() const {
return static_cast<TextDirection>(base_direction_);
}
@@ -33,18 +31,12 @@ struct CORE_EXPORT NGInlineNodeData {
friend class NGInlineNodeForTest;
friend class NGOffsetMappingTest;
- // Text content for all inline items represented by a single NGInlineNode.
- // Encoded either as UTF-16 or latin-1 depending on the content.
- String text_content_;
- Vector<NGInlineItem> items_;
-
- // |items_| to use for the first line, when the node has :first-line rules.
- // Items have different ComputedStyle, and may also have different ShapeResult
- // if fonts are different.
- std::unique_ptr<Vector<NGInlineItem>> first_line_items_;
-
- // The DOM to text content offset mapping of this inline node.
- std::unique_ptr<NGOffsetMapping> offset_mapping_;
+ // Items to use for the first line, when the node has :first-line rules.
+ //
+ // Items have different ComputedStyle, and may also have different
+ // text_content and ShapeResult if 'text-transform' is applied or fonts are
+ // different.
+ std::unique_ptr<NGInlineItemsData> first_line_items_;
unsigned is_bidi_enabled_ : 1;
unsigned base_direction_ : 1; // TextDirection
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 ca628714647..f04e5e70b56 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
@@ -22,29 +22,29 @@ class NGInlineNodeForTest : public NGInlineNode {
public:
using NGInlineNode::NGInlineNode;
- std::string Text() const { return Data().text_content_.Utf8().data(); }
- Vector<NGInlineItem>& Items() { return MutableData()->items_; }
+ std::string Text() const { return Data().text_content.Utf8().data(); }
+ Vector<NGInlineItem>& Items() { return MutableData()->items; }
static Vector<NGInlineItem>& Items(NGInlineNodeData& data) {
- return data.items_;
+ return data.items;
}
void Append(const String& text,
const ComputedStyle* style = nullptr,
LayoutObject* layout_object = nullptr) {
NGInlineNodeData* data = MutableData();
- unsigned start = data->text_content_.length();
- data->text_content_.append(text);
- data->items_.push_back(NGInlineItem(NGInlineItem::kText, start,
- start + text.length(), style,
- layout_object));
+ unsigned start = data->text_content.length();
+ data->text_content.append(text);
+ data->items.push_back(NGInlineItem(NGInlineItem::kText, start,
+ start + text.length(), style,
+ layout_object));
data->is_empty_inline_ = false;
}
void Append(UChar character) {
NGInlineNodeData* data = MutableData();
- data->text_content_.append(character);
- unsigned end = data->text_content_.length();
- data->items_.push_back(
+ data->text_content.append(character);
+ unsigned end = data->text_content.length();
+ data->items.push_back(
NGInlineItem(NGInlineItem::kBidiControl, end - 1, end, nullptr));
data->is_bidi_enabled_ = true;
data->is_empty_inline_ = false;
@@ -52,8 +52,8 @@ class NGInlineNodeForTest : public NGInlineNode {
void ClearText() {
NGInlineNodeData* data = MutableData();
- data->text_content_ = String();
- data->items_.clear();
+ data->text_content = String();
+ data->items.clear();
data->is_empty_inline_ = true;
}
@@ -93,7 +93,7 @@ class NGInlineNodeTest : public NGLayoutTest {
if (!layout_block_flow_)
SetupHtml("t", "<div id=t style='font:10px'>test</div>");
NGInlineNodeForTest node(layout_block_flow_);
- node.InvalidatePrepareLayout();
+ node.InvalidatePrepareLayoutForTest();
return node;
}
@@ -304,7 +304,6 @@ TEST_F(NGInlineNodeTest, SegmentSplit1To2) {
NGInlineNodeForTest node = CreateInlineNode();
node.Append(u"Hello \u05E2\u05D1\u05E8\u05D9\u05EA");
node.SegmentText();
- ASSERT_EQ(2u, node.Items().size());
Vector<NGInlineItem>& items = node.Items();
ASSERT_EQ(2u, items.size());
TEST_ITEM_OFFSET_DIR(items[0], 0u, 6u, TextDirection::kLtr);
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 eeef40c579c..2b7a7e3d58e 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
@@ -5,7 +5,6 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h"
-#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.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_physical_line_box_fragment.h"
@@ -56,6 +55,25 @@ const NGPhysicalFragment* NGLineBoxFragmentBuilder::Child::PhysicalFragment()
: fragment.get();
}
+NGLineBoxFragmentBuilder::Child*
+NGLineBoxFragmentBuilder::ChildList::FirstInFlowChild() {
+ for (auto& child : *this) {
+ if (child.HasInFlowFragment())
+ return &child;
+ }
+ return nullptr;
+}
+
+NGLineBoxFragmentBuilder::Child*
+NGLineBoxFragmentBuilder::ChildList::LastInFlowChild() {
+ for (auto it = rbegin(); it != rend(); it++) {
+ auto& child = *it;
+ if (child.HasInFlowFragment())
+ return &child;
+ }
+ return nullptr;
+}
+
void NGLineBoxFragmentBuilder::ChildList::InsertChild(
unsigned index,
scoped_refptr<NGLayoutResult> layout_result,
@@ -128,28 +146,32 @@ scoped_refptr<NGLayoutResult> NGLineBoxFragmentBuilder::ToLineBoxFragment() {
NGPhysicalSize physical_size = Size().ConvertToPhysical(writing_mode);
NGPhysicalOffsetRect contents_visual_rect({}, physical_size);
+ NGPhysicalOffsetRect scrollable_overflow({}, physical_size);
for (size_t i = 0; i < children_.size(); ++i) {
NGPhysicalFragment* child = children_[i].get();
child->SetOffset(offsets_[i].ConvertToPhysical(
writing_mode, Direction(), physical_size, child->Size()));
child->PropagateContentsVisualRect(&contents_visual_rect);
+ NGPhysicalOffsetRect child_scroll_overflow = child->ScrollableOverflow();
+ child_scroll_overflow.offset += child->Offset();
+ scrollable_overflow.Unite(child_scroll_overflow);
}
scoped_refptr<NGPhysicalLineBoxFragment> fragment =
base::AdoptRef(new NGPhysicalLineBoxFragment(
- Style(), physical_size, children_, contents_visual_rect, metrics_,
- base_direction_,
+ Style(), style_variant_, physical_size, children_,
+ contents_visual_rect, scrollable_overflow, metrics_, base_direction_,
break_token_ ? std::move(break_token_)
: NGInlineBreakToken::Create(node_)));
return base::AdoptRef(new NGLayoutResult(
std::move(fragment), oof_positioned_descendants_, positioned_floats_,
- unpositioned_floats_, unpositioned_list_marker_,
- std::move(exclusion_space_), bfc_offset_, end_margin_strut_,
+ unpositioned_list_marker_, std::move(exclusion_space_), bfc_offset_,
+ end_margin_strut_,
/* intrinsic_block_size */ LayoutUnit(),
/* minimal_space_shortage */ LayoutUnit::Max(), EBreakBetween::kAuto,
EBreakBetween::kAuto, /* has_forced_break */ false, is_pushed_by_floats_,
- NGLayoutResult::kSuccess));
+ adjoining_floats_, NGLayoutResult::kSuccess));
}
} // 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 9f4ed515a70..9ea29183fb1 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
@@ -9,15 +9,15 @@
#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"
#include "third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
namespace blink {
class ComputedStyle;
class NGInlineBreakToken;
-class NGInlineNode;
class NGPhysicalFragment;
+struct NGPositionedFloat;
class CORE_EXPORT NGLineBoxFragmentBuilder final
: public NGContainerFragmentBuilder {
@@ -78,6 +78,14 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
bidi_level(bidi_level) {}
// Create an in-flow |NGPhysicalFragment|.
Child(scoped_refptr<NGPhysicalFragment> fragment,
+ NGLogicalOffset offset,
+ LayoutUnit inline_size,
+ UBiDiLevel bidi_level)
+ : fragment(std::move(fragment)),
+ offset(offset),
+ inline_size(inline_size),
+ bidi_level(bidi_level) {}
+ Child(scoped_refptr<NGPhysicalFragment> fragment,
LayoutUnit block_offset,
LayoutUnit inline_size,
UBiDiLevel bidi_level)
@@ -130,6 +138,15 @@ class CORE_EXPORT NGLineBoxFragmentBuilder final
using const_iterator = Vector<Child, 16>::const_iterator;
const_iterator begin() const { return children_.begin(); }
const_iterator end() const { return children_.end(); }
+ using reverse_iterator = Vector<Child, 16>::reverse_iterator;
+ reverse_iterator rbegin() { return children_.rbegin(); }
+ reverse_iterator rend() { return children_.rend(); }
+ using const_reverse_iterator = Vector<Child, 16>::const_reverse_iterator;
+ const_reverse_iterator rbegin() const { return children_.rbegin(); }
+ const_reverse_iterator rend() const { return children_.rend(); }
+
+ Child* FirstInFlowChild();
+ Child* LastInFlowChild();
// Add a child. Accepts all constructor arguments for |Child|.
template <class... Args>
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 343a5fec56c..79294415634 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
@@ -8,12 +8,12 @@
#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_text_fragment_builder.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_floats_utils.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_positioned_float.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shaping_line_breaker.h"
@@ -35,24 +35,40 @@ inline bool CanBreakAfterLast(const NGInlineItemResults& item_results) {
} // namespace
+NGLineBreaker::LineData::LineData(NGInlineNode node,
+ const NGInlineBreakToken* break_token) {
+ is_first_formatted_line = (!break_token || (!break_token->ItemIndex() &&
+ !break_token->TextOffset())) &&
+ node.CanContainFirstFormattedLine();
+ use_first_line_style = is_first_formatted_line && node.GetLayoutObject()
+ ->GetDocument()
+ .GetStyleEngine()
+ .UsesFirstLineRules();
+}
+
NGLineBreaker::NGLineBreaker(
NGInlineNode node,
NGLineBreakerMode mode,
const NGConstraintSpace& space,
Vector<NGPositionedFloat>* positioned_floats,
Vector<scoped_refptr<NGUnpositionedFloat>>* unpositioned_floats,
+ NGContainerFragmentBuilder* container_builder,
NGExclusionSpace* exclusion_space,
unsigned handled_float_index,
const NGInlineBreakToken* break_token)
- : node_(node),
+ : line_(node, break_token),
+ node_(node),
+ items_data_(node.ItemsData(line_.use_first_line_style)),
mode_(mode),
constraint_space_(space),
positioned_floats_(positioned_floats),
unpositioned_floats_(unpositioned_floats),
+ container_builder_(container_builder),
exclusion_space_(exclusion_space),
- break_iterator_(node.Text()),
- shaper_(node.Text().Characters16(), node.Text().length()),
- spacing_(node.Text()),
+ break_iterator_(items_data_.text_content),
+ shaper_(items_data_.text_content.Characters16(),
+ items_data_.text_content.length()),
+ spacing_(items_data_.text_content),
handled_floats_end_item_index_(handled_float_index),
base_direction_(node_.BaseDirection()),
in_line_height_quirks_mode_(node.InLineHeightQuirksMode()) {
@@ -63,11 +79,15 @@ NGLineBreaker::NGLineBreaker(
item_index_ = break_token->ItemIndex();
offset_ = break_token->TextOffset();
previous_line_had_forced_break_ = break_token->IsForcedBreak();
- node.AssertOffset(item_index_, offset_);
+ items_data_.AssertOffset(item_index_, offset_);
ignore_floats_ = break_token->IgnoreFloats();
}
}
+// Define the destructor here, so that we can forward-declare more in the
+// header.
+NGLineBreaker::~NGLineBreaker() = default;
+
inline NGInlineItemResult* NGLineBreaker::AddItem(
const NGInlineItem& item,
unsigned end_offset,
@@ -106,59 +126,53 @@ inline void NGLineBreaker::ComputeCanBreakAfter(
auto_wrap_ && break_iterator_.IsBreakable(item_result->end_offset);
}
-// @return if this is the "first formatted line".
-// https://www.w3.org/TR/CSS22/selector.html#first-formatted-line
-bool NGLineBreaker::IsFirstFormattedLine() const {
- if (item_index_ || offset_)
- return false;
-
- // TODO(kojii): In LayoutNG, leading OOF creates an anonymous block box,
- // and that |CanContainFirstFormattedLine()| does not work.
- // crbug.com/734554
- // return node_.GetLayoutBlockFlow()->CanContainFirstFormattedLine();
- LayoutObject* layout_object = node_.GetLayoutBlockFlow();
- if (!layout_object->IsAnonymousBlock())
- return true;
- for (;;) {
- layout_object = layout_object->PreviousSibling();
- if (!layout_object)
- return true;
- if (!layout_object->IsFloatingOrOutOfFlowPositioned())
+// True if |item| is trailing; i.e., |item| and all items after it are opaque to
+// whitespace collapsing.
+bool NGLineBreaker::IsTrailing(const NGInlineItem& item,
+ const NGLineInfo& line_info) const {
+ const Vector<NGInlineItem>& items = line_info.ItemsData().items;
+ for (const NGInlineItem* it = &item; it != items.end(); ++it) {
+ if (it->EndCollapseType() != NGInlineItem::kOpaqueToCollapsing)
return false;
}
+ return true;
}
// Compute the base direction for bidi algorithm for this line.
-void NGLineBreaker::ComputeBaseDirection() {
+void NGLineBreaker::ComputeBaseDirection(const NGLineInfo& line_info) {
// If 'unicode-bidi' is not 'plaintext', use the base direction of the block.
if (!previous_line_had_forced_break_ ||
node_.Style().GetUnicodeBidi() != UnicodeBidi::kPlaintext)
return;
// If 'unicode-bidi: plaintext', compute the base direction for each paragraph
// (separated by forced break.)
- const String& text = node_.Text();
+ const String& text = line_info.ItemsData().text_content;
if (text.Is8Bit())
return;
size_t end_offset = text.find(kNewlineCharacter, offset_);
- base_direction_ = NGBidiParagraph::BaseDirectionForString(node_.Text(
- offset_, end_offset == kNotFound ? text.length() : end_offset));
+ base_direction_ = NGBidiParagraph::BaseDirectionForString(
+ end_offset == kNotFound
+ ? StringView(text, offset_)
+ : StringView(text, offset_, end_offset - offset_));
}
// Initialize internal states for the next line.
-void NGLineBreaker::PrepareNextLine(const NGLayoutOpportunity& opportunity,
- NGLineInfo* line_info) {
+void NGLineBreaker::PrepareNextLine(
+ const NGLineLayoutOpportunity& line_opportunity,
+ NGLineInfo* line_info) {
NGInlineItemResults* item_results = &line_info->Results();
item_results->clear();
line_info->SetStartOffset(offset_);
- line_info->SetLineStyle(node_, constraint_space_, IsFirstFormattedLine(),
- previous_line_had_forced_break_);
+ line_info->SetLineStyle(
+ node_, items_data_, constraint_space_, line_.is_first_formatted_line,
+ line_.use_first_line_style, previous_line_had_forced_break_);
// Set the initial style of this line from the break token. Example:
// <p>...<span>....</span></p>
// When the line wraps in <span>, the 2nd line needs to start with the style
// of the <span>.
override_break_anywhere_ = false;
SetCurrentStyle(current_style_ ? *current_style_ : line_info->LineStyle());
- ComputeBaseDirection();
+ ComputeBaseDirection(*line_info);
line_info->SetBaseDirection(base_direction_);
line_.is_after_forced_break = false;
@@ -168,17 +182,12 @@ void NGLineBreaker::PrepareNextLine(const NGLayoutOpportunity& opportunity,
// regardless of 'text-indent'.
line_.position = line_info->TextIndent();
- line_.opportunity = opportunity;
- line_.line_left_bfc_offset = opportunity.rect.LineStartOffset();
- line_.line_right_bfc_offset = opportunity.rect.LineEndOffset();
- bfc_block_offset_ = opportunity.rect.BlockStartOffset();
+ line_.line_opportunity = line_opportunity;
}
-bool NGLineBreaker::NextLine(const NGLayoutOpportunity& opportunity,
+bool NGLineBreaker::NextLine(const NGLineLayoutOpportunity& line_opportunity,
NGLineInfo* line_info) {
- bfc_block_offset_ = constraint_space_.BfcOffset().block_offset;
-
- PrepareNextLine(opportunity, line_info);
+ PrepareNextLine(line_opportunity, line_info);
BreakLine(line_info);
if (line_info->Results().IsEmpty())
@@ -186,22 +195,15 @@ bool NGLineBreaker::NextLine(const NGLayoutOpportunity& opportunity,
// TODO(kojii): There are cases where we need to PlaceItems() without creating
// line boxes. These cases need to be reviewed.
- if (line_.should_create_line_box) {
- if (!line_.CanFit() &&
- node_.GetLayoutBlockFlow()->ShouldTruncateOverflowingText()) {
- TruncateOverflowingText(line_info);
- }
-
+ if (line_.should_create_line_box)
ComputeLineLocation(line_info);
- }
return true;
}
void NGLineBreaker::BreakLine(NGLineInfo* line_info) {
NGInlineItemResults* item_results = &line_info->Results();
- const Vector<NGInlineItem>& items =
- node_.Items(line_info->UseFirstLineStyle());
+ const Vector<NGInlineItem>& items = line_info->ItemsData().items;
LineBreakState state = LineBreakState::kContinue;
while (state != LineBreakState::kDone) {
// Check overflow even if |item_index_| is at the end of the block, because
@@ -214,6 +216,7 @@ void NGLineBreaker::BreakLine(NGLineInfo* line_info) {
// If we reach at the end of the block, this is the last line.
DCHECK_LE(item_index_, items.size());
if (item_index_ == items.size()) {
+ RemoveTrailingCollapsibleSpace(line_info);
line_info->SetIsLastLine(true);
return;
}
@@ -255,7 +258,7 @@ void NGLineBreaker::BreakLine(NGLineInfo* line_info) {
} else if (item.Type() == NGInlineItem::kOpenTag) {
HandleOpenTag(item, AddItem(item, item_results));
} else if (item.Type() == NGInlineItem::kFloating) {
- HandleFloat(item, AddItem(item, item_results));
+ HandleFloat(item, line_info, AddItem(item, item_results));
} else if (item.Type() == NGInlineItem::kOutOfFlowPositioned) {
DCHECK_EQ(item.Length(), 0u);
AddItem(item, item_results);
@@ -291,14 +294,14 @@ void NGLineBreaker::UpdatePosition(const NGInlineItemResults& results) {
}
void NGLineBreaker::ComputeLineLocation(NGLineInfo* line_info) const {
- LayoutUnit bfc_line_offset = line_.line_left_bfc_offset;
+ LayoutUnit bfc_line_offset = line_.line_opportunity.line_left_offset;
LayoutUnit available_width = line_.AvailableWidth();
// Negative margins can make the position negative, but the inline size is
// always positive or 0.
- line_info->SetLineBfcOffset({bfc_line_offset, bfc_block_offset_},
- available_width,
- line_.position.ClampNegativeToZero());
+ line_info->SetLineBfcOffset(
+ {bfc_line_offset, line_.line_opportunity.bfc_block_offset},
+ available_width, line_.position.ClampNegativeToZero());
}
NGLineBreaker::LineBreakState NGLineBreaker::HandleText(
@@ -394,7 +397,7 @@ void NGLineBreaker::BreakText(NGInlineItemResult* item_result,
// * If offset == item.EndOffset(): the break opportunity at the end fits,
// or the first break opportunity is beyond the end.
// There may be room for more characters.
- // * If width > available_width: The first break opporunity does not fit.
+ // * If width > available_width: The first break opportunity does not fit.
// offset is the first break opportunity, either inside, at the end, or
// beyond the end.
if (item_result->end_offset < item.EndOffset()) {
@@ -438,6 +441,7 @@ NGLineBreaker::LineBreakState NGLineBreaker::HandleTrailingSpaces(
NGInlineItemResult* item_result = AddItem(item, end, item_results);
item_result->has_only_trailing_spaces = true;
+ // TODO(kojii): Should reshape if it's not safe to break.
item_result->shape_result = item.TextShapeResult()->SubRange(offset_, end);
item_result->inline_size = item_result->shape_result->SnappedWidth();
line_.position += item_result->inline_size;
@@ -455,6 +459,44 @@ NGLineBreaker::LineBreakState NGLineBreaker::HandleTrailingSpaces(
return LineBreakState::kTrailing;
}
+// Remove trailing collapsible spaces in |line_info|.
+// https://drafts.csswg.org/css-text-3/#white-space-phase-2
+void NGLineBreaker::RemoveTrailingCollapsibleSpace(NGLineInfo* line_info) {
+ NGInlineItemResults* item_results = &line_info->Results();
+ if (item_results->IsEmpty())
+ return;
+ for (auto it = item_results->rbegin(); it != item_results->rend(); ++it) {
+ NGInlineItemResult& item_result = *it;
+ DCHECK(item_result.item);
+ const NGInlineItem& item = *item_result.item;
+ if (item.EndCollapseType() == NGInlineItem::kOpaqueToCollapsing)
+ continue;
+ if (item.Type() != NGInlineItem::kText)
+ return;
+ const String& text = Text();
+ if (text[item_result.end_offset - 1] != kSpaceCharacter)
+ return;
+ DCHECK(item.Style());
+ if (!item.Style()->CollapseWhiteSpace())
+ return;
+
+ // We have a trailing collapsible space. Remove it.
+ line_.position -= item_result.inline_size;
+ --item_result.end_offset;
+ if (item_result.end_offset == item_result.start_offset) {
+ unsigned index = std::distance(item_results->begin(), &item_result);
+ item_results->EraseAt(index);
+ } else {
+ // TODO(kojii): Should reshape if it's not safe to break.
+ item_result.shape_result = item_result.shape_result->SubRange(
+ item_result.start_offset, item_result.end_offset);
+ item_result.inline_size = item_result.shape_result->SnappedWidth();
+ line_.position += item_result.inline_size;
+ }
+ return;
+ }
+}
+
void NGLineBreaker::AppendHyphen(const NGInlineItem& item,
NGLineInfo* line_info) {
DCHECK(item.Style());
@@ -565,16 +607,33 @@ void NGLineBreaker::HandleAtomicInline(const NGInlineItem& item,
line_.should_create_line_box = true;
NGInlineItemResult* item_result = AddItem(item, &line_info->Results());
- item_result->layout_result =
- NGBlockNode(ToLayoutBox(item.GetLayoutObject()))
- .LayoutAtomicInline(constraint_space_,
- line_info->UseFirstLineStyle());
- DCHECK(item_result->layout_result->PhysicalFragment());
-
- item_result->inline_size =
- NGFragment(constraint_space_.GetWritingMode(),
- *item_result->layout_result->PhysicalFragment())
- .InlineSize();
+ // When we're just computing min/max content sizes, we can skip the full
+ // layout and just compute those sizes. On the other hand, for regular
+ // layout we need to do the full layout and get the layout result.
+ // Doing a full layout for min/max content can also have undesirable
+ // side effects when that falls back to legacy layout.
+ if (mode_ == NGLineBreakerMode::kContent) {
+ item_result->layout_result =
+ NGBlockNode(ToLayoutBox(item.GetLayoutObject()))
+ .LayoutAtomicInline(constraint_space_,
+ line_info->LineStyle().GetFontBaseline(),
+ line_info->UseFirstLineStyle());
+ DCHECK(item_result->layout_result->PhysicalFragment());
+
+ item_result->inline_size =
+ NGFragment(constraint_space_.GetWritingMode(),
+ *item_result->layout_result->PhysicalFragment())
+ .InlineSize();
+ } else {
+ NGBlockNode block_node(ToLayoutBox(item.GetLayoutObject()));
+ MinMaxSizeInput input;
+ MinMaxSize sizes = ComputeMinAndMaxContentContribution(
+ constraint_space_.GetWritingMode(), block_node, input,
+ &constraint_space_);
+ item_result->inline_size = mode_ == NGLineBreakerMode::kMinContent
+ ? sizes.min_size
+ : sizes.max_size;
+ }
DCHECK(item.Style());
item_result->margins =
@@ -601,9 +660,8 @@ void NGLineBreaker::HandleAtomicInline(const NGInlineItem& item,
// We have this check if there are already UnpositionedFloats as we aren't
// allowed to position a float "above" another float which has come before us
// in the document.
-//
-// TODO(glebl): Add the support of clearance for inline floats.
void NGLineBreaker::HandleFloat(const NGInlineItem& item,
+ NGLineInfo* line_info,
NGInlineItemResult* item_result) {
// When rewind occurs, an item may be handled multiple times.
// Since floats are put into a separate list, avoid handling same floats
@@ -619,6 +677,13 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item,
if (item_index_ <= handled_floats_end_item_index_ || ignore_floats_)
return;
+ // Floats need to know the current line width to determine whether to put it
+ // into the current line or to the next line. Remove trailing spaces if this
+ // float is trailing, because whitespace should be collapsed across floats,
+ // and this logic requires the width after trailing spaces are collapsed.
+ if (IsTrailing(item, *line_info))
+ RemoveTrailingCollapsibleSpace(line_info);
+
NGBlockNode node(ToLayoutBox(item.GetLayoutObject()));
const ComputedStyle& float_style = node.Style();
@@ -641,49 +706,47 @@ void NGLineBreaker::HandleFloat(const NGInlineItem& item,
margins.InlineSum())
.ClampNegativeToZero();
+ LayoutUnit bfc_block_offset = line_.line_opportunity.bfc_block_offset;
+
// The float should be positioned after the current line if:
- // - It can't fit.
+ // - It can't fit within the non-shape area. (Assuming the current position
+ // also is strictly within the non-shape area).
// - It will be moved down due to block-start edge alignment.
// - It will be moved down due to clearance.
// - We are currently computing our min/max-content size. (We use the
// unpositioned_floats to manually adjust the min/max-content size after
// the line breaker has run).
bool float_after_line =
- !line_.CanFit(inline_margin_size) ||
- exclusion_space_->LastFloatBlockStart() > bfc_block_offset_ ||
+ !line_.CanFloatFit(inline_margin_size) ||
+ exclusion_space_->LastFloatBlockStart() > bfc_block_offset ||
exclusion_space_->ClearanceOffset(float_style.Clear()) >
- bfc_block_offset_ ||
+ bfc_block_offset ||
mode_ != NGLineBreakerMode::kContent;
// Check if we already have a pending float. That's because a float cannot be
// higher than any block or floated box generated before.
if (!unpositioned_floats_->IsEmpty() || float_after_line) {
- unpositioned_floats_->push_back(std::move(unpositioned_float));
+ AddUnpositionedFloat(unpositioned_floats_, container_builder_,
+ std::move(unpositioned_float));
} else {
- LayoutUnit origin_block_offset = bfc_block_offset_;
-
NGPositionedFloat positioned_float = PositionFloat(
- origin_block_offset, constraint_space_.BfcOffset().block_offset,
+ bfc_block_offset, constraint_space_.BfcOffset().block_offset,
unpositioned_float.get(), constraint_space_, exclusion_space_);
positioned_floats_->push_back(positioned_float);
DCHECK_EQ(positioned_float.bfc_offset.block_offset,
- bfc_block_offset_ + margins.block_start);
+ bfc_block_offset + margins.block_start);
- if (float_style.Floating() == EFloat::kLeft) {
- line_.line_left_bfc_offset = std::max(
- line_.line_left_bfc_offset,
- positioned_float.bfc_offset.line_offset + inline_margin_size -
- margins.LineLeft(TextDirection::kLtr));
- } else {
- line_.line_right_bfc_offset =
- std::min(line_.line_right_bfc_offset,
- positioned_float.bfc_offset.line_offset -
- margins.LineLeft(TextDirection::kLtr));
- }
+ NGLayoutOpportunity opportunity = exclusion_space_->FindLayoutOpportunity(
+ {constraint_space_.BfcOffset().line_offset, bfc_block_offset},
+ constraint_space_.AvailableSize().inline_size, NGLogicalSize());
+
+ DCHECK_EQ(bfc_block_offset, opportunity.rect.BlockStartOffset());
+
+ line_.line_opportunity = opportunity.ComputeLineLayoutOpportunity(
+ constraint_space_, line_.line_opportunity.line_block_size,
+ LayoutUnit());
- DCHECK_GE(line_.line_left_bfc_offset, LayoutUnit());
- DCHECK_GE(line_.line_right_bfc_offset, LayoutUnit());
DCHECK_GE(line_.AvailableWidth(), LayoutUnit());
}
}
@@ -783,7 +846,7 @@ void NGLineBreaker::HandleCloseTag(const NGInlineItem& item,
// be a break opportunity after the space. The break_iterator cannot
// compute this because it considers break opportunities are before a run
// of spaces.
- const String& text = node_.Text();
+ const String& text = Text();
if (offset_ < text.length() && IsBreakableSpace(text[offset_])) {
item_result->can_break_after = true;
return;
@@ -858,7 +921,7 @@ NGLineBreaker::LineBreakState NGLineBreaker::HandleOverflow(
#endif
item_index_ = item_result->item_index;
offset_ = item_result->end_offset;
- node_.AssertOffset(item_index_, offset_);
+ items_data_.AssertOffset(item_index_, offset_);
} else {
Rewind(line_info, i + 1);
}
@@ -879,7 +942,7 @@ NGLineBreaker::LineBreakState NGLineBreaker::HandleOverflow(
}
// Let this line overflow.
- // If there was a break opporunity, the overflow should stop there.
+ // If there was a break opportunity, the overflow should stop there.
if (break_before) {
Rewind(line_info, break_before);
return LineBreakState::kTrailing;
@@ -918,8 +981,7 @@ void NGLineBreaker::Rewind(NGLineInfo* line_info, unsigned new_end) {
// paint invalidations, hit testing, etc.
LayoutObject* NGLineBreaker::CurrentLayoutObject(
const NGLineInfo& line_info) const {
- const Vector<NGInlineItem>& items =
- node_.Items(line_info.UseFirstLineStyle());
+ const Vector<NGInlineItem>& items = line_info.ItemsData().items;
DCHECK_LE(item_index_, items.size());
// Find the next item that has LayoutObject. Some items such as bidi controls
// do not have LayoutObject.
@@ -936,56 +998,6 @@ LayoutObject* NGLineBreaker::CurrentLayoutObject(
return nullptr;
}
-// Truncate overflowing text and append ellipsis.
-void NGLineBreaker::TruncateOverflowingText(NGLineInfo* line_info) {
- // The ellipsis is styled according to the line style.
- const Font& font = line_info->LineStyle().GetFont();
- const SimpleFontData* font_data = font.PrimaryFont();
- DCHECK(font_data);
- String ellipsis =
- font_data && font_data->GlyphForCharacter(kHorizontalEllipsisCharacter)
- ? String(&kHorizontalEllipsisCharacter, 1)
- : String(u"...");
- HarfBuzzShaper shaper(ellipsis.Characters16(), ellipsis.length());
- scoped_refptr<ShapeResult> shape_result =
- shaper.Shape(&font, line_info->BaseDirection());
-
- // Truncate the line to (available_width - ellipsis_width) using 'line-break:
- // anywhere'.
- unsigned saved_item_index = item_index_;
- unsigned saved_offset = offset_;
- override_break_anywhere_ = true;
- break_iterator_.SetBreakType(LineBreakType::kBreakCharacter);
- HandleOverflow(line_info,
- line_.AvailableWidth() - shape_result->SnappedWidth());
-
- // Find the LayoutObject this ellpsis is tied to.
- LayoutObject* layout_object = CurrentLayoutObject(*line_info);
-
- // Restore item_index/offset to before HandleOverflow().
- item_index_ = saved_item_index;
- offset_ = saved_offset;
-
- // Ellipsis should not have text decorations. Reset if it's set.
- scoped_refptr<const ComputedStyle> style = &line_info->LineStyle();
- if (style->TextDecorationsInEffect() != TextDecoration::kNone) {
- scoped_refptr<ComputedStyle> ellipsis_style =
- ComputedStyle::CreateAnonymousStyleWithDisplay(*style,
- EDisplay::kInline);
- ellipsis_style->ResetTextDecoration();
- ellipsis_style->ClearAppliedTextDecorations();
- style = std::move(ellipsis_style);
- }
-
- // The ellipsis should appear at the logical end of the line.
- // This is stored seprately from other results so that it can be appended
- // after bidi reorder.
- NGTextFragmentBuilder builder(node_, constraint_space_.GetWritingMode());
- builder.SetText(layout_object, ellipsis, style, true /* is_ellipsis_style */,
- std::move(shape_result));
- SetLineEndFragment(builder.ToTextFragment(), line_info);
-}
-
void NGLineBreaker::SetCurrentStyle(const ComputedStyle& style) {
current_style_ = &style;
@@ -1041,7 +1053,7 @@ void NGLineBreaker::MoveToNextOf(const NGInlineItemResult& item_result) {
scoped_refptr<NGInlineBreakToken> NGLineBreaker::CreateBreakToken(
const NGLineInfo& line_info,
std::unique_ptr<const NGInlineLayoutStateStack> state_stack) const {
- const Vector<NGInlineItem>& items = node_.Items();
+ const Vector<NGInlineItem>& items = Items();
if (item_index_ >= items.size())
return NGInlineBreakToken::Create(node_);
return NGInlineBreakToken::Create(
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 98e15a95b37..b0838c40a67 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
@@ -6,7 +6,7 @@
#define NGLineBreaker_h
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_layout_opportunity.h"
+#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_line_layout_opportunity.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper.h"
@@ -17,10 +17,12 @@
namespace blink {
class Hyphenation;
+class NGContainerFragmentBuilder;
class NGInlineBreakToken;
class NGInlineItem;
class NGInlineLayoutStateStack;
struct NGPositionedFloat;
+struct NGUnpositionedFloat;
// The line breaker needs to know which mode its in to properly handle floats.
enum class NGLineBreakerMode { kContent, kMinContent, kMaxContent };
@@ -38,14 +40,15 @@ class CORE_EXPORT NGLineBreaker {
const NGConstraintSpace&,
Vector<NGPositionedFloat>*,
Vector<scoped_refptr<NGUnpositionedFloat>>*,
+ NGContainerFragmentBuilder* container_builder,
NGExclusionSpace*,
unsigned handled_float_index,
const NGInlineBreakToken* = nullptr);
- ~NGLineBreaker() = default;
+ ~NGLineBreaker();
// Compute the next line break point and produces NGInlineItemResults for
// the line.
- bool NextLine(const NGLayoutOpportunity&, NGLineInfo*);
+ bool NextLine(const NGLineLayoutOpportunity& line_opportunity, NGLineInfo*);
// Create an NGInlineBreakToken for the last line returned by NextLine().
scoped_refptr<NGInlineBreakToken> CreateBreakToken(
@@ -63,15 +66,19 @@ class CORE_EXPORT NGLineBreaker {
struct LineData {
STACK_ALLOCATED();
+ LineData(NGInlineNode node, const NGInlineBreakToken* break_token);
+
// The current position from inline_start. Unlike NGInlineLayoutAlgorithm
// that computes position in visual order, this position in logical order.
LayoutUnit position;
- // The current opportunity.
- NGLayoutOpportunity opportunity;
+ NGLineLayoutOpportunity line_opportunity;
+
+ // True if this line is the "first formatted line".
+ // https://www.w3.org/TR/CSS22/selector.html#first-formatted-line
+ bool is_first_formatted_line;
- LayoutUnit line_left_bfc_offset;
- LayoutUnit line_right_bfc_offset;
+ bool use_first_line_style;
// We don't create "certain zero-height line boxes".
// https://drafts.csswg.org/css2/visuren.html#phantom-line-box
@@ -85,16 +92,20 @@ class CORE_EXPORT NGLineBreaker {
bool is_after_forced_break = false;
LayoutUnit AvailableWidth() const {
- DCHECK_GE(line_right_bfc_offset, line_left_bfc_offset);
- return line_right_bfc_offset - line_left_bfc_offset;
+ return line_opportunity.AvailableInlineSize();
}
bool CanFit() const { return position <= AvailableWidth(); }
bool CanFit(LayoutUnit extra) const {
return position + extra <= AvailableWidth();
}
+ bool CanFloatFit(LayoutUnit extra) const {
+ return position + extra <= line_opportunity.AvailableFloatInlineSize();
+ }
};
- const String& Text() const { return break_iterator_.GetString(); }
+ const String& Text() const { return items_data_.text_content; }
+ const Vector<NGInlineItem>& Items() const { return items_data_.items; }
+
NGInlineItemResult* AddItem(const NGInlineItem&,
unsigned end_offset,
NGInlineItemResults*);
@@ -104,7 +115,7 @@ class CORE_EXPORT NGLineBreaker {
void BreakLine(NGLineInfo*);
- void PrepareNextLine(const NGLayoutOpportunity&, NGLineInfo*);
+ void PrepareNextLine(const NGLineLayoutOpportunity&, NGLineInfo*);
void UpdatePosition(const NGInlineItemResults&);
void ComputeLineLocation(NGLineInfo*) const;
@@ -128,6 +139,7 @@ class CORE_EXPORT NGLineBreaker {
LayoutUnit available_width,
NGLineInfo*);
LineBreakState HandleTrailingSpaces(const NGInlineItem&, NGLineInfo*);
+ void RemoveTrailingCollapsibleSpace(NGLineInfo*);
void AppendHyphen(const NGInlineItem& item, NGLineInfo*);
LineBreakState HandleControlItem(const NGInlineItem&,
@@ -137,7 +149,7 @@ class CORE_EXPORT NGLineBreaker {
LineBreakState,
NGLineInfo*);
void HandleAtomicInline(const NGInlineItem&, NGLineInfo*);
- void HandleFloat(const NGInlineItem&, NGInlineItemResult*);
+ void HandleFloat(const NGInlineItem&, NGLineInfo*, NGInlineItemResult*);
void HandleOpenTag(const NGInlineItem&, NGInlineItemResult*);
void HandleCloseTag(const NGInlineItem&, NGInlineItemResults*);
@@ -147,33 +159,33 @@ class CORE_EXPORT NGLineBreaker {
void Rewind(NGLineInfo*, unsigned new_end);
LayoutObject* CurrentLayoutObject(const NGLineInfo&) const;
- void TruncateOverflowingText(NGLineInfo*);
void SetCurrentStyle(const ComputedStyle&);
void MoveToNextOf(const NGInlineItem&);
void MoveToNextOf(const NGInlineItemResult&);
- bool IsFirstFormattedLine() const;
- void ComputeBaseDirection();
+ void ComputeBaseDirection(const NGLineInfo&);
+ bool IsTrailing(const NGInlineItem&, const NGLineInfo&) const;
LineData line_;
NGInlineNode node_;
+ const NGInlineItemsData& items_data_;
+
NGLineBreakerMode mode_;
const NGConstraintSpace& constraint_space_;
Vector<NGPositionedFloat>* positioned_floats_;
Vector<scoped_refptr<NGUnpositionedFloat>>* unpositioned_floats_;
+ NGContainerFragmentBuilder* container_builder_; /* May be nullptr */
NGExclusionSpace* exclusion_space_;
scoped_refptr<const ComputedStyle> current_style_;
unsigned item_index_ = 0;
unsigned offset_ = 0;
- bool previous_line_had_forced_break_ = false;
- LayoutUnit bfc_line_offset_;
- LayoutUnit bfc_block_offset_;
LazyLineBreakIterator break_iterator_;
HarfBuzzShaper shaper_;
ShapeResultSpacing<String> spacing_;
+ bool previous_line_had_forced_break_ = false;
const Hyphenation* hyphenation_ = nullptr;
// Keep track of handled float items. See HandleFloat().
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 9cf39096049..30c5402b812 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
@@ -11,6 +11,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
namespace blink {
@@ -46,15 +47,14 @@ class NGLineBreakerTest : public NGBaseLayoutAlgorithmTest {
Vector<NGInlineItemResults> lines;
NGExclusionSpace exclusion_space;
- NGLayoutOpportunity opportunity;
- opportunity.rect =
- NGBfcRect(NGBfcOffset(), {available_width, LayoutUnit::Max()});
+ NGLineLayoutOpportunity line_opportunity(available_width);
NGLineInfo line_info;
while (!break_token || !break_token->IsFinished()) {
NGLineBreaker line_breaker(node, NGLineBreakerMode::kContent, *space,
&positioned_floats, &unpositioned_floats,
+ /* container_builder */ nullptr,
&exclusion_space, 0u, break_token.get());
- if (!line_breaker.NextLine(opportunity, &line_info))
+ if (!line_breaker.NextLine(line_opportunity, &line_info))
break;
break_token = line_breaker.CreateBreakToken(line_info, nullptr);
@@ -69,8 +69,11 @@ 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(node.Text(item_result.start_offset, item_result.end_offset));
+ builder.Append(
+ StringView(text, item_result.start_offset,
+ item_result.end_offset - item_result.start_offset));
}
return builder.ToString();
}
@@ -181,7 +184,7 @@ TEST_F(NGLineBreakerTest, OverflowMargin) {
</style>
<div id=container><span>123 456</span> 789</div>
)HTML");
- const Vector<NGInlineItem>& items = node.Items();
+ const Vector<NGInlineItem>& items = node.ItemsData(false).items;
// 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
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.cc
index 44d25987ad9..b83d812d685 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.cc
@@ -15,6 +15,9 @@ NGLineHeightMetrics::NGLineHeightMetrics(const ComputedStyle& style,
Initialize(font_data->GetFontMetrics(), baseline_type);
}
+NGLineHeightMetrics::NGLineHeightMetrics(const ComputedStyle& style)
+ : NGLineHeightMetrics(style, style.GetFontBaseline()) {}
+
NGLineHeightMetrics::NGLineHeightMetrics(const FontMetrics& font_metrics,
FontBaseline baseline_type) {
Initialize(font_metrics, baseline_type);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h
index 8c8c57dc515..978c170044e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h
@@ -25,6 +25,7 @@ struct NGLineHeightMetrics {
// Compute from ComputedStyle, using the font metrics of the prikmary font.
// The leading is not included.
+ NGLineHeightMetrics(const ComputedStyle&);
NGLineHeightMetrics(const ComputedStyle&, FontBaseline);
// Compute from FontMetrics. The leading is not included.
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
new file mode 100644
index 00000000000..ae76600c718
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.cc
@@ -0,0 +1,201 @@
+// 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_line_truncator.h"
+
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item_result.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_text_fragment_builder.h"
+#include "third_party/blink/renderer/platform/fonts/font_baseline.h"
+#include "third_party/blink/renderer/platform/fonts/shaping/harf_buzz_shaper.h"
+
+namespace blink {
+
+namespace {
+
+// Create the style to use for the ellipsis characters.
+//
+// The ellipsis is styled according to the line style.
+// https://drafts.csswg.org/css-ui/#ellipsing-details
+scoped_refptr<const ComputedStyle> CreateEllipsisStyle(
+ scoped_refptr<const ComputedStyle> line_style) {
+ if (line_style->TextDecorationsInEffect() == TextDecoration::kNone)
+ return line_style;
+
+ // Ellipsis should not have text decorations. Reset if it's set.
+ // This is not defined, but 4 impls do this.
+ scoped_refptr<ComputedStyle> ellipsis_style =
+ ComputedStyle::CreateAnonymousStyleWithDisplay(*line_style,
+ EDisplay::kInline);
+ ellipsis_style->ResetTextDecoration();
+ ellipsis_style->ClearAppliedTextDecorations();
+ return ellipsis_style;
+}
+
+} // namespace
+
+NGLineTruncator::NGLineTruncator(NGInlineNode& node,
+ const NGLineInfo& line_info)
+ : node_(node),
+ line_style_(&line_info.LineStyle()),
+ available_width_(line_info.AvailableWidth()),
+ line_direction_(line_info.BaseDirection()) {}
+
+LayoutUnit NGLineTruncator::TruncateLine(
+ LayoutUnit line_width,
+ NGLineBoxFragmentBuilder::ChildList* line_box) {
+ // Shape the ellipsis and compute its inline size.
+ scoped_refptr<const ComputedStyle> ellipsis_style =
+ CreateEllipsisStyle(line_style_);
+ const Font& font = ellipsis_style->GetFont();
+ const SimpleFontData* font_data = font.PrimaryFont();
+ DCHECK(font_data);
+ String ellipsis_text =
+ font_data && font_data->GlyphForCharacter(kHorizontalEllipsisCharacter)
+ ? String(&kHorizontalEllipsisCharacter, 1)
+ : String(u"...");
+ HarfBuzzShaper shaper(ellipsis_text.Characters16(), ellipsis_text.length());
+ scoped_refptr<ShapeResult> ellipsis_shape_result =
+ shaper.Shape(&font, line_direction_);
+ LayoutUnit ellipsis_width = ellipsis_shape_result->SnappedWidth();
+
+ // 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.
+ LayoutUnit ellipsis_inline_offset;
+ const NGPhysicalFragment* ellipsized_fragment = nullptr;
+ 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 (base::Optional<LayoutUnit> candidate = EllipsisOffset(
+ line_width, ellipsis_width, &child == first_child, &child)) {
+ ellipsis_inline_offset = candidate.value();
+ ellipsized_fragment = child.PhysicalFragment();
+ DCHECK(ellipsized_fragment);
+ break;
+ }
+ }
+ } else {
+ NGLineBoxFragmentBuilder::Child* first_child = line_box->LastInFlowChild();
+ ellipsis_inline_offset = available_width_ - ellipsis_width;
+ for (auto& child : *line_box) {
+ if (base::Optional<LayoutUnit> candidate = EllipsisOffset(
+ line_width, ellipsis_width, &child == first_child, &child)) {
+ ellipsis_inline_offset = candidate.value();
+ ellipsized_fragment = child.PhysicalFragment();
+ DCHECK(ellipsized_fragment);
+ break;
+ }
+ }
+ }
+
+ // Abort if ellipsis could not be placed.
+ if (!ellipsized_fragment)
+ return line_width;
+
+ // Now the offset of the ellpisis is determined. Place the ellpisis into the
+ // line box.
+ NGTextFragmentBuilder builder(node_, line_style_->GetWritingMode());
+ DCHECK(ellipsized_fragment->GetLayoutObject() &&
+ ellipsized_fragment->GetLayoutObject()->IsInline());
+ builder.SetText(ellipsized_fragment->GetLayoutObject(), ellipsis_text,
+ ellipsis_style, true /* is_ellipsis_style */,
+ std::move(ellipsis_shape_result));
+ FontBaseline baseline_type = line_style_->GetFontBaseline();
+ NGLineHeightMetrics ellipsis_metrics(font_data->GetFontMetrics(),
+ baseline_type);
+ line_box->AddChild(
+ builder.ToTextFragment(),
+ NGLogicalOffset{ellipsis_inline_offset, -ellipsis_metrics.ascent},
+ ellipsis_width, 0);
+ return std::max(ellipsis_inline_offset + ellipsis_width, line_width);
+}
+
+// Return the offset to place the ellipsis.
+//
+// This function may truncate or move the child so that the ellipsis can fit.
+base::Optional<LayoutUnit> NGLineTruncator::EllipsisOffset(
+ LayoutUnit line_width,
+ LayoutUnit ellipsis_width,
+ bool is_first_child,
+ NGLineBoxFragmentBuilder::Child* child) {
+ // Leave out-of-flow children as is.
+ if (!child->HasInFlowFragment())
+ return base::nullopt;
+
+ // Can't place ellipsis if this child is completely outside of the box.
+ DCHECK_GE(line_width, child->offset.inline_offset + child->inline_size);
+ LayoutUnit child_inline_offset =
+ IsLtr(line_direction_)
+ ? child->offset.inline_offset
+ : line_width - (child->offset.inline_offset + child->inline_size);
+ LayoutUnit space_for_child = available_width_ - child_inline_offset;
+ if (space_for_child <= 0)
+ return base::nullopt;
+
+ // If not all of this child can fit, try to truncate.
+ space_for_child -= ellipsis_width;
+ if (space_for_child < child->inline_size &&
+ !TruncateChild(space_for_child, is_first_child, child)) {
+ // This child maybe partially visible. When it can't be truncated, move it
+ // out so that none of this child should be visible.
+ child->offset.inline_offset = line_width;
+ return base::nullopt;
+ }
+
+ return IsLtr(line_direction_)
+ ? child->offset.inline_offset + child->inline_size
+ : child->offset.inline_offset - ellipsis_width;
+}
+
+// Truncate the specified child. Returns true if truncated successfully, false
+// otherwise.
+//
+// Note that this function may return true even if it can't fit the child when
+// |is_first_child|, because the spec defines that the first character or atomic
+// inline-level element on a line must be clipped rather than ellipsed.
+// https://drafts.csswg.org/css-ui/#text-overflow
+bool NGLineTruncator::TruncateChild(LayoutUnit space_for_child,
+ bool is_first_child,
+ NGLineBoxFragmentBuilder::Child* child) {
+ // If the space is not enough, try the next child.
+ if (space_for_child <= 0 && !is_first_child)
+ return false;
+
+ // Only text fragments can be truncated.
+ if (!child->fragment)
+ return is_first_child;
+ auto& fragment = ToNGPhysicalTextFragment(*child->fragment);
+ const ShapeResult* shape_result = fragment.TextShapeResult();
+ if (!shape_result)
+ return is_first_child;
+
+ // Compute the offset to truncate.
+ unsigned new_length = shape_result->OffsetToFit(
+ IsLtr(line_direction_) ? space_for_child
+ : shape_result->Width() - space_for_child,
+ line_direction_);
+ if (!new_length || new_length == fragment.Length()) {
+ if (!is_first_child)
+ return false;
+ new_length = !new_length ? 1 : new_length - 1;
+ }
+
+ // Truncate the text fragment.
+ child->fragment = line_direction_ == shape_result->Direction()
+ ? fragment.TrimText(fragment.StartOffset(),
+ fragment.StartOffset() + new_length)
+ : fragment.TrimText(fragment.StartOffset() + new_length,
+ fragment.EndOffset());
+ LayoutUnit new_inline_size = line_style_->IsHorizontalWritingMode()
+ ? child->fragment->Size().width
+ : child->fragment->Size().height;
+ DCHECK_LE(new_inline_size, child->inline_size);
+ if (UNLIKELY(IsRtl(line_direction_)))
+ child->offset.inline_offset += child->inline_size - new_inline_size;
+ child->inline_size = new_inline_size;
+ return true;
+}
+
+} // namespace blink
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
new file mode 100644
index 00000000000..adfcd22ad9c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_truncator.h
@@ -0,0 +1,51 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_TRUNCATOR_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_TRUNCATOR_H_
+
+#include "base/optional.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_box_fragment_builder.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
+
+namespace blink {
+
+class NGLineInfo;
+
+// A class to truncate lines and place ellipsis, invoked by the CSS
+// 'text-overflow: ellipsis' property.
+// https://drafts.csswg.org/css-ui/#overflow-ellipsis
+class CORE_EXPORT NGLineTruncator final {
+ STACK_ALLOCATED();
+
+ public:
+ NGLineTruncator(NGInlineNode& node, const NGLineInfo& line_info);
+
+ // Truncate |line_box| and place ellipsis. Returns the new inline-size of the
+ // |line_box|.
+ //
+ // |line_box| should be after bidi reorder, but before box fragments are
+ // created.
+ LayoutUnit TruncateLine(LayoutUnit line_width,
+ NGLineBoxFragmentBuilder::ChildList* line_box);
+
+ private:
+ base::Optional<LayoutUnit> EllipsisOffset(LayoutUnit line_width,
+ LayoutUnit ellipsis_width,
+ bool is_first_child,
+ NGLineBoxFragmentBuilder::Child*);
+ bool TruncateChild(LayoutUnit space_for_this_child,
+ bool is_first_child,
+ NGLineBoxFragmentBuilder::Child* child);
+
+ NGInlineNode& node_;
+ scoped_refptr<const ComputedStyle> line_style_;
+ LayoutUnit available_width_;
+ TextDirection line_direction_;
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_TRUNCATOR_H_
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_utils.cc
new file mode 100644
index 00000000000..d4c9f60a712
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_utils.cc
@@ -0,0 +1,31 @@
+// 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_line_utils.h"
+
+#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_caret_position.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
+
+namespace blink {
+
+const NGPaintFragment* NGContainingLineBoxOf(
+ const PositionWithAffinity& position) {
+ const NGCaretPosition caret_position = ComputeNGCaretPosition(position);
+ if (caret_position.IsNull())
+ return nullptr;
+ return caret_position.fragment->ContainerLineBox();
+}
+
+bool InSameNGLineBox(const PositionWithAffinity& position1,
+ const PositionWithAffinity& position2) {
+ const NGPaintFragment* line_box1 = NGContainingLineBoxOf(position1);
+ if (!line_box1)
+ return false;
+
+ const NGPaintFragment* line_box2 = NGContainingLineBoxOf(position2);
+ return line_box1 == line_box2;
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_utils.h
new file mode 100644
index 00000000000..e77e8dbde26
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_line_utils.h
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_UTILS_H_
+
+#include "third_party/blink/renderer/core/editing/forward.h"
+
+namespace blink {
+
+class NGPaintFragment;
+
+// Returns the NG line box fragment containing the caret position of the given
+// position. Returns false if the position is not in Layout NG, or does not
+// have any caret position.
+const NGPaintFragment* NGContainingLineBoxOf(const PositionWithAffinity&);
+
+// Returns true if the caret positions of the two positions are in the same NG
+// line box. Returns false in all other cases.
+bool InSameNGLineBox(const PositionWithAffinity&, const PositionWithAffinity&);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_INLINE_NG_LINE_UTILS_H_
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 ff4406cef52..46e7077f983 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
@@ -10,6 +10,7 @@
#include "third_party/blink/renderer/core/editing/position.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
#include "third_party/blink/renderer/core/layout/ng/ng_block_node.h"
+#include "third_party/blink/renderer/platform/text/character.h"
namespace blink {
@@ -247,13 +248,13 @@ NGMappingUnitRange NGOffsetMapping::GetMappingUnitsForDOMRange(
return {result_begin, result_end};
}
-Optional<unsigned> NGOffsetMapping::GetTextContentOffset(
+base::Optional<unsigned> NGOffsetMapping::GetTextContentOffset(
const Position& position) const {
DCHECK(NGOffsetMapping::AcceptsPosition(position)) << position;
if (IsNonAtomicInline(*position.AnchorNode())) {
auto iter = ranges_.find(position.AnchorNode());
if (iter == ranges_.end())
- return WTF::nullopt;
+ return base::nullopt;
DCHECK_NE(iter->value.first, iter->value.second) << position;
if (position.IsBeforeAnchor())
return units_[iter->value.first].TextContentStart();
@@ -262,7 +263,7 @@ Optional<unsigned> NGOffsetMapping::GetTextContentOffset(
const NGOffsetMappingUnit* unit = GetMappingUnitForPosition(position);
if (!unit)
- return WTF::nullopt;
+ return base::nullopt;
return unit->ConvertDOMOffsetToTextContent(ToNodeOffsetPair(position).second);
}
@@ -339,13 +340,13 @@ bool NGOffsetMapping::IsAfterNonCollapsedContent(
unit->GetType() != NGOffsetMappingUnitType::kCollapsed;
}
-Optional<UChar> NGOffsetMapping::GetCharacterBefore(
+base::Optional<UChar> NGOffsetMapping::GetCharacterBefore(
const Position& position) const {
DCHECK(NGOffsetMapping::AcceptsPosition(position));
DCHECK(!IsNonAtomicInline(*position.AnchorNode())) << position;
- Optional<unsigned> text_content_offset = GetTextContentOffset(position);
+ base::Optional<unsigned> text_content_offset = GetTextContentOffset(position);
if (!text_content_offset || !*text_content_offset)
- return WTF::nullopt;
+ return base::nullopt;
return text_[*text_content_offset - 1];
}
@@ -385,4 +386,15 @@ Position NGOffsetMapping::GetLastPosition(unsigned offset) const {
return CreatePositionForOffsetMapping(node, dom_offset);
}
+bool NGOffsetMapping::HasBidiControlCharactersOnly(unsigned start,
+ unsigned end) const {
+ DCHECK_LE(start, end);
+ DCHECK_LE(end, text_.length());
+ for (unsigned i = start; i < end; ++i) {
+ if (!Character::IsBidiControl(text_[i]))
+ return false;
+ }
+ return true;
+}
+
} // namespace blink
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 f4ea52ba8f5..efb2769eb30 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
@@ -5,12 +5,13 @@
#ifndef NGOffsetMapping_h
#define NGOffsetMapping_h
+#include "base/optional.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -18,7 +19,6 @@ namespace blink {
class LayoutBlockFlow;
class LayoutObject;
-class Node;
enum class NGOffsetMappingUnitType { kIdentity, kCollapsed, kExpanded };
@@ -134,7 +134,7 @@ class CORE_EXPORT NGOffsetMapping {
// Returns the text content offset corresponding to the given position.
// Returns nullopt when the position is not laid out in this context.
- Optional<unsigned> GetTextContentOffset(const Position&) const;
+ base::Optional<unsigned> GetTextContentOffset(const Position&) const;
// Starting from the given position, searches for non-collapsed content in
// the anchor node in forward/backward direction and returns the position
@@ -151,7 +151,7 @@ class CORE_EXPORT NGOffsetMapping {
// Maps the given position to a text content offset, and then returns the text
// content character before the offset. Returns nullopt if it does not exist.
- Optional<UChar> GetCharacterBefore(const Position&) const;
+ base::Optional<UChar> GetCharacterBefore(const Position&) const;
// ------ Mapping APIs from text content to DOM ------
@@ -172,6 +172,12 @@ class CORE_EXPORT NGOffsetMapping {
// TODO(xiaochengh): Add offset-to-DOM APIs skipping generated contents.
+ // ------ APIs inspecting the text content string ------
+
+ // Returns false if all characters in [start, end) of |text_| are bidi
+ // control charcters. Returns true otherwise.
+ bool HasBidiControlCharactersOnly(unsigned start, unsigned end) const;
+
private:
// The NGOffsetMappingUnits of the inline formatting context in osrted order.
UnitVector units_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h
index 8451f04475a..716d3ac760e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_offset_mapping_builder.h
@@ -5,9 +5,9 @@
#ifndef NGOffsetMappingBuilder_h
#define NGOffsetMappingBuilder_h
+#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/auto_reset.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
@@ -80,7 +80,7 @@ class CORE_EXPORT NGOffsetMappingBuilder {
~SourceNodeScope();
private:
- AutoReset<const LayoutObject*> auto_reset_;
+ base::AutoReset<const LayoutObject*> auto_reset_;
#if DCHECK_IS_ON()
NGOffsetMappingBuilder* builder_ = nullptr;
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 39232f8ad19..1036a000106 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
@@ -40,7 +40,7 @@ class NGOffsetMappingTest : public NGLayoutTest {
}
bool IsOffsetMappingStored() const {
- return layout_block_flow_->GetNGInlineNodeData()->offset_mapping_.get();
+ return layout_block_flow_->GetNGInlineNodeData()->offset_mapping.get();
}
const LayoutText* GetLayoutTextUnder(const char* parent_id) {
@@ -53,7 +53,8 @@ class NGOffsetMappingTest : public NGLayoutTest {
return GetOffsetMapping().GetMappingUnitForPosition(position);
}
- Optional<unsigned> GetTextContentOffset(const Position& position) const {
+ base::Optional<unsigned> GetTextContentOffset(
+ const Position& position) const {
return GetOffsetMapping().GetTextContentOffset(position);
}
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 10d79eb6c43..e341ddffdae 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
@@ -5,26 +5,61 @@
#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_inline_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
namespace blink {
+namespace {
+
+static const NGPhysicalFragment* LastLogicalLeafExceptLinebreakInternal(
+ const NGPhysicalFragment& runner,
+ TextDirection direction) {
+ if (runner.IsText()) {
+ if (ToNGPhysicalTextFragment(runner).IsLineBreak())
+ return nullptr;
+ return &runner;
+ }
+ if (!runner.IsContainer() || runner.IsBlockLayoutRoot())
+ return &runner;
+ const auto& children = ToNGPhysicalContainerFragment(runner).Children();
+ for (size_t i = 0; i < children.size(); i++) {
+ // TODO(xiaochengh): This isn't correct for mixed Bidi. Fix it. Besides, we
+ // should compute and store it during layout.
+ // We want a logical last child in a line.
+ const size_t index =
+ direction == TextDirection::kLtr ? (children.size() - 1 - i) : i;
+ const NGPhysicalFragment* child = children[index].get();
+ DCHECK(child);
+ if (const NGPhysicalFragment* candidate =
+ LastLogicalLeafExceptLinebreakInternal(*child, direction))
+ return candidate;
+ }
+ return nullptr;
+}
+
+} // namespace
+
NGPhysicalLineBoxFragment::NGPhysicalLineBoxFragment(
const ComputedStyle& style,
+ NGStyleVariant style_variant,
NGPhysicalSize size,
Vector<scoped_refptr<NGPhysicalFragment>>& children,
const NGPhysicalOffsetRect& contents_visual_rect,
+ const NGPhysicalOffsetRect& scrollable_overflow,
const NGLineHeightMetrics& metrics,
TextDirection base_direction,
scoped_refptr<NGBreakToken> break_token)
: NGPhysicalContainerFragment(nullptr,
style,
+ style_variant,
size,
kFragmentLineBox,
0,
children,
contents_visual_rect,
std::move(break_token)),
+ scrollable_overflow_(scrollable_overflow),
metrics_(metrics) {
base_direction_ = static_cast<unsigned>(base_direction);
}
@@ -80,6 +115,13 @@ const NGPhysicalFragment* NGPhysicalLineBoxFragment::LastLogicalLeaf() const {
return runner;
}
+const NGPhysicalFragment*
+NGPhysicalLineBoxFragment::LastLogicalLeafIgnoringLineBreak() const {
+ if (Children().IsEmpty())
+ return nullptr;
+ return LastLogicalLeafExceptLinebreakInternal(*this, this->BaseDirection());
+}
+
bool NGPhysicalLineBoxFragment::HasSoftWrapToNextLine() const {
DCHECK(BreakToken());
DCHECK(BreakToken()->IsInlineType());
@@ -87,9 +129,4 @@ bool NGPhysicalLineBoxFragment::HasSoftWrapToNextLine() const {
return !break_token.IsFinished() && !break_token.IsForcedBreak();
}
-PositionWithAffinity NGPhysicalLineBoxFragment::PositionForPoint(
- const NGPhysicalOffset& point) const {
- return PositionForPointInInlineLevelBox(point);
-}
-
} // namespace blink
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 02989a0955e..b92b910d2b3 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
@@ -17,9 +17,11 @@ class CORE_EXPORT NGPhysicalLineBoxFragment final
public:
// This modifies the passed-in children vector.
NGPhysicalLineBoxFragment(const ComputedStyle&,
+ NGStyleVariant style_variant,
NGPhysicalSize size,
Vector<scoped_refptr<NGPhysicalFragment>>& children,
const NGPhysicalOffsetRect& contents_visual_rect,
+ const NGPhysicalOffsetRect& scrollable_overflow,
const NGLineHeightMetrics&,
TextDirection base_direction,
scoped_refptr<NGBreakToken> break_token = nullptr);
@@ -39,24 +41,31 @@ class CORE_EXPORT NGPhysicalLineBoxFragment final
// VisualRect of itself including contents, in the local coordinate.
NGPhysicalOffsetRect VisualRectWithContents() const;
+ // Scrollable overflow. including contents, in the local coordinate.
+ NGPhysicalOffsetRect ScrollableOverflow() const {
+ return scrollable_overflow_;
+ }
+
// Returns the first/last leaf fragment in the line in logical order. Returns
// nullptr if the line box is empty.
const NGPhysicalFragment* FirstLogicalLeaf() const;
const NGPhysicalFragment* LastLogicalLeaf() const;
+ // Returns the last leaf fragment in the line in logical order except line
+ // break. Returns nullptr if such fragment doesn't exist.
+ const NGPhysicalFragment* LastLogicalLeafIgnoringLineBreak() const;
// Whether the content soft-wraps to the next line.
bool HasSoftWrapToNextLine() const;
- PositionWithAffinity PositionForPoint(const NGPhysicalOffset&) const final;
-
scoped_refptr<NGPhysicalFragment> CloneWithoutOffset() const {
Vector<scoped_refptr<NGPhysicalFragment>> children_copy(children_);
return base::AdoptRef(new NGPhysicalLineBoxFragment(
- Style(), size_, children_copy, contents_visual_rect_, metrics_,
- BaseDirection(), break_token_));
+ Style(), StyleVariant(), size_, children_copy, contents_visual_rect_,
+ scrollable_overflow_, metrics_, BaseDirection(), break_token_));
}
private:
+ NGPhysicalOffsetRect scrollable_overflow_;
NGLineHeightMetrics metrics_;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc
index cd44fd8ea05..331fb87d70b 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment_test.cc
@@ -59,6 +59,7 @@ TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafInSimpleText) {
"</div>");
EXPECT_TEXT_FRAGMENT("foo", GetLineBox()->FirstLogicalLeaf());
EXPECT_TEXT_FRAGMENT("bar", GetLineBox()->LastLogicalLeaf());
+ EXPECT_TEXT_FRAGMENT("bar", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
}
TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafInRtlText) {
@@ -69,6 +70,7 @@ TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafInRtlText) {
"</bdo>");
EXPECT_TEXT_FRAGMENT("foo", GetLineBox()->FirstLogicalLeaf());
EXPECT_TEXT_FRAGMENT("bar", GetLineBox()->LastLogicalLeaf());
+ EXPECT_TEXT_FRAGMENT("bar", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
}
TEST_F(NGPhysicalLineBoxFragmentTest,
@@ -81,6 +83,7 @@ TEST_F(NGPhysicalLineBoxFragmentTest,
"</div>");
EXPECT_TEXT_FRAGMENT("f", GetLineBox()->FirstLogicalLeaf());
EXPECT_TEXT_FRAGMENT("r", GetLineBox()->LastLogicalLeaf());
+ EXPECT_TEXT_FRAGMENT("r", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
}
TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafWithInlineBlock) {
@@ -92,12 +95,26 @@ TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafWithInlineBlock) {
"</div>");
EXPECT_BOX_FRAGMENT("foo", GetLineBox()->FirstLogicalLeaf());
EXPECT_BOX_FRAGMENT("baz", GetLineBox()->LastLogicalLeaf());
+ EXPECT_BOX_FRAGMENT("baz", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
}
TEST_F(NGPhysicalLineBoxFragmentTest, FirstLastLogicalLeafWithImages) {
SetBodyInnerHTML("<div id=root><img id=img1>foo<img id=img2></div>");
EXPECT_BOX_FRAGMENT("img1", GetLineBox()->FirstLogicalLeaf());
EXPECT_BOX_FRAGMENT("img2", GetLineBox()->LastLogicalLeaf());
+ EXPECT_BOX_FRAGMENT("img2", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
+}
+
+TEST_F(NGPhysicalLineBoxFragmentTest, LastLogicalLeafSoftWrap) {
+ SetBodyInnerHTML("<div id=root style='width: 2em'>foo bar</div>");
+ EXPECT_TEXT_FRAGMENT("foo", GetLineBox()->LastLogicalLeaf());
+ EXPECT_TEXT_FRAGMENT("foo", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
+}
+
+TEST_F(NGPhysicalLineBoxFragmentTest, LastLogicalLeafHardWrap) {
+ SetBodyInnerHTML("<div id=root>foo<br>bar</div>");
+ EXPECT_TEXT_FRAGMENT("\n", GetLineBox()->LastLogicalLeaf());
+ EXPECT_TEXT_FRAGMENT("foo", GetLineBox()->LastLogicalLeafIgnoringLineBreak());
}
} // namespace blink
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 848ed377dd8..d75f591cc0f 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
@@ -5,16 +5,31 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/dom/node.h"
-#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
#include "third_party/blink/renderer/core/layout/layout_text_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_rect.h"
+#include "third_party/blink/renderer/core/layout/line/line_orientation_utils.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.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_offset_mapping.h"
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_item.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
namespace blink {
+// Convert logical cooridnate to local physical coordinate.
+NGPhysicalOffsetRect NGPhysicalTextFragment::ConvertToLocal(
+ const LayoutRect& logical_rect) const {
+ switch (LineOrientation()) {
+ case NGLineOrientation::kHorizontal:
+ return NGPhysicalOffsetRect(logical_rect);
+ case NGLineOrientation::kClockWiseVertical:
+ return {{size_.width - logical_rect.MaxY(), logical_rect.X()},
+ {logical_rect.Height(), logical_rect.Width()}};
+ case NGLineOrientation::kCounterClockWiseVertical:
+ return {{logical_rect.Y(), size_.height - logical_rect.MaxX()},
+ {logical_rect.Height(), logical_rect.Width()}};
+ }
+ NOTREACHED();
+ return NGPhysicalOffsetRect(logical_rect);
+}
+
// Compute the inline position from text offset, in logical coordinate relative
// to this fragment.
LayoutUnit NGPhysicalTextFragment::InlinePositionForOffset(
@@ -75,8 +90,8 @@ NGPhysicalOffsetRect NGPhysicalTextFragment::LocalRect(
}
NGPhysicalOffsetRect NGPhysicalTextFragment::SelfVisualRect() const {
- if (!shape_result_)
- return {};
+ if (UNLIKELY(!shape_result_))
+ return LocalRect();
// Glyph bounds is in logical coordinate, origin at the alphabetic baseline.
LayoutRect visual_rect = EnclosingLayoutRect(shape_result_->Bounds());
@@ -84,8 +99,7 @@ NGPhysicalOffsetRect NGPhysicalTextFragment::SelfVisualRect() const {
// Make the origin at the logical top of this fragment.
const ComputedStyle& style = Style();
const Font& font = style.GetFont();
- const SimpleFontData* font_data = font.PrimaryFont();
- if (font_data) {
+ if (const SimpleFontData* font_data = font.PrimaryFont()) {
visual_rect.SetY(visual_rect.Y() + font_data->GetFontMetrics().FixedAscent(
kAlphabeticBaseline));
}
@@ -111,26 +125,38 @@ NGPhysicalOffsetRect NGPhysicalTextFragment::SelfVisualRect() const {
if (ShadowList* text_shadow = style.TextShadow()) {
LayoutRectOutsets text_shadow_logical_outsets =
- LayoutRectOutsets(text_shadow->RectOutsetsIncludingOriginal())
- .LineOrientationOutsets(style.GetWritingMode());
+ LineOrientationLayoutRectOutsets(
+ LayoutRectOutsets(text_shadow->RectOutsetsIncludingOriginal()),
+ style.GetWritingMode());
text_shadow_logical_outsets.ClampNegativeToZero();
visual_rect.Expand(text_shadow_logical_outsets);
}
visual_rect = LayoutRect(EnclosingIntRect(visual_rect));
- switch (LineOrientation()) {
- case NGLineOrientation::kHorizontal:
- return NGPhysicalOffsetRect(visual_rect);
- case NGLineOrientation::kClockWiseVertical:
- return {{size_.width - visual_rect.MaxY(), visual_rect.X()},
- {visual_rect.Height(), visual_rect.Width()}};
- case NGLineOrientation::kCounterClockWiseVertical:
- return {{visual_rect.Y(), size_.height - visual_rect.MaxX()},
- {visual_rect.Height(), visual_rect.Width()}};
- }
- NOTREACHED();
- return {};
+ // Uniting the frame rect ensures that non-ink spaces such side bearings, or
+ // even space characters, are included in the visual rect for decorations.
+ NGPhysicalOffsetRect local_visual_rect = ConvertToLocal(visual_rect);
+ local_visual_rect.Unite(LocalRect());
+ return local_visual_rect;
+}
+
+scoped_refptr<NGPhysicalFragment> NGPhysicalTextFragment::TrimText(
+ unsigned new_start_offset,
+ unsigned new_end_offset) const {
+ DCHECK(shape_result_);
+ DCHECK_GE(new_start_offset, StartOffset());
+ DCHECK_GT(new_end_offset, new_start_offset);
+ DCHECK_LE(new_end_offset, EndOffset());
+ scoped_refptr<ShapeResult> new_shape_result =
+ shape_result_->SubRange(new_start_offset, new_end_offset);
+ LayoutUnit new_inline_size = new_shape_result->SnappedWidth();
+ return base::AdoptRef(new NGPhysicalTextFragment(
+ layout_object_, Style(), static_cast<NGStyleVariant>(style_variant_),
+ TextType(), text_, new_start_offset, new_end_offset,
+ IsHorizontal() ? NGPhysicalSize{new_inline_size, size_.height}
+ : NGPhysicalSize{size_.width, new_inline_size},
+ LineOrientation(), EndEffect(), std::move(new_shape_result)));
}
scoped_refptr<NGPhysicalFragment> NGPhysicalTextFragment::CloneWithoutOffset()
@@ -164,15 +190,24 @@ unsigned NGPhysicalTextFragment::TextOffsetForPoint(
StartOffset();
}
-PositionWithAffinity NGPhysicalTextFragment::PositionForPoint(
- const NGPhysicalOffset& point) const {
- if (IsAnonymousText())
- return PositionWithAffinity();
- const unsigned text_offset = TextOffsetForPoint(point);
- const Position position =
- NGOffsetMapping::GetFor(GetLayoutObject())->GetFirstPosition(text_offset);
- // TODO(xiaochengh): Adjust TextAffinity.
- return PositionWithAffinity(position, TextAffinity::kDownstream);
+UBiDiLevel NGPhysicalTextFragment::BidiLevel() const {
+ // TODO(xiaochengh): Make the implementation more efficient with, e.g.,
+ // binary search and/or LayoutNGText::InlineItems().
+ const auto& items = InlineItemsOfContainingBlock();
+ const NGInlineItem* containing_item = std::find_if(
+ items.begin(), items.end(), [this](const NGInlineItem& item) {
+ return item.StartOffset() <= StartOffset() &&
+ item.EndOffset() >= EndOffset();
+ });
+ DCHECK(containing_item);
+ DCHECK_NE(containing_item, items.end());
+ return containing_item->BidiLevel();
+}
+
+TextDirection NGPhysicalTextFragment::ResolvedDirection() const {
+ if (TextShapeResult())
+ return TextShapeResult()->Direction();
+ return NGPhysicalFragment::ResolvedDirection();
}
} // 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 eea1dddd920..f6921d10546 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
@@ -8,7 +8,6 @@
#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/ng_physical_fragment.h"
-#include "third_party/blink/renderer/platform/fonts/font_baseline.h"
#include "third_party/blink/renderer/platform/fonts/ng_text_fragment_paint_info.h"
#include "third_party/blink/renderer/platform/fonts/shaping/shape_result.h"
#include "third_party/blink/renderer/platform/wtf/text/string_view.h"
@@ -16,8 +15,6 @@
namespace blink {
-class ShapeResult;
-
struct NGPhysicalOffsetRect;
enum class AdjustMidCluster;
@@ -104,9 +101,6 @@ class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
bool IsHorizontal() const {
return LineOrientation() == NGLineOrientation::kHorizontal;
}
- FontBaseline BaselineType() const {
- return IsHorizontal() ? kAlphabeticBaseline : kIdeographicBaseline;
- }
// Compute the inline position from text offset, in logical coordinate
// relative to this fragment.
@@ -116,6 +110,7 @@ class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
// Start and end offsets must be between StartOffset() and EndOffset().
NGPhysicalOffsetRect LocalRect(unsigned start_offset,
unsigned end_offset) const;
+ using NGPhysicalFragment::LocalRect;
// The visual bounding box that includes glpyh bounding box and CSS
// properties, in local coordinates.
@@ -125,6 +120,11 @@ class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
return static_cast<NGTextEndEffect>(end_effect_);
}
+ // Create a new fragment that has part of the text of this fragment.
+ // All other properties are the same as this fragment.
+ scoped_refptr<NGPhysicalFragment> TrimText(unsigned start_offset,
+ unsigned end_offset) const;
+
scoped_refptr<NGPhysicalFragment> CloneWithoutOffset() const;
NGTextFragmentPaintInfo PaintInfo() const {
@@ -139,13 +139,16 @@ class CORE_EXPORT NGPhysicalTextFragment final : public NGPhysicalFragment {
// Returns the text offset in the fragment placed closest to the given point.
unsigned TextOffsetForPoint(const NGPhysicalOffset&) const;
- PositionWithAffinity PositionForPoint(const NGPhysicalOffset&) const override;
+ UBiDiLevel BidiLevel() const override;
+ TextDirection ResolvedDirection() const override;
private:
LayoutUnit InlinePositionForOffset(unsigned offset,
LayoutUnit (*round)(float),
AdjustMidCluster) const;
+ NGPhysicalOffsetRect ConvertToLocal(const LayoutRect&) const;
+
// The text of NGInlineNode; i.e., of a parent block. The text for this
// fragment is a substring(start_offset_, end_offset_) of this string.
const String text_;
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 8852bb2da74..9ee319a8d3c 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
@@ -37,13 +37,14 @@ NGTextFragmentBuilder::NGTextFragmentBuilder(NGInlineNode node,
void NGTextFragmentBuilder::SetItem(
NGPhysicalTextFragment::NGTextType text_type,
+ const NGInlineItemsData& items_data,
NGInlineItemResult* item_result,
LayoutUnit line_height) {
DCHECK(item_result);
DCHECK(item_result->item->Style());
text_type_ = text_type;
- text_ = inline_node_.Text();
+ text_ = items_data.text_content;
item_index_ = item_result->item_index;
start_offset_ = item_result->start_offset;
end_offset_ = item_result->end_offset;
@@ -71,11 +72,8 @@ void NGTextFragmentBuilder::SetText(
end_offset_ = shape_result->EndIndexForResult();
SetStyle(style, is_ellipsis_style ? NGStyleVariant::kEllipsis
: NGStyleVariant::kStandard);
- FontBaseline baseline_type = style->IsHorizontalWritingMode()
- ? kAlphabeticBaseline
- : kIdeographicBaseline;
size_ = {shape_result->SnappedWidth(),
- NGLineHeightMetrics(*style, baseline_type).LineHeight()};
+ NGLineHeightMetrics(*style).LineHeight()};
shape_result_ = std::move(shape_result);
layout_object_ = layout_object;
end_effect_ = NGTextEndEffect::kNone;
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 b53ca079a0b..68efb30de15 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
@@ -26,6 +26,7 @@ class CORE_EXPORT NGTextFragmentBuilder final : public NGBaseFragmentBuilder {
// NOTE: Takes ownership of the shape result within the item result.
void SetItem(NGPhysicalTextFragment::NGTextType,
+ const NGInlineItemsData&,
NGInlineItemResult*,
LayoutUnit line_height);
void SetText(LayoutObject*,
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
index 8a0ad1a3f46..6b81fd15240 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.cc
@@ -7,9 +7,11 @@
#include "third_party/blink/renderer/core/layout/layout_analyzer.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_node_data.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.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/paint/paint_layer.h"
namespace blink {
@@ -81,8 +83,8 @@ void LayoutNGBlockFlow::UpdateOutOfFlowBlockLayout() {
container_style->GetWritingMode(), container_style->Direction());
// Compute ContainingBlock logical size.
- // OverrideContainingBlockLogicalWidth/Height are used by e.g. grid layout.
- // Override sizes are padding box size, not border box, so we must add
+ // OverrideContainingBlockContentLogicalWidth/Height are used by e.g. grid
+ // layout. Override sizes are padding box size, not border box, so we must add
// borders and scrollbars to compensate.
NGBoxStrut borders_and_scrollbars =
ComputeBorders(*constraint_space, *container_style) +
@@ -97,14 +99,14 @@ void LayoutNGBlockFlow::UpdateOutOfFlowBlockLayout() {
// object is really managed by legacy layout).
LayoutUnit container_border_box_logical_width;
LayoutUnit container_border_box_logical_height;
- if (HasOverrideContainingBlockLogicalWidth()) {
+ if (HasOverrideContainingBlockContentLogicalWidth()) {
container_border_box_logical_width =
OverrideContainingBlockContentLogicalWidth() +
borders_and_scrollbars.InlineSum();
} else {
container_border_box_logical_width = container->LogicalWidth();
}
- if (HasOverrideContainingBlockLogicalHeight()) {
+ if (HasOverrideContainingBlockContentLogicalHeight()) {
container_border_box_logical_height =
OverrideContainingBlockContentLogicalHeight() +
borders_and_scrollbars.BlockSum();
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
new file mode 100644
index 00000000000..5db1077417f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.cc
@@ -0,0 +1,49 @@
+// 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/layout_ng_flexible_box.h"
+
+#include "third_party/blink/renderer/core/layout/layout_analyzer.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/core/layout/ng/ng_layout_result.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+
+namespace blink {
+
+LayoutNGFlexibleBox::LayoutNGFlexibleBox(Element* element)
+ : LayoutBlock(element) {}
+
+void LayoutNGFlexibleBox::UpdateBlockLayout(bool relayout_children) {
+ LayoutAnalyzer::BlockScope analyzer(*this);
+
+ scoped_refptr<NGConstraintSpace> constraint_space =
+ NGConstraintSpace::CreateFromLayoutObject(*this);
+
+ scoped_refptr<NGLayoutResult> result =
+ NGBlockNode(this).Layout(*constraint_space);
+
+ for (NGOutOfFlowPositionedDescendant descendant :
+ result->OutOfFlowPositionedDescendants())
+ descendant.node.UseOldOutOfFlowPositioning();
+
+ NGPhysicalBoxFragment* fragment =
+ ToNGPhysicalBoxFragment(result->PhysicalFragment().get());
+
+ // Pasted from layout_ng_block_flow. TODO(dgrogan): Factor a utility method.
+ const LayoutBlock* containing_block = ContainingBlock();
+ NGPhysicalOffset physical_offset;
+ if (containing_block) {
+ NGPhysicalSize containing_block_size(containing_block->Size().Width(),
+ containing_block->Size().Height());
+ NGLogicalOffset logical_offset(LogicalLeft(), LogicalTop());
+ physical_offset = logical_offset.ConvertToPhysical(
+ constraint_space->GetWritingMode(), constraint_space->Direction(),
+ containing_block_size, fragment->Size());
+ }
+ fragment->SetOffset(physical_offset);
+}
+
+} // 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
new file mode 100644
index 00000000000..6ff73e9c01f
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_flexible_box.h
@@ -0,0 +1,31 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FLEXIBLE_BOX_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FLEXIBLE_BOX_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_mixin.h"
+
+namespace blink {
+
+class CORE_EXPORT LayoutNGFlexibleBox : public LayoutBlock {
+ public:
+ explicit LayoutNGFlexibleBox(Element*);
+
+ void UpdateBlockLayout(bool relayout_children) override;
+
+ bool IsFlexibleBox() const final { return true; }
+ const char* GetName() const override { return "LayoutNGFlexibleBox"; }
+
+ protected:
+ bool IsOfType(LayoutObjectType type) const override {
+ return type == kLayoutObjectNGFlexibleBox || LayoutBlock::IsOfType(type);
+ }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_FLEXIBLE_BOX_H_
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 c32f0ceb87b..19c0da2d6fd 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
@@ -9,16 +9,29 @@
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
#include "third_party/blink/renderer/core/layout/hit_test_location.h"
+#include "third_party/blink/renderer/core/layout/layout_block_flow.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/ng/inline/ng_inline_node_data.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/layout/ng/ng_layout_utils.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/page/scrolling/root_scroller_util.h"
#include "third_party/blink/renderer/core/paint/ng/ng_block_flow_painter.h"
+#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
namespace blink {
template <typename Base>
+LayoutNGMixin<Base>::LayoutNGMixin(Element* element) : Base(element) {
+ static_assert(
+ std::is_base_of<LayoutBlockFlow, Base>::value,
+ "Base class of LayoutNGMixin must be LayoutBlockFlow or derived class.");
+}
+
+template <typename Base>
LayoutNGMixin<Base>::~LayoutNGMixin() = default;
template <typename Base>
@@ -27,6 +40,11 @@ bool LayoutNGMixin<Base>::IsOfType(LayoutObject::LayoutObjectType type) const {
}
template <typename Base>
+NGInlineNodeData* LayoutNGMixin<Base>::TakeNGInlineNodeData() {
+ return ng_inline_node_data_.release();
+}
+
+template <typename Base>
NGInlineNodeData* LayoutNGMixin<Base>::GetNGInlineNodeData() const {
DCHECK(ng_inline_node_data_);
return ng_inline_node_data_.get();
@@ -56,26 +74,43 @@ void LayoutNGMixin<Base>::AddOverflowFromChildren() {
// Add overflow from the last layout cycle.
if (Base::ChildrenInline()) {
if (const NGPhysicalBoxFragment* physical_fragment = CurrentFragment()) {
- bool has_width =
- physical_fragment->Style().OverflowX() != EOverflow::kHidden;
- bool has_height =
- physical_fragment->Style().OverflowY() != EOverflow::kHidden;
- if (has_width || has_height) {
+ // LayoutOverflow is only computed if overflow is not hidden
+ if (physical_fragment->Style().OverflowX() != EOverflow::kHidden ||
+ physical_fragment->Style().OverflowY() != EOverflow::kHidden) {
+ // inline-end LayoutOverflow padding spec is still undecided:
+ // https://github.com/w3c/csswg-drafts/issues/129
+ // For backwards compatibility, if container clips overflow,
+ // padding is added to the inline-end for inline children.
+ base::Optional<NGPhysicalBoxStrut> padding_strut;
+ if (Base::HasOverflowClip()) {
+ padding_strut =
+ NGBoxStrut(LayoutUnit(), Base::PaddingEnd(), LayoutUnit(),
+ LayoutUnit())
+ .ConvertToPhysical(Base::StyleRef().GetWritingMode(),
+ Base::StyleRef().Direction());
+ }
+ NGPhysicalOffsetRect children_overflow;
for (const auto& child : physical_fragment->Children()) {
- NGPhysicalOffsetRect child_rect(child->Offset(), child->Size());
- if (!has_width)
- child_rect.size.width = LayoutUnit();
- if (!has_height)
- child_rect.size.height = LayoutUnit();
- Base::AddLayoutOverflow(child_rect.ToLayoutRect());
+ NGPhysicalOffsetRect child_scrollable_overflow =
+ child->ScrollableOverflow();
+ child_scrollable_overflow.offset += child->Offset();
+ if (child->IsLineBox() && padding_strut) {
+ child_scrollable_overflow.Expand(*padding_strut);
+ }
+ children_overflow.Unite(child_scrollable_overflow);
}
+ Base::AddLayoutOverflow(children_overflow.ToLayoutFlippedRect(
+ physical_fragment->Style(), physical_fragment->Size()));
}
-
+ Base::AddSelfVisualOverflow(
+ physical_fragment->SelfVisualRect().ToLayoutFlippedRect(
+ physical_fragment->Style(), physical_fragment->Size()));
// TODO(kojii): If |RecalcOverflowAfterStyleChange()|, we need to
// re-compute glyph bounding box. How to detect it and how to re-compute
// is TBD.
Base::AddContentsVisualOverflow(
- physical_fragment->ContentsVisualRect().ToLayoutRect());
+ physical_fragment->ContentsVisualRect().ToLayoutFlippedRect(
+ physical_fragment->Style(), physical_fragment->Size()));
// TODO(kojii): The above code computes visual overflow only, we fallback
// to LayoutBlock for AddLayoutOverflow() for now. It doesn't compute
// correctly without RootInlineBox though.
@@ -84,14 +119,24 @@ void LayoutNGMixin<Base>::AddOverflowFromChildren() {
Base::AddOverflowFromChildren();
}
+template <typename Base>
+void LayoutNGMixin<Base>::AddOutlineRects(
+ Vector<LayoutRect>& rects,
+ const LayoutPoint& additional_offset,
+ LayoutObject::IncludeBlockVisualOverflowOrNot include_block_overflows)
+ const {
+ Base::AddOutlineRects(rects, additional_offset, include_block_overflows);
+ if (CurrentFragment()) {
+ CurrentFragment()->AddSelfOutlineRects(&rects, additional_offset);
+ }
+}
+
// Retrieve NGBaseline from the current fragment.
template <typename Base>
const NGBaseline* LayoutNGMixin<Base>::FragmentBaseline(
NGBaselineAlgorithmType type) const {
if (const NGPhysicalFragment* physical_fragment = CurrentFragment()) {
- FontBaseline baseline_type = Base::IsHorizontalWritingMode()
- ? kAlphabeticBaseline
- : kIdeographicBaseline;
+ FontBaseline baseline_type = Base::StyleRef().GetFontBaseline();
return ToNGPhysicalBoxFragment(physical_fragment)
->Baseline({type, baseline_type});
}
@@ -131,13 +176,26 @@ scoped_refptr<NGLayoutResult> LayoutNGMixin<Base>::CachedLayoutResult(
return nullptr;
if (constraint_space != *cached_constraint_space_)
return nullptr;
- if (cached_constraint_space_->UnpositionedFloats().size() ||
- cached_result_->UnpositionedFloats().size())
+ // The checks above should be enough to bail if layout is incomplete, but
+ // let's verify:
+ DCHECK(IsBlockLayoutComplete(*cached_constraint_space_, *cached_result_));
+ // If we used to contain abspos items, we can't reuse the fragment, because
+ // we can't be sure that the list of items hasn't changed (as we bubble them
+ // up during layout). In the case of newly-added abspos items to this
+ // containing block, we will handle those by the NeedsLayout check above for
+ // now.
+ // TODO(layout-ng): Come up with a better solution for this
+ if (cached_result_->OutOfFlowPositionedDescendants().size())
return nullptr;
return cached_result_->CloneWithoutOffset();
}
template <typename Base>
+const NGConstraintSpace* LayoutNGMixin<Base>::CachedConstraintSpace() const {
+ return cached_constraint_space_.get();
+}
+
+template <typename Base>
void LayoutNGMixin<Base>::SetCachedLayoutResult(
const NGConstraintSpace& constraint_space,
NGBreakToken* break_token,
@@ -146,6 +204,8 @@ void LayoutNGMixin<Base>::SetCachedLayoutResult(
// We can't cache these yet
return;
}
+ if (constraint_space.IsIntermediateLayout())
+ return;
cached_constraint_space_ = &constraint_space;
cached_result_ = layout_result;
@@ -167,26 +227,9 @@ void LayoutNGMixin<Base>::SetPaintFragment(
Base::SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kSubtree);
}
-static Vector<NGPaintFragment*> GetNGPaintFragmentsInternal(
- NGPaintFragment* paint,
- const LayoutObject& layout_object) {
- if (!paint)
- return Vector<NGPaintFragment*>();
- Vector<NGPaintFragment*> fragments;
- if (paint->GetLayoutObject() == &layout_object)
- fragments.push_back(paint);
- for (const auto& child : paint->Children()) {
- const auto& result =
- GetNGPaintFragmentsInternal(child.get(), layout_object);
- fragments.AppendVector(result);
- }
- return fragments;
-}
-
template <typename Base>
-Vector<NGPaintFragment*> LayoutNGMixin<Base>::GetPaintFragments(
- const LayoutObject& layout_object) const {
- return GetNGPaintFragmentsInternal(PaintFragment(), layout_object);
+void LayoutNGMixin<Base>::ClearPaintFragment() {
+ paint_fragment_ = nullptr;
}
template <typename Base>
@@ -223,8 +266,10 @@ bool LayoutNGMixin<Base>::NodeAtPoint(
return LayoutBlockFlow::NodeAtPoint(result, location_in_container,
accumulated_offset, action);
}
-
- LayoutPoint adjusted_location = accumulated_offset + Base::Location();
+ LayoutPoint offset = PaintFragment()->PhysicalFragment().IsPlacedByLayoutNG()
+ ? PaintFragment()->Offset().ToLayoutPoint()
+ : Base::Location();
+ LayoutPoint adjusted_location = accumulated_offset + offset;
if (!RootScrollerUtil::IsEffective(*this)) {
// Check if we need to do anything at all.
// If we have clipping, then we can't have any spillout.
@@ -235,6 +280,10 @@ bool LayoutNGMixin<Base>::NodeAtPoint(
if (!location_in_container.Intersects(overflow_box))
return false;
}
+ if (Base::IsInSelfHitTestingPhase(action) && Base::HasOverflowClip() &&
+ Base::HitTestOverflowControl(result, location_in_container,
+ adjusted_location))
+ return true;
return NGBlockFlowPainter(*this).NodeAtPoint(result, location_in_container,
accumulated_offset,
@@ -254,16 +303,17 @@ PositionWithAffinity LayoutNGMixin<Base>::PositionForPoint(
if (!Base::ChildrenInline())
return LayoutBlock::PositionForPoint(point);
- if (!CurrentFragment())
+ if (!PaintFragment())
return Base::CreatePositionWithAffinity(0);
const PositionWithAffinity ng_position =
- CurrentFragment()->PositionForPoint(NGPhysicalOffset(point));
+ PaintFragment()->PositionForPoint(NGPhysicalOffset(point));
if (ng_position.IsNotNull())
return ng_position;
return Base::CreatePositionWithAffinity(0);
}
+template class LayoutNGMixin<LayoutTableCaption>;
template class LayoutNGMixin<LayoutTableCell>;
template class LayoutNGMixin<LayoutBlockFlow>;
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 e2812400e48..3f7511fd9b9 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
@@ -7,30 +7,30 @@
#include <type_traits>
-#include "third_party/blink/renderer/core/layout/layout_table_cell.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node_data.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h"
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/layout_box_model_object.h"
namespace blink {
+enum class NGBaselineAlgorithmType;
class NGBreakToken;
+class NGConstraintSpace;
class NGLayoutResult;
+class NGPaintFragment;
+class NGPhysicalFragment;
+struct NGBaseline;
+struct NGInlineNodeData;
// This mixin holds code shared between LayoutNG subclasses of
// LayoutBlockFlow.
template <typename Base>
class CORE_TEMPLATE_CLASS_EXPORT LayoutNGMixin : public Base {
- static_assert(
- std::is_base_of<LayoutBlockFlow, Base>::value,
- "Base class of LayoutNGMixin must be LayoutBlockFlow or derived class.");
-
public:
- explicit LayoutNGMixin(Element* element) : Base(element) {}
+ explicit LayoutNGMixin(Element* element);
~LayoutNGMixin() override;
+ NGInlineNodeData* TakeNGInlineNodeData() override;
NGInlineNodeData* GetNGInlineNodeData() const override;
void ResetNGInlineNodeData() override;
bool HasNGInlineNodeData() const override {
@@ -57,6 +57,7 @@ class CORE_TEMPLATE_CLASS_EXPORT LayoutNGMixin : public Base {
scoped_refptr<NGLayoutResult> CachedLayoutResult(
const NGConstraintSpace&,
NGBreakToken*) const override;
+ const NGConstraintSpace* CachedConstraintSpace() const override;
void SetCachedLayoutResult(const NGConstraintSpace&,
NGBreakToken*,
@@ -68,15 +69,18 @@ class CORE_TEMPLATE_CLASS_EXPORT LayoutNGMixin : public Base {
return paint_fragment_.get();
}
void SetPaintFragment(scoped_refptr<const NGPhysicalFragment>) override;
- void ClearPaintFragment() { paint_fragment_ = nullptr; }
- Vector<NGPaintFragment*> GetPaintFragments(
- const LayoutObject&) const override;
+ void ClearPaintFragment() override;
protected:
bool IsOfType(LayoutObject::LayoutObjectType) const override;
void AddOverflowFromChildren() override;
+ void AddOutlineRects(
+ Vector<LayoutRect>&,
+ const LayoutPoint& additional_offset,
+ LayoutObject::IncludeBlockVisualOverflowOrNot) const override;
+
const NGPhysicalBoxFragment* CurrentFragment() const override;
const NGBaseline* FragmentBaseline(NGBaselineAlgorithmType) const;
@@ -90,11 +94,6 @@ class CORE_TEMPLATE_CLASS_EXPORT LayoutNGMixin : public Base {
friend class NGBaseLayoutAlgorithmTest;
};
-extern template class CORE_EXTERN_TEMPLATE_EXPORT
- LayoutNGMixin<LayoutTableCell>;
-extern template class CORE_EXTERN_TEMPLATE_EXPORT
- LayoutNGMixin<LayoutBlockFlow>;
-
} // namespace blink
#endif // LayoutNGMixin_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
new file mode 100644
index 00000000000..1ec5ed14bb6
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.cc
@@ -0,0 +1,49 @@
+// 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/layout_ng_table_caption.h"
+
+#include "third_party/blink/renderer/core/layout/layout_analyzer.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/core/layout/ng/ng_layout_result.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+
+namespace blink {
+
+LayoutNGTableCaption::LayoutNGTableCaption(Element* element)
+ : LayoutNGMixin<LayoutTableCaption>(element) {}
+
+void LayoutNGTableCaption::UpdateBlockLayout(bool relayout_children) {
+ LayoutAnalyzer::BlockScope analyzer(*this);
+
+ DCHECK(!IsOutOfFlowPositioned()) << "Out of flow captions are blockified.";
+
+ scoped_refptr<NGConstraintSpace> constraint_space =
+ NGConstraintSpace::CreateFromLayoutObject(*this);
+
+ scoped_refptr<NGLayoutResult> result =
+ NGBlockNode(this).Layout(*constraint_space);
+
+ // 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 (NGOutOfFlowPositionedDescendant descendant :
+ result->OutOfFlowPositionedDescendants())
+ descendant.node.UseOldOutOfFlowPositioning();
+
+ // 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;
+ // NGBoxFragmentPainter::Paint will have to handle it until table layout is
+ // implemented in NG, in which case that algorithm will set each child's
+ // offsets. See https://crbug.com/788590 for more info.
+ DCHECK(!result->PhysicalFragment()->IsPlacedByLayoutNG())
+ << "Only a table should be placing table caption fragments and the ng "
+ "table algorithm doesn't exist yet!";
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h
new file mode 100644
index 00000000000..cacadfd46fc
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/layout_ng_table_caption.h
@@ -0,0 +1,26 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_TABLE_CAPTION_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_TABLE_CAPTION_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/layout/layout_table_caption.h"
+#include "third_party/blink/renderer/core/layout/ng/layout_ng_mixin.h"
+
+namespace blink {
+
+class CORE_EXPORT LayoutNGTableCaption final
+ : public LayoutNGMixin<LayoutTableCaption> {
+ public:
+ explicit LayoutNGTableCaption(Element*);
+
+ void UpdateBlockLayout(bool relayout_children) override;
+
+ const char* GetName() const override { return "LayoutNGTableCaption"; }
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_LAYOUT_NG_TABLE_CAPTION_H_
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 346cc36c6bf..e9e3423485d 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
@@ -5,8 +5,12 @@
#include "third_party/blink/renderer/core/layout/ng/layout_ng_table_cell.h"
#include "third_party/blink/renderer/core/layout/layout_analyzer.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/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_positioned_descendant.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
namespace blink {
@@ -16,8 +20,7 @@ LayoutNGTableCell::LayoutNGTableCell(Element* element)
void LayoutNGTableCell::UpdateBlockLayout(bool relayout_children) {
LayoutAnalyzer::BlockScope analyzer(*this);
- SetOverrideLogicalContentWidth(
- (LogicalWidth() - BorderAndPaddingLogicalWidth()).ClampNegativeToZero());
+ SetOverrideLogicalWidth(LogicalWidth());
scoped_refptr<NGConstraintSpace> constraint_space =
NGConstraintSpace::CreateFromLayoutObject(*this);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc b/chromium/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc
index f18e7fa24be..6f504c9b9da 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.cc
@@ -4,7 +4,6 @@
#include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h"
-#include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h"
#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
namespace blink {
@@ -15,7 +14,7 @@ namespace blink {
// LayoutMultiColumnSpannerPlaceholder. NG needs to skip these special
// objects. The actual content is inside the flow thread.
-LayoutObject* GetLayoutObjectForFirstChildNode(LayoutBlockFlow* parent) {
+LayoutObject* GetLayoutObjectForFirstChildNode(LayoutBlock* parent) {
LayoutObject* child = parent->FirstChild();
if (!child)
return nullptr;
@@ -38,7 +37,7 @@ LayoutObject* GetLayoutObjectForParentNode(LayoutObject* object) {
return parent;
}
-bool AreNGBlockFlowChildrenInline(const LayoutBlockFlow* block) {
+bool AreNGBlockFlowChildrenInline(const LayoutBlock* block) {
if (block->ChildrenInline())
return true;
if (const auto* first_child = block->FirstChild()) {
@@ -49,14 +48,15 @@ bool AreNGBlockFlowChildrenInline(const LayoutBlockFlow* block) {
}
bool IsManagedByLayoutNG(const LayoutObject& object) {
- if (!object.IsLayoutNGMixin())
+ if (!object.IsLayoutNGMixin() && !object.IsLayoutNGFlexibleBox())
return false;
const auto* containing_block = object.ContainingBlock();
if (!containing_block)
return false;
if (containing_block->IsLayoutFlowThread())
containing_block = containing_block->ContainingBlock();
- return containing_block && containing_block->IsLayoutNGMixin();
+ return containing_block && (containing_block->IsLayoutNGMixin() ||
+ containing_block->IsLayoutNGFlexibleBox());
}
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h b/chromium/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h
index 64bc4f57362..ab67358c6c0 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.h
@@ -7,13 +7,13 @@
namespace blink {
-class LayoutBlockFlow;
+class LayoutBlock;
class LayoutObject;
// Return the layout object that should be the first child NGLayoutInputNode of
// |parent|. Normally this will just be the first layout object child, but there
// are certain layout objects that should be skipped for NG.
-LayoutObject* GetLayoutObjectForFirstChildNode(LayoutBlockFlow*);
+LayoutObject* GetLayoutObjectForFirstChildNode(LayoutBlock*);
// Return the layout object that should be the parent NGLayoutInputNode of
// |object|. Normally this will just be the parent layout object, but there
@@ -22,7 +22,7 @@ LayoutObject* GetLayoutObjectForParentNode(LayoutObject*);
// Return true if the NGLayoutInputNode children of the NGLayoutInputNode
// established by |block| will be inline; see LayoutObject::ChildrenInline().
-bool AreNGBlockFlowChildrenInline(const LayoutBlockFlow*);
+bool AreNGBlockFlowChildrenInline(const LayoutBlock*);
// Return true if the layout object is a LayoutNG object that is managed by the
// LayoutNG engine (i.e. its containing block is a LayoutNG object as well).
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 0bcf2bf175c..fbd11c2a09d 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
@@ -38,8 +38,9 @@ void LayoutNGListMarkerImage::ComputeSVGIntrinsicSizingInfoByDefaultSize(
font_data->GetFontMetrics().Ascent() / LayoutUnit(2);
FloatSize default_size(bullet_width, bullet_width);
default_size.Scale(1 / Style()->EffectiveZoom());
- LayoutSize svg_image_size =
- RoundedLayoutSize(ToSVGImage(image)->ConcreteObjectSize(default_size));
+ FloatSize concrete_size = ToSVGImage(image)->ConcreteObjectSize(default_size);
+ concrete_size.Scale(Style()->EffectiveZoom() * ImageDevicePixelRatio());
+ LayoutSize svg_image_size(RoundedLayoutSize(concrete_size));
intrinsic_sizing_info.size.SetWidth(svg_image_size.Width());
intrinsic_sizing_info.size.SetHeight(svg_image_size.Height());
@@ -47,19 +48,21 @@ void LayoutNGListMarkerImage::ComputeSVGIntrinsicSizingInfoByDefaultSize(
intrinsic_sizing_info.has_height = true;
}
-bool LayoutNGListMarkerImage::GetNestedIntrinsicSizingInfo(
+void LayoutNGListMarkerImage::ComputeIntrinsicSizingInfo(
IntrinsicSizingInfo& intrinsic_sizing_info) const {
- if (!LayoutImage::GetNestedIntrinsicSizingInfo(intrinsic_sizing_info))
- return false;
+ LayoutImage::ComputeIntrinsicSizingInfo(intrinsic_sizing_info);
- // For SVG image, if GetNestedIntrinsicSizingInfo successfully and the size is
- // empty, we need to compute the intrinsic size by setting a default size.
+ // If this is an SVG image without intrinsic width and height,
+ // compute an intrinsic size using the concrete object size resolved
+ // with a default object size of 1em x 1em.
+ // TODO(fs): Apply this more generally to all images (CSS <image> values)
+ // that have no intrinsic width or height. I.e just always compute the
+ // concrete object size here.
if (intrinsic_sizing_info.size.IsEmpty() && CachedImage()) {
Image* image = CachedImage()->GetImage();
if (image && image->IsSVGImage())
ComputeSVGIntrinsicSizingInfoByDefaultSize(intrinsic_sizing_info);
}
- return true;
}
} // namespace blink
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 59cc8766a59..050b8ae5ee4 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
@@ -21,7 +21,7 @@ class CORE_EXPORT LayoutNGListMarkerImage final : public LayoutImage {
bool IsOfType(LayoutObjectType) const override;
void ComputeSVGIntrinsicSizingInfoByDefaultSize(IntrinsicSizingInfo&) const;
- bool GetNestedIntrinsicSizingInfo(IntrinsicSizingInfo&) const final;
+ void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const final;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutNGListMarkerImage,
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 499092699aa..cfd4aad7ddd 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
@@ -5,8 +5,6 @@
#include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h"
#include "third_party/blink/renderer/core/layout/layout_list_marker.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_item_result.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/ng_box_fragment.h"
@@ -41,24 +39,28 @@ LayoutUnit NGUnpositionedListMarker::InlineOffset(
}
scoped_refptr<NGLayoutResult> NGUnpositionedListMarker::Layout(
- const NGConstraintSpace& space) const {
+ const NGConstraintSpace& space,
+ FontBaseline baseline_type) const {
DCHECK(marker_layout_object_);
NGBlockNode marker_node(marker_layout_object_);
scoped_refptr<NGLayoutResult> marker_layout_result =
- marker_node.LayoutAtomicInline(space, space.UseFirstLineStyle());
+ marker_node.LayoutAtomicInline(space, baseline_type,
+ space.UseFirstLineStyle());
DCHECK(marker_layout_result && marker_layout_result->PhysicalFragment());
return marker_layout_result;
}
bool NGUnpositionedListMarker::AddToBox(
const NGConstraintSpace& space,
+ FontBaseline baseline_type,
const NGPhysicalFragment& content,
NGLogicalOffset* content_offset,
NGFragmentBuilder* container_builder) const {
+ // Baselines from two different writing-mode cannot be aligned.
+ if (UNLIKELY(space.GetWritingMode() != content.Style().GetWritingMode()))
+ return false;
+
// Compute the baseline of the child content.
- FontBaseline baseline_type = IsHorizontalWritingMode(space.GetWritingMode())
- ? kAlphabeticBaseline
- : kIdeographicBaseline;
NGLineHeightMetrics content_metrics;
if (content.IsLineBox()) {
content_metrics = ToNGPhysicalLineBoxFragment(content).Metrics();
@@ -66,7 +68,7 @@ bool NGUnpositionedListMarker::AddToBox(
NGBoxFragment content_fragment(space.GetWritingMode(),
ToNGPhysicalBoxFragment(content));
content_metrics = content_fragment.BaselineMetricsWithoutSynthesize(
- {NGBaselineAlgorithmType::kFirstLine, baseline_type}, space);
+ {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.
@@ -76,7 +78,8 @@ bool NGUnpositionedListMarker::AddToBox(
}
// Layout the list marker.
- scoped_refptr<NGLayoutResult> marker_layout_result = Layout(space);
+ scoped_refptr<NGLayoutResult> marker_layout_result =
+ Layout(space, baseline_type);
DCHECK(marker_layout_result && marker_layout_result->PhysicalFragment());
const NGPhysicalBoxFragment& marker_physical_fragment =
ToNGPhysicalBoxFragment(*marker_layout_result->PhysicalFragment());
@@ -108,9 +111,11 @@ bool NGUnpositionedListMarker::AddToBox(
LayoutUnit NGUnpositionedListMarker::AddToBoxWithoutLineBoxes(
const NGConstraintSpace& space,
+ FontBaseline baseline_type,
NGFragmentBuilder* container_builder) const {
// Layout the list marker.
- scoped_refptr<NGLayoutResult> marker_layout_result = Layout(space);
+ scoped_refptr<NGLayoutResult> marker_layout_result =
+ Layout(space, baseline_type);
DCHECK(marker_layout_result && marker_layout_result->PhysicalFragment());
const NGPhysicalBoxFragment& marker_physical_fragment =
ToNGPhysicalBoxFragment(*marker_layout_result->PhysicalFragment());
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 a532a0eeb22..30e19bf3693 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
@@ -7,6 +7,7 @@
#include "base/memory/scoped_refptr.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/wtf/allocator.h"
namespace blink {
@@ -45,6 +46,7 @@ class CORE_EXPORT NGUnpositionedListMarker final {
// that the child content does not have a baseline to align to, and that
// caller should try next child, or "WithoutLineBoxes" version.
bool AddToBox(const NGConstraintSpace&,
+ FontBaseline,
const NGPhysicalFragment& content,
NGLogicalOffset* content_offset,
NGFragmentBuilder*) const;
@@ -53,13 +55,15 @@ class CORE_EXPORT NGUnpositionedListMarker final {
// boxes.
// Returns the block size of the list marker.
LayoutUnit AddToBoxWithoutLineBoxes(const NGConstraintSpace&,
+ FontBaseline,
NGFragmentBuilder*) const;
private:
bool IsImage() const;
LayoutUnit InlineOffset(const LayoutUnit marker_inline_size) const;
- scoped_refptr<NGLayoutResult> Layout(const NGConstraintSpace&) const;
+ scoped_refptr<NGLayoutResult> Layout(const NGConstraintSpace&,
+ FontBaseline) const;
LayoutNGListMarker* marker_layout_object_;
};
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 94159196a42..4da55760b6b 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
@@ -6,7 +6,6 @@
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_static_position.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/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/length_functions.h"
@@ -50,38 +49,41 @@ bool IsTopDominant(const WritingMode container_writing_mode,
LayoutUnit ResolveWidth(const Length& width,
const NGConstraintSpace& space,
const ComputedStyle& style,
- const Optional<MinMaxSize>& child_minmax,
- LengthResolveType resolve_type) {
- if (space.GetWritingMode() == WritingMode::kHorizontalTb)
- return ResolveInlineLength(space, style, child_minmax, width, resolve_type);
+ const base::Optional<MinMaxSize>& child_minmax,
+ LengthResolveType type) {
+ if (space.GetWritingMode() == WritingMode::kHorizontalTb) {
+ return ResolveInlineLength(space, style, child_minmax, width, type,
+ LengthResolvePhase::kLayout);
+ }
LayoutUnit computed_width =
child_minmax.has_value() ? child_minmax->max_size : LayoutUnit();
- return ResolveBlockLength(space, style, style.Width(), computed_width,
- resolve_type);
+ return ResolveBlockLength(space, style, width, computed_width, type,
+ LengthResolvePhase::kLayout);
}
LayoutUnit ResolveHeight(const Length& height,
const NGConstraintSpace& space,
const ComputedStyle& style,
- const Optional<MinMaxSize>& child_minmax,
- LengthResolveType resolve_type) {
- if (space.GetWritingMode() != WritingMode::kHorizontalTb)
- return ResolveInlineLength(space, style, child_minmax, height,
- resolve_type);
+ const base::Optional<MinMaxSize>& child_minmax,
+ LengthResolveType type) {
+ if (space.GetWritingMode() != WritingMode::kHorizontalTb) {
+ return ResolveInlineLength(space, style, child_minmax, height, type,
+ LengthResolvePhase::kLayout);
+ }
LayoutUnit computed_height =
child_minmax.has_value() ? child_minmax->max_size : LayoutUnit();
- return ResolveBlockLength(space, style, height, computed_height,
- resolve_type);
+ return ResolveBlockLength(space, style, height, computed_height, type,
+ LengthResolvePhase::kLayout);
}
// Available size can is maximum length Element can have without overflowing
// container bounds. The position of Element's edges will determine
// how much space there is available.
LayoutUnit ComputeAvailableWidth(LayoutUnit container_width,
- const Optional<LayoutUnit>& left,
- const Optional<LayoutUnit>& right,
- const Optional<LayoutUnit>& margin_left,
- const Optional<LayoutUnit>& margin_right,
+ const base::Optional<LayoutUnit>& left,
+ const base::Optional<LayoutUnit>& right,
+ const base::Optional<LayoutUnit>& margin_left,
+ const base::Optional<LayoutUnit>& margin_right,
const NGStaticPosition& static_position) {
LayoutUnit available_width = container_width;
DCHECK(!left || !right);
@@ -100,12 +102,13 @@ LayoutUnit ComputeAvailableWidth(LayoutUnit container_width,
return (available_width - margins).ClampNegativeToZero();
}
-LayoutUnit ComputeAvailableHeight(LayoutUnit container_height,
- const Optional<LayoutUnit>& top,
- const Optional<LayoutUnit>& bottom,
- const Optional<LayoutUnit>& margin_top,
- const Optional<LayoutUnit>& margin_bottom,
- const NGStaticPosition& static_position) {
+LayoutUnit ComputeAvailableHeight(
+ LayoutUnit container_height,
+ const base::Optional<LayoutUnit>& top,
+ const base::Optional<LayoutUnit>& bottom,
+ const base::Optional<LayoutUnit>& margin_top,
+ const base::Optional<LayoutUnit>& margin_bottom,
+ const NGStaticPosition& static_position) {
LayoutUnit available_height = container_height;
DCHECK(!top || !bottom);
if (!top && !bottom) {
@@ -145,30 +148,30 @@ LayoutUnit VerticalBorderPadding(const NGConstraintSpace& space,
// https://www.w3.org/TR/css-position-3/#abs-non-replaced-width
void ComputeAbsoluteHorizontal(const NGConstraintSpace& space,
const ComputedStyle& style,
- const Optional<LayoutUnit>& incoming_width,
+ const base::Optional<LayoutUnit>& incoming_width,
const NGStaticPosition& static_position,
- const Optional<MinMaxSize>& child_minmax,
+ const base::Optional<MinMaxSize>& child_minmax,
const WritingMode container_writing_mode,
const TextDirection container_direction,
NGAbsolutePhysicalPosition* position) {
NGLogicalSize percentage_logical = space.PercentageResolutionSize();
NGPhysicalSize percentage_physical =
percentage_logical.ConvertToPhysical(space.GetWritingMode());
- Optional<LayoutUnit> margin_left;
+ base::Optional<LayoutUnit> margin_left;
if (!style.MarginLeft().IsAuto())
margin_left =
ValueForLength(style.MarginLeft(), percentage_logical.inline_size);
- Optional<LayoutUnit> margin_right;
+ base::Optional<LayoutUnit> margin_right;
if (!style.MarginRight().IsAuto())
margin_right =
ValueForLength(style.MarginRight(), percentage_logical.inline_size);
- Optional<LayoutUnit> left;
+ base::Optional<LayoutUnit> left;
if (!style.Left().IsAuto())
left = ValueForLength(style.Left(), percentage_physical.width);
- Optional<LayoutUnit> right;
+ base::Optional<LayoutUnit> right;
if (!style.Right().IsAuto())
right = ValueForLength(style.Right(), percentage_physical.width);
- Optional<LayoutUnit> width = incoming_width;
+ base::Optional<LayoutUnit> width = incoming_width;
NGPhysicalSize container_size =
space.AvailableSize().ConvertToPhysical(space.GetWritingMode());
DCHECK_NE(container_size.width, NGSizeIndefinite);
@@ -281,16 +284,12 @@ void ComputeAbsoluteHorizontal(const NGConstraintSpace& space,
// If calculated width is outside of min/max constraints,
// rerun the algorithm with constrained width.
- Optional<LayoutUnit> min_width;
- if (!style.MinWidth().IsAuto())
- min_width = ResolveWidth(style.MinWidth(), space, style, child_minmax,
- LengthResolveType::kMinSize);
- Optional<LayoutUnit> max_width;
- if (!style.MaxWidth().IsMaxSizeNone())
- max_width = ResolveWidth(style.MaxWidth(), space, style, child_minmax,
- LengthResolveType::kMaxSize);
- if (width != ConstrainByMinMax(*width, min_width, max_width)) {
- width = ConstrainByMinMax(*width, min_width, max_width);
+ LayoutUnit min = ResolveWidth(style.MinWidth(), space, style, child_minmax,
+ LengthResolveType::kMinSize);
+ LayoutUnit max = ResolveWidth(style.MaxWidth(), space, style, child_minmax,
+ LengthResolveType::kMaxSize);
+ if (width != ConstrainByMinMax(*width, min, max)) {
+ width = ConstrainByMinMax(*width, min, max);
// Because this function only changes "width" when it's not already
// set, it is safe to recursively call ourselves here because on the
// second call it is guaranteed to be within min..max.
@@ -312,9 +311,9 @@ void ComputeAbsoluteHorizontal(const NGConstraintSpace& space,
// https://www.w3.org/TR/css-position-3/#abs-non-replaced-height
void ComputeAbsoluteVertical(const NGConstraintSpace& space,
const ComputedStyle& style,
- const Optional<LayoutUnit>& incoming_height,
+ const base::Optional<LayoutUnit>& incoming_height,
const NGStaticPosition& static_position,
- const Optional<MinMaxSize>& child_minmax,
+ const base::Optional<MinMaxSize>& child_minmax,
const WritingMode container_writing_mode,
const TextDirection container_direction,
NGAbsolutePhysicalPosition* position) {
@@ -322,22 +321,22 @@ void ComputeAbsoluteVertical(const NGConstraintSpace& space,
NGPhysicalSize percentage_physical =
percentage_logical.ConvertToPhysical(space.GetWritingMode());
- Optional<LayoutUnit> margin_top;
+ base::Optional<LayoutUnit> margin_top;
if (!style.MarginTop().IsAuto())
margin_top =
ValueForLength(style.MarginTop(), percentage_logical.inline_size);
- Optional<LayoutUnit> margin_bottom;
+ base::Optional<LayoutUnit> margin_bottom;
if (!style.MarginBottom().IsAuto())
margin_bottom =
ValueForLength(style.MarginBottom(), percentage_logical.inline_size);
- Optional<LayoutUnit> top;
+ base::Optional<LayoutUnit> top;
if (!style.Top().IsAuto())
top = ValueForLength(style.Top(), percentage_physical.height);
- Optional<LayoutUnit> bottom;
+ base::Optional<LayoutUnit> bottom;
if (!style.Bottom().IsAuto())
bottom = ValueForLength(style.Bottom(), percentage_physical.height);
LayoutUnit border_padding = VerticalBorderPadding(space, style);
- Optional<LayoutUnit> height = incoming_height;
+ base::Optional<LayoutUnit> height = incoming_height;
NGPhysicalSize container_size =
space.AvailableSize().ConvertToPhysical(space.GetWritingMode());
@@ -449,16 +448,12 @@ void ComputeAbsoluteVertical(const NGConstraintSpace& space,
}
// If calculated height is outside of min/max constraints,
// rerun the algorithm with constrained width.
- Optional<LayoutUnit> min_height;
- if (!style.MinHeight().IsAuto())
- min_height = ResolveHeight(style.MinHeight(), space, style, child_minmax,
- LengthResolveType::kMinSize);
- Optional<LayoutUnit> max_height;
- if (!style.MaxHeight().IsMaxSizeNone())
- max_height = ResolveHeight(style.MaxHeight(), space, style, child_minmax,
- LengthResolveType::kMaxSize);
- if (height != ConstrainByMinMax(*height, min_height, max_height)) {
- height = ConstrainByMinMax(*height, min_height, max_height);
+ LayoutUnit min = ResolveHeight(style.MinHeight(), space, style, child_minmax,
+ LengthResolveType::kMinSize);
+ LayoutUnit max = ResolveHeight(style.MaxHeight(), space, style, child_minmax,
+ LengthResolveType::kMaxSize);
+ if (height != ConstrainByMinMax(*height, min, max)) {
+ height = ConstrainByMinMax(*height, min, max);
// Because this function only changes "height" when it's not already
// set, it is safe to recursively call ourselves here because on the
// second call it is guaranteed to be within min..max.
@@ -502,13 +497,13 @@ NGAbsolutePhysicalPosition ComputePartialAbsoluteWithChildInlineSize(
const NGConstraintSpace& space,
const ComputedStyle& style,
const NGStaticPosition& static_position,
- const Optional<MinMaxSize>& child_minmax,
- const Optional<NGLogicalSize>& replaced_size,
+ const base::Optional<MinMaxSize>& child_minmax,
+ const base::Optional<NGLogicalSize>& replaced_size,
const WritingMode container_writing_mode,
const TextDirection container_direction) {
NGAbsolutePhysicalPosition position;
if (style.IsHorizontalWritingMode()) {
- Optional<LayoutUnit> width;
+ base::Optional<LayoutUnit> width;
if (!style.Width().IsAuto()) {
width = ResolveWidth(style.Width(), space, style, child_minmax,
LengthResolveType::kContentSize);
@@ -519,7 +514,7 @@ NGAbsolutePhysicalPosition ComputePartialAbsoluteWithChildInlineSize(
child_minmax, container_writing_mode,
container_direction, &position);
} else {
- Optional<LayoutUnit> height;
+ base::Optional<LayoutUnit> height;
if (!style.Height().IsAuto()) {
height = ResolveHeight(style.Height(), space, style, child_minmax,
LengthResolveType::kContentSize);
@@ -537,8 +532,8 @@ void ComputeFullAbsoluteWithChildBlockSize(
const NGConstraintSpace& space,
const ComputedStyle& style,
const NGStaticPosition& static_position,
- const Optional<LayoutUnit>& child_block_size,
- const Optional<NGLogicalSize>& replaced_size,
+ const base::Optional<LayoutUnit>& child_block_size,
+ const base::Optional<NGLogicalSize>& replaced_size,
const WritingMode container_writing_mode,
const TextDirection container_direction,
NGAbsolutePhysicalPosition* position) {
@@ -546,12 +541,12 @@ void ComputeFullAbsoluteWithChildBlockSize(
// unknown, or fully computed, there is no minmax.
// To express this, a 'fixed' minmax is created where
// min and max are the same.
- Optional<MinMaxSize> child_minmax;
+ base::Optional<MinMaxSize> child_minmax;
if (child_block_size.has_value()) {
child_minmax = MinMaxSize{*child_block_size, *child_block_size};
}
if (style.IsHorizontalWritingMode()) {
- Optional<LayoutUnit> height;
+ base::Optional<LayoutUnit> height;
if (!style.Height().IsAuto()) {
height = ResolveHeight(style.Height(), space, style, child_minmax,
LengthResolveType::kContentSize);
@@ -562,7 +557,7 @@ void ComputeFullAbsoluteWithChildBlockSize(
container_writing_mode, container_direction,
position);
} else {
- Optional<LayoutUnit> width;
+ base::Optional<LayoutUnit> width;
if (!style.Width().IsAuto()) {
width = ResolveWidth(style.Width(), space, style, child_minmax,
LengthResolveType::kContentSize);
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 5e4fe6a5e4c..ede1012089f 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
@@ -5,12 +5,12 @@
#ifndef NGAbsoluteUtils_h
#define NGAbsoluteUtils_h
+#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/ng/geometry/ng_logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h"
#include "third_party/blink/renderer/platform/layout_unit.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink {
@@ -54,8 +54,8 @@ ComputePartialAbsoluteWithChildInlineSize(
const NGConstraintSpace& space,
const ComputedStyle& style,
const NGStaticPosition&,
- const Optional<MinMaxSize>& child_minmax,
- const Optional<NGLogicalSize>& replaced_size,
+ const base::Optional<MinMaxSize>& child_minmax,
+ const base::Optional<NGLogicalSize>& replaced_size,
const WritingMode container_writing_mode,
const TextDirection container_direction);
@@ -64,8 +64,8 @@ CORE_EXPORT void ComputeFullAbsoluteWithChildBlockSize(
const NGConstraintSpace& space,
const ComputedStyle& style,
const NGStaticPosition&,
- const Optional<LayoutUnit>& child_block_size,
- const Optional<NGLogicalSize>& replaced_size,
+ const base::Optional<LayoutUnit>& child_block_size,
+ const base::Optional<NGLogicalSize>& replaced_size,
const WritingMode container_writing_mode,
const TextDirection container_direction,
NGAbsolutePhysicalPosition* position);
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 8d9fc740317..c070173984f 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,8 +118,8 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
LayoutUnit width =
container_size_.inline_size - left - margin_left - right - margin_right;
- Optional<MinMaxSize> estimated_inline;
- Optional<LayoutUnit> estimated_block;
+ base::Optional<MinMaxSize> estimated_inline;
+ base::Optional<LayoutUnit> estimated_block;
MinMaxSize minmax_60{LayoutUnit(60) + border_padding,
LayoutUnit(60) + border_padding};
@@ -148,7 +148,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), true);
estimated_inline = minmax_60;
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(minmax_60.min_size, p.size.width);
EXPECT_EQ(LayoutUnit(0), p.inset.left);
@@ -159,13 +159,13 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
estimated_inline = minmax_60;
p = ComputePartialAbsoluteWithChildInlineSize(
*ltr_space_, *style_, static_right_position, estimated_inline,
- WTF::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr);
+ base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(minmax_60.min_size, p.size.width);
EXPECT_EQ(container_size_.inline_size, p.inset.right);
// All auto + RTL.
p = ComputePartialAbsoluteWithChildInlineSize(
- *rtl_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *rtl_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(minmax_60.min_size, p.size.width);
EXPECT_EQ(container_size_.inline_size - minmax_60.min_size, p.inset.right);
@@ -175,7 +175,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
LayoutUnit margin_space =
(container_size_.inline_size - left - right - p.size.width) / 2;
@@ -189,7 +189,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
estimated_inline.reset();
ComputeFullAbsoluteWithChildBlockSize(
*vertical_lr_space_, *style_, static_position, estimated_block,
- WTF::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
+ base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(left + margin_space, p.inset.left);
EXPECT_EQ(right + margin_space, p.inset.right);
@@ -200,7 +200,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
estimated_inline.reset();
ComputeFullAbsoluteWithChildBlockSize(
*vertical_rl_space_, *style_, static_position, estimated_block,
- WTF::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
+ base::nullopt, WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(left + margin_space, p.inset.left);
EXPECT_EQ(right + margin_space, p.inset.right);
@@ -208,7 +208,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
SetHorizontalStyle(left, NGAuto, LayoutUnit(200), NGAuto, right);
estimated_inline.reset();
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(left, p.inset.left);
EXPECT_EQ(-left, p.inset.right);
@@ -218,7 +218,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
WritingMode::kHorizontalTb);
estimated_inline.reset();
p = ComputePartialAbsoluteWithChildInlineSize(
- *rtl_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *rtl_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kRtl);
EXPECT_EQ(-right, p.inset.left);
EXPECT_EQ(right, p.inset.right);
@@ -228,7 +228,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), true);
estimated_inline = minmax_60;
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(minmax_60.min_size, p.size.width);
@@ -237,7 +237,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(margin_left, p.inset.left);
EXPECT_EQ(container_size_.inline_size - margin_left - width, p.inset.right);
@@ -247,7 +247,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
p = ComputePartialAbsoluteWithChildInlineSize(
- *rtl_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *rtl_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(margin_left, p.inset.left);
EXPECT_EQ(container_size_.inline_size - margin_left - width, p.inset.right);
@@ -257,7 +257,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), true);
estimated_inline = minmax_60;
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(
container_size_.inline_size - minmax_60.min_size - left - margin_left,
@@ -269,7 +269,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(left + margin_left, p.inset.left);
@@ -281,7 +281,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(left + margin_left, p.inset.left);
style_->SetBoxSizing(EBoxSizing::kBorderBox);
@@ -291,7 +291,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(right + margin_right, p.inset.right);
@@ -300,7 +300,7 @@ TEST_F(NGAbsoluteUtilsTest, Horizontal) {
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
estimated_inline.reset();
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(width, p.size.width);
}
@@ -335,7 +335,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
style_->SetBorderRightWidth(0);
NGAbsolutePhysicalPosition p;
- Optional<LayoutUnit> auto_height;
+ base::Optional<LayoutUnit> auto_height;
MinMaxSize minmax_60{LayoutUnit(60), LayoutUnit(60)};
NGStaticPosition static_position{NGStaticPosition::kTopLeft,
@@ -352,14 +352,14 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), true);
auto_height = LayoutUnit(60);
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(*auto_height, p.size.height);
EXPECT_EQ(LayoutUnit(0), p.inset.top);
// All auto, static position bottom
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position_bottom, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position_bottom, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(container_size_.block_size, p.inset.bottom);
@@ -368,7 +368,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
auto_height.reset();
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
LayoutUnit margin_space =
(container_size_.block_size - top - height - bottom) / 2;
@@ -380,7 +380,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
WritingMode::kVerticalLr);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
p = ComputePartialAbsoluteWithChildInlineSize(
- *vertical_lr_space_, *style_, static_position, minmax_60, WTF::nullopt,
+ *vertical_lr_space_, *style_, static_position, minmax_60, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(top + margin_space, p.inset.top);
EXPECT_EQ(bottom + margin_space, p.inset.bottom);
@@ -390,7 +390,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
WritingMode::kVerticalRl);
EXPECT_EQ(AbsoluteNeedsChildInlineSize(*style_), false);
p = ComputePartialAbsoluteWithChildInlineSize(
- *vertical_rl_space_, *style_, static_position, minmax_60, WTF::nullopt,
+ *vertical_rl_space_, *style_, static_position, minmax_60, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(top + margin_space, p.inset.top);
EXPECT_EQ(bottom + margin_space, p.inset.bottom);
@@ -399,7 +399,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
SetVerticalStyle(top, NGAuto, LayoutUnit(300), NGAuto, bottom);
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(top, p.inset.top);
EXPECT_EQ(-top, p.inset.bottom);
@@ -409,7 +409,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), true);
auto_height = LayoutUnit(60);
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(*auto_height, p.size.height);
@@ -418,7 +418,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
auto_height.reset();
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(margin_top, p.inset.top);
EXPECT_EQ(container_size_.block_size - margin_top - height, p.inset.bottom);
@@ -428,7 +428,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), true);
auto_height = LayoutUnit(20);
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(border_padding, p.size.height);
@@ -437,7 +437,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), true);
auto_height = LayoutUnit(70);
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(*auto_height, p.size.height);
@@ -446,7 +446,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
auto_height.reset();
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(top + margin_top, p.inset.top);
@@ -455,7 +455,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
auto_height.reset();
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(bottom + margin_bottom, p.inset.bottom);
@@ -464,7 +464,7 @@ TEST_F(NGAbsoluteUtilsTest, Vertical) {
EXPECT_EQ(AbsoluteNeedsChildBlockSize(*style_), false);
auto_height.reset();
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(height, p.size.height);
}
@@ -488,39 +488,39 @@ TEST_F(NGAbsoluteUtilsTest, MinMax) {
// width < min gets set to min.
SetHorizontalStyle(NGAuto, NGAuto, LayoutUnit(5), NGAuto, NGAuto);
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(min, p.size.width);
// width > max gets set to max.
SetHorizontalStyle(NGAuto, NGAuto, LayoutUnit(200), NGAuto, NGAuto);
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(max, p.size.width);
// Unspecified width becomes minmax, gets clamped to min.
SetHorizontalStyle(NGAuto, NGAuto, NGAuto, NGAuto, NGAuto);
p = ComputePartialAbsoluteWithChildInlineSize(
- *ltr_space_, *style_, static_position, estimated_inline, WTF::nullopt,
+ *ltr_space_, *style_, static_position, estimated_inline, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr);
EXPECT_EQ(min, p.size.width);
// HEIGHT TESTS
- Optional<LayoutUnit> auto_height;
+ base::Optional<LayoutUnit> auto_height;
// height < min gets set to min.
SetVerticalStyle(NGAuto, NGAuto, LayoutUnit(5), NGAuto, NGAuto);
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(min, p.size.height);
// height > max gets set to max.
SetVerticalStyle(NGAuto, NGAuto, LayoutUnit(200), NGAuto, NGAuto);
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(max, p.size.height);
@@ -528,7 +528,7 @@ TEST_F(NGAbsoluteUtilsTest, MinMax) {
SetVerticalStyle(NGAuto, NGAuto, NGAuto, NGAuto, NGAuto);
auto_height = LayoutUnit(20);
ComputeFullAbsoluteWithChildBlockSize(
- *ltr_space_, *style_, static_position, auto_height, WTF::nullopt,
+ *ltr_space_, *style_, static_position, auto_height, base::nullopt,
WritingMode::kHorizontalTb, TextDirection::kLtr, &p);
EXPECT_EQ(min, p.size.width);
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_base_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_base_fragment_builder.cc
index 356a4863457..09fff586050 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_base_fragment_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_base_fragment_builder.cc
@@ -4,6 +4,8 @@
#include "third_party/blink/renderer/core/layout/ng/ng_base_fragment_builder.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
+
namespace blink {
NGBaseFragmentBuilder::NGBaseFragmentBuilder(
@@ -12,7 +14,8 @@ NGBaseFragmentBuilder::NGBaseFragmentBuilder(
TextDirection direction)
: style_(std::move(style)),
writing_mode_(writing_mode),
- direction_(direction) {
+ direction_(direction),
+ style_variant_(NGStyleVariant::kStandard) {
DCHECK(style_);
}
@@ -22,6 +25,12 @@ NGBaseFragmentBuilder::NGBaseFragmentBuilder(WritingMode writing_mode,
NGBaseFragmentBuilder::~NGBaseFragmentBuilder() = default;
+NGBaseFragmentBuilder& NGBaseFragmentBuilder::SetStyleVariant(
+ NGStyleVariant style_variant) {
+ style_variant_ = style_variant;
+ return *this;
+}
+
NGBaseFragmentBuilder& NGBaseFragmentBuilder::SetStyle(
scoped_refptr<const ComputedStyle> style,
NGStyleVariant style_variant) {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_base_fragment_builder.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_base_fragment_builder.h
index ea0e8495a82..62dcd9510ca 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_base_fragment_builder.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_base_fragment_builder.h
@@ -8,13 +8,14 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
namespace blink {
+class ComputedStyle;
+
class CORE_EXPORT NGBaseFragmentBuilder {
STACK_ALLOCATED();
public:
@@ -24,6 +25,7 @@ class CORE_EXPORT NGBaseFragmentBuilder {
DCHECK(style_);
return *style_;
}
+ NGBaseFragmentBuilder& SetStyleVariant(NGStyleVariant);
NGBaseFragmentBuilder& SetStyle(scoped_refptr<const ComputedStyle>,
NGStyleVariant);
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 b88822c3282..c377e3ac66b 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
@@ -7,10 +7,8 @@
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
-#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.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"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
@@ -19,6 +17,8 @@
namespace blink {
class Element;
+class LayoutNGBlockFlow;
+class NGPhysicalBoxFragment;
// Base class for all LayoutNG Algorithms unit test classes.
typedef bool TestParamLayoutNG;
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 b20e516c46a..5b315e8cada 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
@@ -8,7 +8,6 @@
#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_layout_test.h"
-#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
namespace blink {
namespace {
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 3f03f269bcb..baa5f80f16e 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
@@ -8,55 +8,69 @@
#include <memory>
#include <utility>
+#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/layout_object.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/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_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_floats_utils.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.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"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#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/style/computed_style.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink {
namespace {
-// Returns if a child may be affected by its clear property. I.e. it will
-// actually clear a float.
-bool ClearanceMayAffectLayout(
- const NGExclusionSpace& exclusion_space,
- const Vector<scoped_refptr<NGUnpositionedFloat>>& unpositioned_floats,
- const ComputedStyle& child_style) {
- EClear clear = child_style.Clear();
- bool should_clear_left = (clear == EClear::kBoth || clear == EClear::kLeft);
- bool should_clear_right = (clear == EClear::kBoth || clear == EClear::kRight);
-
- if (exclusion_space.HasLeftFloat() && should_clear_left)
- return true;
-
- if (exclusion_space.HasRightFloat() && should_clear_right)
- return true;
-
- auto should_clear_pred =
- [&](const scoped_refptr<const NGUnpositionedFloat>& unpositioned_float) {
- return (unpositioned_float->IsLeft() && should_clear_left) ||
- (unpositioned_float->IsRight() && should_clear_right);
- };
+// Return true if a child is to be cleared past adjoining floats. These are
+// floats that would otherwise (if 'clear' were 'none') be pulled down by the
+// BFC offset of the child. If the child is to clear floats, though, we
+// obviously need separate the child from the floats and move it past them,
+// since that's what clearance is all about. This means that if we have any such
+// floats to clear, we know for sure that we get clearance, even before layout.
+inline bool HasClearancePastAdjoiningFloats(NGFloatTypes adjoining_floats,
+ const ComputedStyle& child_style) {
+ return ToFloatTypes(child_style.Clear()) & adjoining_floats;
+}
- if (std::any_of(unpositioned_floats.begin(), unpositioned_floats.end(),
- should_clear_pred))
+// Adjust BFC block offset for clearance, if applicable. Return true of
+// clearance was applied.
+//
+// Clearance applies either when the BFC block offset calculated simply isn't
+// past all relevant floats, *or* when we have already determined that we're
+// directly preceded by clearance.
+//
+// The latter is the case when we need to force ourselves past floats that would
+// otherwise be adjoining, were it not for the predetermined clearance.
+// Clearance inhibits margin collapsing and acts as spacing before the
+// block-start margin of the child. It needs to be exactly what takes the
+// block-start border edge of the cleared block adjacent to the block-end outer
+// edge of the "bottommost" relevant float.
+//
+// We cannot reliably calculate the actual clearance amount at this point,
+// because 1) this block right here may actually be a descendant of the block
+// that is to be cleared, and 2) we may not yet have separated the margin before
+// and after the clearance. None of this matters, though, because we know where
+// to place this block if clearance applies: exactly at the ConstraintSpace's
+// ClearanceOffset().
+bool ApplyClearance(const NGConstraintSpace& constraint_space,
+ LayoutUnit* bfc_block_offset) {
+ if (constraint_space.HasClearanceOffset() &&
+ (*bfc_block_offset < constraint_space.ClearanceOffset() ||
+ constraint_space.ShouldForceClearance())) {
+ *bfc_block_offset = constraint_space.ClearanceOffset();
return true;
-
+ }
return false;
}
@@ -112,7 +126,11 @@ NGBlockLayoutAlgorithm::NGBlockLayoutAlgorithm(NGBlockNode node,
is_resuming_(break_token && !break_token->IsBreakBefore()),
exclusion_space_(new NGExclusionSpace(space.ExclusionSpace())) {}
-Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
+// Define the destructor here, so that we can forward-declare more in the
+// header.
+NGBlockLayoutAlgorithm::~NGBlockLayoutAlgorithm() = default;
+
+base::Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
const MinMaxSizeInput& input) const {
MinMaxSize sizes;
@@ -164,14 +182,11 @@ Optional<MinMaxSize> NGBlockLayoutAlgorithm::ComputeMinMaxSize(
// an anonymous box that contains all line boxes.
// |NextSibling| returns the next block sibling, or nullptr, skipping all
// following inline siblings and descendants.
- child_sizes = child.ComputeMinMaxSize(child_input);
- } else {
- Optional<MinMaxSize> child_minmax;
- if (NeedMinMaxSizeForContentContribution(child_style))
- child_minmax = child.ComputeMinMaxSize(child_input);
-
child_sizes =
- ComputeMinAndMaxContentContribution(child_style, child_minmax);
+ child.ComputeMinMaxSize(Style().GetWritingMode(), child_input);
+ } else {
+ child_sizes = ComputeMinAndMaxContentContribution(
+ Style().GetWritingMode(), child, child_input);
}
// Determine the max inline contribution of the child.
@@ -244,7 +259,7 @@ NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset(
NGLayoutInputNode child,
const NGFragment& fragment,
const NGBoxStrut& child_margins,
- const WTF::Optional<NGBfcOffset>& known_fragment_offset) {
+ const base::Optional<NGBfcOffset>& known_fragment_offset) {
if (known_fragment_offset) {
return LogicalFromBfcOffsets(
fragment, known_fragment_offset.value(), ContainerBfcOffset(),
@@ -257,7 +272,7 @@ NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset(
if (child.IsInline()) {
LayoutUnit offset =
LineOffsetForTextAlign(Style().GetTextAlign(), Style().Direction(),
- child_available_size_.inline_size);
+ child_available_size_.inline_size, LayoutUnit());
if (IsRtl(Style().Direction()))
offset = child_available_size_.inline_size - offset;
inline_offset += offset;
@@ -271,7 +286,7 @@ NGLogicalOffset NGBlockLayoutAlgorithm::CalculateLogicalOffset(
}
scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
- WTF::Optional<MinMaxSize> min_max_size;
+ base::Optional<MinMaxSize> min_max_size;
if (NeedMinMaxSize(ConstraintSpace(), Style())) {
MinMaxSizeInput zero_input;
min_max_size = ComputeMinMaxSize(zero_input);
@@ -293,47 +308,79 @@ scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
// Anonymous constraint spaces are auto-sized. Don't let that affect
// block-axis percentage resolution.
- if (ConstraintSpace().IsAnonymous())
+ if (ConstraintSpace().IsAnonymous() || Node().IsAnonymous())
child_percentage_size_ = ConstraintSpace().PercentageResolutionSize();
else
child_percentage_size_ = adjusted_size;
+ if (ConstraintSpace().IsFixedSizeBlock() &&
+ !ConstraintSpace().FixedSizeBlockIsDefinite())
+ child_percentage_size_.block_size = NGSizeIndefinite;
container_builder_.SetInlineSize(size.inline_size);
- // If we have a list of unpositioned floats as input to this layout, we'll
- // need to abort once our BFC offset is resolved. Additionally the
- // FloatsBfcOffset() must not be present in this case.
- unpositioned_floats_ = ConstraintSpace().UnpositionedFloats();
- abort_when_bfc_resolved_ = !unpositioned_floats_.IsEmpty();
- if (abort_when_bfc_resolved_)
- DCHECK(!ConstraintSpace().FloatsBfcOffset());
+ if (NGFloatTypes float_types = ConstraintSpace().AdjoiningFloatTypes()) {
+ DCHECK(!ConstraintSpace().IsNewFormattingContext());
+ DCHECK(!container_builder_.BfcOffset());
+
+ // If there were preceding adjoining floats, they will be affected when the
+ // BFC offset gets resolved or updated. We then need to roll back and
+ // re-layout those floats with the new BFC offset, once the BFC offset is
+ // updated.
+ abort_when_bfc_offset_updated_ = true;
+
+ container_builder_.AddAdjoiningFloatTypes(float_types);
+ }
// If we are resuming from a break token our start border and padding is
// within a previous fragment.
- intrinsic_block_size_ =
+ LayoutUnit content_edge =
is_resuming_ ? LayoutUnit() : border_scrollbar_padding_.block_start;
- NGMarginStrut input_margin_strut = ConstraintSpace().MarginStrut();
-
- LayoutUnit input_bfc_block_offset =
- ConstraintSpace().BfcOffset().block_offset;
-
- // Margins collapsing:
- // Do not collapse margins between parent and its child if there is
- // border/padding between them.
- if (border_scrollbar_padding_.block_start) {
- input_bfc_block_offset += input_margin_strut.Sum();
- bool updated = MaybeUpdateFragmentBfcOffset(input_bfc_block_offset);
+ NGPreviousInflowPosition previous_inflow_position = {
+ ConstraintSpace().BfcOffset().block_offset, LayoutUnit(),
+ ConstraintSpace().MarginStrut(),
+ /* empty_block_affected_by_clearance */ false};
- if (updated && abort_when_bfc_resolved_) {
- container_builder_.SwapUnpositionedFloats(&unpositioned_floats_);
+ // Margins collapsing: Do not collapse margins between parent and its child if
+ // there is border/padding between them. Then we can and must resolve the BFC
+ // offset now. Also, if this is a new formatting context, or if we're resuming
+ // layout from a break token, we need to resolve the BFC offset now. Margin
+ // struts cannot pass from one fragment to another if they are generated by
+ // the same block; they must be dealt with at the first fragment.
+ if (border_scrollbar_padding_.block_start || is_resuming_ ||
+ ConstraintSpace().IsNewFormattingContext()) {
+ if (!ResolveBfcOffset(&previous_inflow_position)) {
+ // There should be no preceding content that depends on the BFC offset of
+ // a new formatting context block, and likewise when resuming from a break
+ // token.
+ DCHECK(!ConstraintSpace().IsNewFormattingContext());
+ DCHECK(!is_resuming_);
return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved);
}
+ // Move to the content edge. This is where the first child should be placed.
+ previous_inflow_position.bfc_block_offset += content_edge;
+ previous_inflow_position.logical_block_offset = content_edge;
+ }
+
+#if DCHECK_IS_ON()
+ // If this is a new formatting context, we should definitely be at the origin
+ // here. If we're resuming from a break token (for a block that doesn't
+ // establish a new formatting context), that may not be the case,
+ // though. There may e.g. be clearance involved, or inline-start margins.
+ if (ConstraintSpace().IsNewFormattingContext())
+ DCHECK_EQ(container_builder_.BfcOffset().value(), NGBfcOffset());
+ // If this is a new formatting context, or if we're resuming from a break
+ // token, no margin strut must be lingering around at this point.
+ if (ConstraintSpace().IsNewFormattingContext() || is_resuming_)
+ DCHECK(ConstraintSpace().MarginStrut().IsEmpty());
- // We reset the block offset here as it may have been effected by clearance.
- input_bfc_block_offset = ContainerBfcOffset().block_offset;
- input_margin_strut = NGMarginStrut();
+ if (!container_builder_.BfcOffset()) {
+ // New formatting contexts, and where we have an empty block affected by
+ // clearance should already have their BFC offset resolved.
+ DCHECK(!previous_inflow_position.empty_block_affected_by_clearance);
+ DCHECK(!ConstraintSpace().IsNewFormattingContext());
}
+#endif
// If this node is a quirky container, (we are in quirks mode and either a
// table cell or body), we set our margin strut to a mode where it only
@@ -346,32 +393,10 @@ scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
// In the above example <p>'s & <h1>'s margins are ignored as they are
// quirky, and we only consider <div>'s 10px margin.
if (node_.IsQuirkyContainer())
- input_margin_strut.is_quirky_container_start = true;
-
- // If a new formatting context hits the margin collapsing if-branch above
- // then the BFC offset is still {} as the margin strut from the constraint
- // space must also be empty.
- // If we are resuming layout from a break token the same rule applies. Margin
- // struts cannot pass through break tokens (unless it's a break token before
- // the first fragment (the one we're about to create)).
- if (ConstraintSpace().IsNewFormattingContext() || is_resuming_) {
- MaybeUpdateFragmentBfcOffset(input_bfc_block_offset);
- DCHECK(input_margin_strut.IsEmpty());
-#if DCHECK_IS_ON()
- // If this is a new formatting context, we should definitely be at the
- // origin here. If we're resuming at a fragmented block (that doesn't
- // establish a new formatting context), that may not be the case,
- // though. There may e.g. be clearance involved, or inline-start margins.
- if (ConstraintSpace().IsNewFormattingContext())
- DCHECK_EQ(container_builder_.BfcOffset().value(), NGBfcOffset());
-#endif
- }
+ previous_inflow_position.margin_strut.is_quirky_container_start = true;
- input_bfc_block_offset += intrinsic_block_size_;
+ intrinsic_block_size_ = content_edge;
- NGPreviousInflowPosition previous_inflow_position = {
- input_bfc_block_offset, intrinsic_block_size_, input_margin_strut,
- /* empty_block_affected_by_clearance */ false};
scoped_refptr<NGBreakToken> previous_inline_break_token;
NGBlockChildIterator child_iterator(Node().FirstChild(), BreakToken());
@@ -408,7 +433,6 @@ scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
if (!success) {
// We need to abort the layout, as our BFC offset was resolved.
- container_builder_.SwapUnpositionedFloats(&unpositioned_floats_);
return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved);
}
if (container_builder_.DidBreak() && IsFragmentainerOutOfSpace())
@@ -418,32 +442,15 @@ scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
}
NGMarginStrut end_margin_strut = previous_inflow_position.margin_strut;
- LayoutUnit end_bfc_block_offset = previous_inflow_position.bfc_block_offset;
// If the current layout is a new formatting context, we need to encapsulate
// all of our floats.
if (ConstraintSpace().IsNewFormattingContext()) {
- // We can use the BFC coordinates, as we are a new formatting context.
- DCHECK_EQ(container_builder_.BfcOffset().value(), NGBfcOffset());
-
- WTF::Optional<LayoutUnit> float_end_offset =
- exclusion_space_->ClearanceOffset(EClear::kBoth);
-
- // We only update the size of this fragment if we need to grow to
- // encapsulate the floats.
- if (float_end_offset && float_end_offset.value() > end_bfc_block_offset) {
- end_margin_strut = NGMarginStrut();
- end_bfc_block_offset = float_end_offset.value();
- intrinsic_block_size_ =
- std::max(intrinsic_block_size_, float_end_offset.value());
- }
+ intrinsic_block_size_ =
+ std::max(intrinsic_block_size_,
+ exclusion_space_->ClearanceOffset(EClear::kBoth));
}
- // There are still a couple of opportunities to find something solid for this
- // block to hang on to, if we haven't already been able to do so. Keep track
- // of this, so that we can abort layout if necessary.
- bool bfc_updated = false;
-
// 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.
@@ -462,8 +469,6 @@ scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
LayoutUnit margin_strut_sum = node_.IsQuirkyContainer()
? end_margin_strut.QuirkyContainerSum()
: end_margin_strut.Sum();
- end_bfc_block_offset += margin_strut_sum;
-
if (!container_builder_.BfcOffset()) {
// If we have collapsed through the block start and all children (if any),
// now is the time to determine the BFC offset, because finally we have
@@ -471,8 +476,9 @@ scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
// for instance). If we're a new formatting context, though, we shouldn't
// be here, because then the offset should already have been determined.
DCHECK(!ConstraintSpace().IsNewFormattingContext());
- bfc_updated = MaybeUpdateFragmentBfcOffset(end_bfc_block_offset);
- DCHECK(bfc_updated);
+ if (!ResolveBfcOffset(&previous_inflow_position))
+ return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved);
+ DCHECK(container_builder_.BfcOffset());
} else {
// The trailing margin strut will be part of our intrinsic block size, but
// only if there is something that separates the end margin strut from the
@@ -503,25 +509,12 @@ scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
// have a break token, it means that we know the blocks' position even if
// they're empty; it will be at the very start of the fragmentainer.
if (!container_builder_.BfcOffset() && (size.block_size || BreakToken())) {
- end_bfc_block_offset += end_margin_strut.Sum();
- bfc_updated = MaybeUpdateFragmentBfcOffset(end_bfc_block_offset);
- DCHECK(bfc_updated);
- }
-
- if (bfc_updated && abort_when_bfc_resolved_) {
- // New formatting contexts, and where we have an empty block affected by
- // clearance should already have their BFC offset resolved, and shouldn't
- // enter this branch.
- DCHECK(!previous_inflow_position.empty_block_affected_by_clearance);
- DCHECK(!ConstraintSpace().IsNewFormattingContext());
-
- container_builder_.SwapUnpositionedFloats(&unpositioned_floats_);
- return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved);
+ if (!ResolveBfcOffset(&previous_inflow_position))
+ return container_builder_.Abort(NGLayoutResult::kBfcOffsetResolved);
+ DCHECK(container_builder_.BfcOffset());
}
if (container_builder_.BfcOffset()) {
- PositionPendingFloats(end_bfc_block_offset);
-
// Do not collapse margins between the last in-flow child and bottom margin
// of its parent if the parent has height != auto.
if (!Style().LogicalHeight().IsAuto()) {
@@ -556,18 +549,24 @@ scoped_refptr<NGLayoutResult> NGBlockLayoutAlgorithm::Layout() {
.Run();
}
- // If we have any unpositioned floats at this stage, need to tell our parent
- // about this, so that we get relayout with a forced BFC offset.
+#if DCHECK_IS_ON()
+ // If we have any unpositioned floats at this stage, our parent will pick up
+ // this by examining adjoining float types returned, so that we get relayout
+ // with a forced BFC offset once it's known.
if (!unpositioned_floats_.IsEmpty()) {
DCHECK(!container_builder_.BfcOffset());
- container_builder_.SwapUnpositionedFloats(&unpositioned_floats_);
+ DCHECK(container_builder_.AdjoiningFloatTypes());
}
+#endif
PropagateBaselinesFromChildren();
DCHECK(exclusion_space_);
container_builder_.SetExclusionSpace(std::move(exclusion_space_));
+ if (ConstraintSpace().UseFirstLineStyle())
+ container_builder_.SetStyleVariant(NGStyleVariant::kFirstLine);
+
return container_builder_.ToBoxFragment();
}
@@ -603,7 +602,8 @@ void NGBlockLayoutAlgorithm::HandleFloat(
origin_inline_offset,
ConstraintSpace().BfcOffset().line_offset,
margins, child, child_break_token);
- unpositioned_floats_.push_back(std::move(unpositioned_float));
+ AddUnpositionedFloat(&unpositioned_floats_, &container_builder_,
+ unpositioned_float);
// If there is a break token for a float we must be resuming layout, we must
// always know our position in the BFC.
@@ -636,17 +636,71 @@ bool NGBlockLayoutAlgorithm::HandleNewFormattingContext(
const ComputedStyle& child_style = child.Style();
const TextDirection direction = ConstraintSpace().Direction();
+ bool has_clearance_past_adjoining_floats = HasClearancePastAdjoiningFloats(
+ container_builder_.AdjoiningFloatTypes(), child_style);
NGInflowChildData child_data =
- ComputeChildData(*previous_inflow_position, child, child_break_token);
-
+ ComputeChildData(*previous_inflow_position, child, child_break_token,
+ has_clearance_past_adjoining_floats);
+
+ // If the child has a block-start margin, and the BFC offset is still
+ // unresolved, and we have preceding adjoining floats, things get complicated
+ // here. Depending on whether the child fits beside the floats, the margin may
+ // or may not be adjoining with the current margin strut. This affects the
+ // position of the preceding adjoining floats. We may have to resolve the BFC
+ // offset once with the child's margin tentatively adjoining, then realize
+ // that the child isn't going to fit beside the floats at the current
+ // position, and therefore re-resolve the BFC offset with the child's margin
+ // non-adjoining. This is akin to clearance.
NGMarginStrut adjoining_margin_strut(previous_inflow_position->margin_strut);
adjoining_margin_strut.Append(child_data.margins.block_start,
child_style.HasMarginBeforeQuirk());
-
- LayoutUnit initial_child_bfc_offset_estimate =
+ LayoutUnit adjoining_bfc_offset_estimate =
child_data.bfc_offset_estimate.block_offset +
adjoining_margin_strut.Sum();
- LayoutUnit child_bfc_offset_estimate = initial_child_bfc_offset_estimate;
+ LayoutUnit non_adjoining_bfc_offset_estimate =
+ child_data.bfc_offset_estimate.block_offset +
+ previous_inflow_position->margin_strut.Sum();
+ LayoutUnit child_bfc_offset_estimate = adjoining_bfc_offset_estimate;
+ bool bfc_offset_already_resolved = false;
+ bool child_determined_bfc_offset = false;
+ bool child_margin_got_separated = false;
+ bool had_pending_floats = false;
+
+ if (!container_builder_.BfcOffset()) {
+ had_pending_floats = !unpositioned_floats_.IsEmpty();
+
+ if (ConstraintSpace().FloatsBfcOffset()) {
+ // This is not the first time we're here. We already have a suggested BFC
+ // offset.
+ bfc_offset_already_resolved = true;
+ NGBfcOffset bfc_offset = *ConstraintSpace().FloatsBfcOffset();
+ child_bfc_offset_estimate = bfc_offset.block_offset;
+ // We require that the BFC offset be the one we'd get with either margins
+ // adjoining or margins separated. Anything else is a bug.
+ DCHECK(bfc_offset.block_offset == adjoining_bfc_offset_estimate ||
+ bfc_offset.block_offset == non_adjoining_bfc_offset_estimate);
+ // Figure out if the child margin has already got separated from the
+ // margin strut or not.
+ child_margin_got_separated =
+ bfc_offset.block_offset != adjoining_bfc_offset_estimate;
+ } else if (has_clearance_past_adjoining_floats) {
+ child_bfc_offset_estimate = previous_inflow_position->NextBorderEdge();
+ child_margin_got_separated = true;
+ }
+
+ // The BFC offset of this container gets resolved because of this child.
+ child_determined_bfc_offset = true;
+ if (!ResolveBfcOffset(previous_inflow_position,
+ child_bfc_offset_estimate)) {
+ // If we need to abort here, it means that we had preceding unpositioned
+ // floats. This is only expected if we're here for the first time.
+ DCHECK(!bfc_offset_already_resolved);
+ return false;
+ }
+
+ // We reset the block offset here as it may have been affected by clearance.
+ child_bfc_offset_estimate = ContainerBfcOffset().block_offset;
+ }
// If the child has a non-zero block-start margin, our initial estimate will
// be that any pending floats will be flush (block-start-wise) with this
@@ -659,7 +713,9 @@ bool NGBlockLayoutAlgorithm::HandleNewFormattingContext(
// ignore this margin, which may cause them to end up at completely different
// positions than initially estimated. In other words, we'll need another
// layout pass if this happens.
- bool abort_if_cleared = child_data.margins.block_start != LayoutUnit();
+ bool abort_if_cleared = child_data.margins.block_start != LayoutUnit() &&
+ !child_margin_got_separated &&
+ child_determined_bfc_offset;
NGLayoutOpportunity opportunity;
scoped_refptr<NGLayoutResult> layout_result;
std::tie(layout_result, opportunity) =
@@ -669,39 +725,43 @@ bool NGBlockLayoutAlgorithm::HandleNewFormattingContext(
if (!layout_result) {
DCHECK(abort_if_cleared);
// Layout got aborted, because the child got pushed down by floats, and we
- // had pending floats that we tentatively positioned incorrectly, due to a
- // margin that shouldn't have affected them. Try again without the child's
- // margin. This re-layout *must* produce a fragment and opportunity which
- // fits within the exclusion space.
+ // may have had pending floats that we tentatively positioned incorrectly
+ // (since the child's margin shouldn't have affected them). Try again
+ // without the child's margin. So, we need another layout pass. Figure out
+ // if we can do it right away from here, or if we have to roll back and
+ // reposition floats first.
+ if (child_determined_bfc_offset) {
+ // The BFC offset was calculated when we got to this child, with the
+ // child's margin adjoining. Since that turned out to be wrong, re-resolve
+ // the BFC offset without the child's margin.
+ LayoutUnit old_offset = container_builder_.BfcOffset()->block_offset;
+ container_builder_.ResetBfcOffset();
+ ResolveBfcOffset(previous_inflow_position,
+ non_adjoining_bfc_offset_estimate);
+ if ((bfc_offset_already_resolved || had_pending_floats) &&
+ old_offset != container_builder_.BfcOffset()->block_offset) {
+ // The first BFC offset resolution turned out to be wrong, and we
+ // positioned preceding adjacent floats based on that. Now we have to
+ // roll back and position them at the correct offset. The only expected
+ // incorrect estimate is with the child's margin adjoining. Any other
+ // incorrect estimate will result in failed layout.
+ DCHECK_EQ(old_offset, adjoining_bfc_offset_estimate);
+ return false;
+ }
+ }
+
DCHECK_GT(opportunity.rect.start_offset.block_offset,
child_bfc_offset_estimate);
- NGMarginStrut non_adjoining_margin_strut(
- previous_inflow_position->margin_strut);
- child_bfc_offset_estimate = child_data.bfc_offset_estimate.block_offset +
- non_adjoining_margin_strut.Sum();
-
- // Make sure that we don't move below the previously found layout
- // opportunity. This could otherwise happen if the child has negative
- // margins.
- child_bfc_offset_estimate = std::min(
- child_bfc_offset_estimate, opportunity.rect.start_offset.block_offset);
+ child_bfc_offset_estimate = non_adjoining_bfc_offset_estimate;
+ child_margin_got_separated = true;
+ // We can re-layout the child right away. This re-layout *must* produce a
+ // fragment and opportunity which fits within the exclusion space.
std::tie(layout_result, opportunity) = LayoutNewFormattingContext(
child, child_break_token, child_data, child_bfc_offset_estimate,
/* abort_if_cleared */ false);
}
DCHECK(layout_result->PhysicalFragment());
-
- // We now know the childs BFC offset, try and update our own if needed.
- bool updated = MaybeUpdateFragmentBfcOffset(child_bfc_offset_estimate);
-
- if (updated && abort_when_bfc_resolved_)
- return false;
-
- // Position any pending floats if we've just updated our BFC offset.
- PositionPendingFloats(child_bfc_offset_estimate);
-
- DCHECK(layout_result->PhysicalFragment());
const auto& physical_fragment = *layout_result->PhysicalFragment();
NGFragment fragment(ConstraintSpace().GetWritingMode(), physical_fragment);
@@ -720,8 +780,9 @@ bool NGBlockLayoutAlgorithm::HandleNewFormattingContext(
if (ConstraintSpace().HasBlockFragmentation()) {
bool is_pushed_by_floats =
- layout_result->IsPushedByFloats() ||
- child_bfc_offset.block_offset > initial_child_bfc_offset_estimate;
+ child_margin_got_separated ||
+ child_bfc_offset.block_offset > child_bfc_offset_estimate ||
+ layout_result->IsPushedByFloats();
if (BreakBeforeChild(child, *layout_result, logical_offset.block_offset,
is_pushed_by_floats))
return true;
@@ -758,28 +819,18 @@ NGBlockLayoutAlgorithm::LayoutNewFormattingContext(
const TextDirection direction = ConstraintSpace().Direction();
const WritingMode writing_mode = ConstraintSpace().GetWritingMode();
- // Position all the pending floats into a temporary exclusion space. This
- // *doesn't* place them into our output exclusion space yet, as we don't know
- // where the child will be positioned, and hence what *out* BFC offset is.
- // If we already know our BFC offset, this won't have any affect.
- NGExclusionSpace tmp_exclusion_space(*exclusion_space_);
- PositionFloats(child_origin_block_offset, child_origin_block_offset,
- unpositioned_floats_, ConstraintSpace(), &tmp_exclusion_space);
-
LayoutUnit child_bfc_line_offset =
ConstraintSpace().BfcOffset().line_offset +
border_scrollbar_padding_.LineLeft(direction) +
child_data.margins.LineLeft(direction);
// The origin offset is where we should start looking for layout
- // opportunities. It needs to be adjusted by the child's clearance, in
- // addition to the parent's (if we don't know our BFC offset yet).
+ // opportunities. It needs to be adjusted by the child's clearance.
NGBfcOffset origin_offset = {child_bfc_line_offset,
child_origin_block_offset};
- AdjustToClearance(tmp_exclusion_space.ClearanceOffset(child.Style().Clear()),
+ AdjustToClearance(exclusion_space_->ClearanceOffset(child.Style().Clear()),
&origin_offset);
- if (!container_builder_.BfcOffset())
- AdjustToClearance(ConstraintSpace().ClearanceOffset(), &origin_offset);
+ DCHECK(container_builder_.BfcOffset());
// Before we lay out, figure out how much inline space we have available at
// the start block offset estimate (the child is not allowed to overlap with
@@ -793,7 +844,7 @@ NGBlockLayoutAlgorithm::LayoutNewFormattingContext(
LayoutUnit inline_margin = child_data.margins.InlineSum();
LayoutUnit inline_size =
(child_available_size_.inline_size - inline_margin).ClampNegativeToZero();
- NGLayoutOpportunity opportunity = tmp_exclusion_space.FindLayoutOpportunity(
+ NGLayoutOpportunity opportunity = exclusion_space_->FindLayoutOpportunity(
origin_offset, inline_size, NGLogicalSize());
scoped_refptr<NGLayoutResult> layout_result;
@@ -807,7 +858,8 @@ NGBlockLayoutAlgorithm::LayoutNewFormattingContext(
if (abort_if_cleared &&
origin_offset.block_offset < opportunity.rect.BlockStartOffset()) {
// Abort if we got pushed downwards. We need to adjust
- // child_origin_block_offset and try again.
+ // child_origin_block_offset, reposition any floats affected by that, and
+ // try again.
layout_result = nullptr;
break;
}
@@ -829,7 +881,7 @@ NGBlockLayoutAlgorithm::LayoutNewFormattingContext(
// Now find a layout opportunity where the fragment is actually going to
// fit.
NGFragment fragment(writing_mode, *layout_result->PhysicalFragment());
- opportunity = tmp_exclusion_space.FindLayoutOpportunity(
+ opportunity = exclusion_space_->FindLayoutOpportunity(
origin_offset, inline_size, fragment.Size());
} while (origin_offset.block_offset < opportunity.rect.BlockStartOffset());
@@ -849,102 +901,53 @@ bool NGBlockLayoutAlgorithm::HandleInflow(
bool is_non_empty_inline =
child.IsInline() && !ToNGInlineNode(child).IsEmptyInline();
- // TODO(ikilpatrick): We may only want to position pending floats if there is
- // something that we *might* clear in the unpositioned list. E.g. we may
- // clear an already placed left float, but the unpositioned list may only have
- // right floats.
- bool should_position_pending_floats =
+ bool has_clearance_past_adjoining_floats =
child.IsBlock() &&
- ClearanceMayAffectLayout(*exclusion_space_, unpositioned_floats_,
- child.Style());
+ HasClearancePastAdjoiningFloats(container_builder_.AdjoiningFloatTypes(),
+ child.Style());
- // There are two conditions where we need to position our pending floats:
- // 1. If the child will be affected by clearance.
+ // If we can separate the previous margin strut from what is to follow, do
+ // that. Then we're able to resolve *our* BFC offset and position any pending
+ // floats. There are two situations where this is necessary:
+ // 1. If the child is to be cleared by adjoining floats.
// 2. If the child is a non-empty inline.
- // This collapses the previous margin strut, and optionally resolves *our*
- // BFC offset.
- if (should_position_pending_floats || is_non_empty_inline) {
- LayoutUnit origin_point_block_offset =
- previous_inflow_position->bfc_block_offset +
- previous_inflow_position->margin_strut.Sum();
- bool updated = MaybeUpdateFragmentBfcOffset(origin_point_block_offset);
-
- if (updated && abort_when_bfc_resolved_)
+ if (has_clearance_past_adjoining_floats || is_non_empty_inline) {
+ if (!ResolveBfcOffset(previous_inflow_position))
return false;
-
- // If our BFC offset was updated we may have been affected by clearance
- // ourselves. We need to adjust the origin point to accomodate this.
- if (updated)
- origin_point_block_offset =
- std::max(origin_point_block_offset,
- ConstraintSpace().ClearanceOffset().value_or(LayoutUnit()));
-
- bool positioned_direct_child_floats = !unpositioned_floats_.IsEmpty();
-
- PositionPendingFloats(origin_point_block_offset);
-
- // If we positioned float which are direct children, or the child is a
- // non-empty inline, we need to artificially "reset" the previous inflow
- // position, e.g. we clear the margin strut, and set the offset to our
- // block-start border edge.
- //
- // This behaviour is similar to if we had block-start border or padding.
- if ((positioned_direct_child_floats && updated) || is_non_empty_inline) {
- // We must have no border/scrollbar/padding here otherwise our BFC offset
- // would already be resolved.
- if (!is_non_empty_inline)
- DCHECK_EQ(border_scrollbar_padding_.block_start, LayoutUnit());
-
- previous_inflow_position->bfc_block_offset = origin_point_block_offset;
- previous_inflow_position->margin_strut = NGMarginStrut();
- previous_inflow_position->logical_block_offset = LayoutUnit();
- }
}
// Perform layout on the child.
NGInflowChildData child_data =
- ComputeChildData(*previous_inflow_position, child, child_break_token);
+ ComputeChildData(*previous_inflow_position, child, child_break_token,
+ has_clearance_past_adjoining_floats);
scoped_refptr<NGConstraintSpace> child_space =
CreateConstraintSpaceForChild(child, child_data, child_available_size_);
scoped_refptr<NGLayoutResult> layout_result =
child.Layout(*child_space, child_break_token);
+ base::Optional<NGBfcOffset> child_bfc_offset = layout_result->BfcOffset();
+ // TODO(layout-dev): A more optimal version of this is to set
+ // relayout_child_when_bfc_resolved only if the child tree itself _added_ any
+ // floats that it failed to position. Currently, we risk relaying out the
+ // parent block for no reason, because we're not able to make this
+ // distinction.
+ bool relayout_child_when_bfc_resolved =
+ layout_result->AdjoiningFloatTypes() && !child_bfc_offset &&
+ !child_space->FloatsBfcOffset();
bool is_empty_block = IsEmptyBlock(child, *layout_result);
- // If we don't know our BFC offset yet, we need to copy the list of
- // unpositioned floats from the child's layout result.
- //
- // If the child had any unpositioned floats, we need to abort our layout if
- // we resolve our BFC offset.
- //
- // If we are a new formatting context, the child will get re-laid out once it
- // has been positioned.
- //
- // TODO(ikilpatrick): a more optimal version of this is to set
- // abort_when_bfc_resolved_, if the child tree _added_ any floats.
- if (!container_builder_.BfcOffset()) {
- unpositioned_floats_ = layout_result->UnpositionedFloats();
- abort_when_bfc_resolved_ |= !layout_result->UnpositionedFloats().IsEmpty();
- if (child_space->FloatsBfcOffset())
- DCHECK(layout_result->UnpositionedFloats().IsEmpty());
- // If our BFC offset is unknown, and the child got pushed down by floats, so
- // will we.
- if (layout_result->IsPushedByFloats())
- container_builder_.SetIsPushedByFloats();
- }
-
// A child may have aborted its layout if it resolved its BFC offset. If
// we don't have a BFC offset yet, we need to propagate the abortion up
// to our parent.
if (layout_result->Status() == NGLayoutResult::kBfcOffsetResolved &&
!container_builder_.BfcOffset()) {
- MaybeUpdateFragmentBfcOffset(
- layout_result->BfcOffset().value().block_offset);
-
- // NOTE: Unlike other aborts, we don't try check if we *should* abort with
- // abort_when_bfc_resolved_, this is simply propagating an abort up to a
- // node which is able to restart the layout (a node that has resolved its
- // BFC offset).
+ // There's no need to do anything apart from resolving the BFC offset here,
+ // so make sure that it aborts before trying to position floats or anything
+ // like that, which would just be waste of time. This is simply propagating
+ // an abort up to a node which is able to restart the layout (a node that
+ // has resolved its BFC offset).
+ abort_when_bfc_offset_updated_ = true;
+ ResolveBfcOffset(previous_inflow_position, child_bfc_offset->block_offset);
return false;
}
@@ -967,22 +970,50 @@ bool NGBlockLayoutAlgorithm::HandleInflow(
// We try and position the child within the block formatting context. This
// may cause our BFC offset to be resolved, in which case we should abort our
// layout if needed.
- WTF::Optional<NGBfcOffset> child_bfc_offset;
- if (layout_result->BfcOffset()) {
- if (!PositionWithBfcOffset(layout_result->BfcOffset().value(),
- &child_bfc_offset))
+ bool has_clearance = layout_result->IsPushedByFloats();
+ if (!child_bfc_offset) {
+ if (!has_clearance && child_space->HasClearanceOffset() &&
+ child.Style().Clear() != EClear::kNone) {
+ // This is an empty block child that we collapsed through, so we have to
+ // detect clearance manually. See if the child's hypothetical border edge
+ // is past the relevant floats. If it's not, we need to apply clearance
+ // before it.
+ LayoutUnit child_block_offset_estimate =
+ previous_inflow_position->bfc_block_offset +
+ layout_result->EndMarginStrut().Sum();
+ if (child_block_offset_estimate < child_space->ClearanceOffset() ||
+ child_space->ShouldForceClearance())
+ has_clearance = empty_block_affected_by_clearance = true;
+ }
+ }
+ if (has_clearance) {
+ // The child has clearance. Clearance inhibits margin collapsing and acts as
+ // spacing before the block-start margin of the child. Our BFC offset is
+ // therefore resolvable, and if it hasn't already been resolved, we'll do it
+ // now to separate the child's collapsed margin from this container.
+ if (!ResolveBfcOffset(previous_inflow_position))
return false;
- } else {
+ }
+ if (!child_bfc_offset) {
+ DCHECK(is_empty_block);
// Layout wasn't able to determine the BFC offset of the child. This has to
// mean that the child is empty (block-size-wise).
- DCHECK(is_empty_block);
if (container_builder_.BfcOffset()) {
// Since we know our own BFC offset, though, we can calculate that of the
// child as well.
child_bfc_offset = PositionEmptyChildWithParentBfc(
- child, *child_space, child_data, *layout_result,
- &empty_block_affected_by_clearance);
+ child, *child_space, child_data, *layout_result);
}
+ } else if (!has_clearance) {
+ // We shouldn't have any pending floats here, since an in-flow child found
+ // its BFC offset.
+ DCHECK(unpositioned_floats_.IsEmpty());
+
+ // The child's BFC offset is known, and since there's no clearance, this
+ // container will get the same offset, unless it has already been resolved.
+ if (!ResolveBfcOffset(previous_inflow_position,
+ child_bfc_offset->block_offset))
+ return false;
}
// We need to re-layout a child if it was affected by clearance in order to
@@ -1020,7 +1051,7 @@ bool NGBlockLayoutAlgorithm::HandleInflow(
// - It has some unpositioned floats.
// - It was affected by clearance.
if ((layout_result->Status() == NGLayoutResult::kBfcOffsetResolved ||
- !layout_result->UnpositionedFloats().IsEmpty() ||
+ relayout_child_when_bfc_resolved ||
empty_block_affected_by_clearance_needs_relayout) &&
child_bfc_offset) {
scoped_refptr<NGConstraintSpace> new_child_space =
@@ -1028,11 +1059,45 @@ bool NGBlockLayoutAlgorithm::HandleInflow(
child_bfc_offset);
layout_result = child.Layout(*new_child_space, child_break_token);
+ if (layout_result->Status() == NGLayoutResult::kBfcOffsetResolved) {
+ // Even a second layout pass may abort, if the BFC offset initially
+ // calculated turned out to be wrong. This happens when we discover that
+ // an in-flow block-level descendant that establishes a new formatting
+ // context doesn't fit beside the floats at its initial position. Allow
+ // one more pass.
+ child_bfc_offset = layout_result->BfcOffset();
+ DCHECK(child_bfc_offset);
+ new_child_space = CreateConstraintSpaceForChild(
+ child, child_data, child_available_size_, child_bfc_offset);
+ layout_result = child.Layout(*new_child_space, child_break_token);
+ }
+
DCHECK_EQ(layout_result->Status(), NGLayoutResult::kSuccess);
DCHECK(layout_result->ExclusionSpace());
exclusion_space_ =
std::make_unique<NGExclusionSpace>(*layout_result->ExclusionSpace());
+ relayout_child_when_bfc_resolved = false;
+ }
+
+ // If we don't know our BFC offset yet, and the child stumbled into something
+ // that needs it (unable to position floats when the BFC offset is unknown),
+ // we need abort layout once we manage to resolve it, and relayout. Note that
+ // this check is performed after the optional second layout pass above, since
+ // we may have been able to resolve our BFC offset (e.g. due to clearance) and
+ // position any descendant floats in the second pass. In particular, when it
+ // comes to clearance of empty blocks, if we just applied it and resolved the
+ // BFC offset to separate the margins before and after clearance, we cannot
+ // abort and re-layout this block, or clearance would be lost.
+ //
+ // If we are a new formatting context, the child will get re-laid out once it
+ // has been positioned.
+ if (!container_builder_.BfcOffset()) {
+ abort_when_bfc_offset_updated_ |= relayout_child_when_bfc_resolved;
+ // If our BFC offset is unknown, and the child got pushed down by floats,
+ // so will we.
+ if (layout_result->IsPushedByFloats())
+ container_builder_.SetIsPushedByFloats();
}
// A line-box may have a list of floats which we add as children.
@@ -1073,6 +1138,9 @@ bool NGBlockLayoutAlgorithm::HandleInflow(
intrinsic_block_size_ =
std::max(intrinsic_block_size_,
logical_offset.block_offset + fragment.BlockSize());
+ } else if (!container_builder_.BfcOffset()) {
+ container_builder_.AddAdjoiningFloatTypes(
+ layout_result->AdjoiningFloatTypes());
}
container_builder_.AddChild(layout_result, logical_offset);
@@ -1094,7 +1162,8 @@ bool NGBlockLayoutAlgorithm::HandleInflow(
NGInflowChildData NGBlockLayoutAlgorithm::ComputeChildData(
const NGPreviousInflowPosition& previous_inflow_position,
NGLayoutInputNode child,
- const NGBreakToken* child_break_token) {
+ const NGBreakToken* child_break_token,
+ bool force_clearance) {
DCHECK(child);
DCHECK(!child.IsFloating());
@@ -1114,14 +1183,14 @@ NGInflowChildData NGBlockLayoutAlgorithm::ComputeChildData(
margins.LineLeft(ConstraintSpace().Direction()),
previous_inflow_position.bfc_block_offset};
- return {child_bfc_offset, margin_strut, margins};
+ return {child_bfc_offset, margin_strut, margins, force_clearance};
}
NGPreviousInflowPosition NGBlockLayoutAlgorithm::ComputeInflowPosition(
const NGPreviousInflowPosition& previous_inflow_position,
const NGLayoutInputNode child,
const NGInflowChildData& child_data,
- const WTF::Optional<NGBfcOffset>& child_bfc_offset,
+ const base::Optional<NGBfcOffset>& child_bfc_offset,
const NGLogicalOffset& logical_offset,
const NGLayoutResult& layout_result,
const NGFragment& fragment,
@@ -1133,6 +1202,10 @@ NGPreviousInflowPosition NGBlockLayoutAlgorithm::ComputeInflowPosition(
bool is_empty_block = IsEmptyBlock(child, layout_result);
if (is_empty_block) {
+ // The default behaviour for empty blocks is they just pass through the
+ // previous inflow position.
+ child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset;
+
if (empty_block_affected_by_clearance) {
// If an empty block was affected by clearance (that is it got pushed
// down past a float), we need to do something slightly bizarre.
@@ -1144,18 +1217,46 @@ NGPreviousInflowPosition NGBlockLayoutAlgorithm::ComputeInflowPosition(
// Another way of thinking about this is that when you *add* back the
// margin strut, you end up with the same position as you started with.
//
- // This behaviour isn't known to be in any CSS specification.
- child_end_bfc_block_offset = child_bfc_offset.value().block_offset -
- layout_result.EndMarginStrut().Sum();
- logical_block_offset =
- logical_offset.block_offset - layout_result.EndMarginStrut().Sum();
- } else {
- // The default behaviour for empty blocks is they just pass through the
- // previous inflow position.
- child_end_bfc_block_offset = previous_inflow_position.bfc_block_offset;
- logical_block_offset = previous_inflow_position.logical_block_offset;
+ // This is essentially what the spec refers to as clearance [1], and,
+ // while we normally don't have to calculate it directly, in the case of
+ // an empty cleared child like here, we actually have to.
+ //
+ // We have to calculate clearance for empty cleared children, because we
+ // need the margin that's between the clearance and this block to collapse
+ // correctly with subsequent content. This is something that needs to take
+ // place after the margin strut preceding and following the clearance have
+ // been separated. Clearance may be positive, negative or zero, depending
+ // on what it takes to (hypothetically) place this child just below the
+ // last relevant float. Since the margins before and after the clearance
+ // have been separated, we may have to pull the child back, and that's an
+ // example of negative clearance.
+ //
+ // (In the other case, when a cleared child is non-empty (i.e. when we
+ // don't end up here), we don't need to explicitly calculate clearance,
+ // because then we just place its border edge where it should be and we're
+ // done with it.)
+ //
+ // [1] https://www.w3.org/TR/CSS22/visuren.html#flow-control
+
+ // First move past the margin that is to precede the clearance. It will
+ // not participate in any subsequent margin collapsing.
+ LayoutUnit margin_before_clearance =
+ previous_inflow_position.margin_strut.Sum();
+ child_end_bfc_block_offset += margin_before_clearance;
+
+ // Calculate and apply actual clearance.
+ LayoutUnit clearance = child_bfc_offset.value().block_offset -
+ layout_result.EndMarginStrut().Sum() -
+ previous_inflow_position.NextBorderEdge();
+ child_end_bfc_block_offset += clearance;
}
+ // The logical block offset needs to go through exactly the same change as
+ // the BFC block offset here.
+ logical_block_offset = previous_inflow_position.logical_block_offset +
+ child_end_bfc_block_offset -
+ previous_inflow_position.bfc_block_offset;
+
if (!container_builder_.BfcOffset()) {
DCHECK_EQ(child_end_bfc_block_offset,
ConstraintSpace().BfcOffset().block_offset);
@@ -1190,27 +1291,11 @@ NGPreviousInflowPosition NGBlockLayoutAlgorithm::ComputeInflowPosition(
empty_or_sibling_empty_affected_by_clearance};
}
-bool NGBlockLayoutAlgorithm::PositionWithBfcOffset(
- const NGBfcOffset& bfc_offset,
- WTF::Optional<NGBfcOffset>* child_bfc_offset) {
- LayoutUnit bfc_block_offset = bfc_offset.block_offset;
- bool updated = MaybeUpdateFragmentBfcOffset(bfc_block_offset);
-
- if (updated && abort_when_bfc_resolved_)
- return false;
-
- PositionPendingFloats(bfc_block_offset);
-
- *child_bfc_offset = bfc_offset;
- return true;
-}
-
NGBfcOffset NGBlockLayoutAlgorithm::PositionEmptyChildWithParentBfc(
const NGLayoutInputNode& child,
const NGConstraintSpace& child_space,
const NGInflowChildData& child_data,
- const NGLayoutResult& layout_result,
- bool* has_clearance) const {
+ const NGLayoutResult& layout_result) const {
DCHECK(IsEmptyBlock(child, layout_result));
// The child must be an in-flow zero-block-size fragment, use its end margin
@@ -1225,11 +1310,10 @@ NGBfcOffset NGBlockLayoutAlgorithm::PositionEmptyChildWithParentBfc(
if (child.IsInline()) {
child_bfc_offset.line_offset +=
LineOffsetForTextAlign(Style().GetTextAlign(), Style().Direction(),
- child_available_size_.inline_size);
+ child_available_size_.inline_size, LayoutUnit());
}
- *has_clearance =
- AdjustToClearance(child_space.ClearanceOffset(), &child_bfc_offset);
+ ApplyClearance(child_space, &child_bfc_offset.block_offset);
return child_bfc_offset;
}
@@ -1551,12 +1635,12 @@ NGBoxStrut NGBlockLayoutAlgorithm::CalculateMargins(
// TODO(ikilpatrick): Move the auto margins calculation for different writing
// modes to post-layout.
if (!child.IsFloating() && !child.CreatesNewFormattingContext()) {
- WTF::Optional<MinMaxSize> sizes;
+ base::Optional<MinMaxSize> sizes;
if (NeedMinMaxSize(*space, child_style)) {
// We only want to guess the child's size here, so preceding floats are of
// no interest.
MinMaxSizeInput zero_input;
- sizes = child.ComputeMinMaxSize(zero_input);
+ sizes = child.ComputeMinMaxSize(child_style.GetWritingMode(), zero_input);
}
LayoutUnit child_inline_size =
@@ -1575,7 +1659,7 @@ NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
const NGLayoutInputNode child,
const NGInflowChildData& child_data,
const NGLogicalSize child_available_size,
- const WTF::Optional<NGBfcOffset> floats_bfc_offset) {
+ const base::Optional<NGBfcOffset> floats_bfc_offset) {
NGConstraintSpaceBuilder space_builder(ConstraintSpace());
NGLogicalSize available_size(child_available_size);
@@ -1600,8 +1684,11 @@ NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
.SetBfcOffset(child_data.bfc_offset_estimate)
.SetMarginStrut(child_data.margin_strut);
- if (!is_new_fc)
+ if (!is_new_fc) {
space_builder.SetExclusionSpace(*exclusion_space_);
+ space_builder.SetAdjoiningFloatTypes(
+ container_builder_.AdjoiningFloatTypes());
+ }
if (!container_builder_.BfcOffset() && ConstraintSpace().FloatsBfcOffset()) {
space_builder.SetFloatsBfcOffset(
@@ -1612,26 +1699,17 @@ NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
if (floats_bfc_offset)
space_builder.SetFloatsBfcOffset(floats_bfc_offset);
- if (!is_new_fc && !floats_bfc_offset) {
- space_builder.SetUnpositionedFloats(unpositioned_floats_);
- }
-
WritingMode writing_mode;
- Optional<LayoutUnit> clearance_offset;
- if (!constraint_space_.IsNewFormattingContext())
- clearance_offset = ConstraintSpace().ClearanceOffset();
+ LayoutUnit clearance_offset = constraint_space_.IsNewFormattingContext()
+ ? LayoutUnit::Min()
+ : ConstraintSpace().ClearanceOffset();
if (child.IsInline()) {
writing_mode = Style().GetWritingMode();
} else {
const ComputedStyle& child_style = child.Style();
LayoutUnit child_clearance_offset =
exclusion_space_->ClearanceOffset(child_style.Clear());
- if (clearance_offset) {
- clearance_offset =
- std::max(clearance_offset.value(), child_clearance_offset);
- } else {
- clearance_offset = child_clearance_offset;
- }
+ clearance_offset = std::max(clearance_offset, child_clearance_offset);
space_builder.SetIsShrinkToFit(ShouldShrinkToFit(Style(), child_style));
space_builder.SetTextDirection(child_style.Direction());
writing_mode = child_style.GetWritingMode();
@@ -1639,13 +1717,12 @@ NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
// PositionListMarker() requires a first line baseline.
if (container_builder_.UnpositionedListMarker()) {
space_builder.AddBaselineRequest(
- {NGBaselineAlgorithmType::kFirstLine,
- IsHorizontalWritingMode(constraint_space_.GetWritingMode())
- ? kAlphabeticBaseline
- : kIdeographicBaseline});
+ {NGBaselineAlgorithmType::kFirstLine, Style().GetFontBaseline()});
}
}
space_builder.SetClearanceOffset(clearance_offset);
+ if (child_data.force_clearance)
+ space_builder.SetShouldForceClearance();
LayoutUnit space_available;
if (ConstraintSpace().HasBlockFragmentation()) {
@@ -1668,7 +1745,6 @@ NGBlockLayoutAlgorithm::CreateConstraintSpaceForChild(
space_builder.SetFragmentainerSpaceAtBfcStart(space_available);
space_builder.SetFragmentationType(
ConstraintSpace().BlockFragmentationType());
-
return space_builder.ToConstraintSpace(writing_mode);
}
@@ -1734,20 +1810,59 @@ void NGBlockLayoutAlgorithm::PropagateBaselinesFromChildren() {
}
}
-bool NGBlockLayoutAlgorithm::MaybeUpdateFragmentBfcOffset(
+bool NGBlockLayoutAlgorithm::ResolveBfcOffset(
+ NGPreviousInflowPosition* previous_inflow_position,
LayoutUnit bfc_block_offset) {
- if (container_builder_.BfcOffset())
- return false;
+ if (container_builder_.BfcOffset()) {
+ DCHECK(unpositioned_floats_.IsEmpty());
+ return true;
+ }
NGBfcOffset bfc_offset(ConstraintSpace().BfcOffset().line_offset,
bfc_block_offset);
- if (AdjustToClearance(ConstraintSpace().ClearanceOffset(), &bfc_offset))
+ if (ApplyClearance(ConstraintSpace(), &bfc_offset.block_offset))
container_builder_.SetIsPushedByFloats();
container_builder_.SetBfcOffset(bfc_offset);
+ container_builder_.ResetAdjoiningFloatTypes();
+
+ if (NeedsAbortOnBfcOffsetChange())
+ return false;
+
+ // If our BFC offset was updated, we may have been affected by clearance
+ // ourselves. We need to adjust the origin point to accomodate this.
+ bfc_block_offset = bfc_offset.block_offset;
+
+ PositionPendingFloats(bfc_block_offset);
+
+ // Reset the previous inflow position. Clear the margin strut and set the
+ // offset to our block-start border edge.
+ //
+ // We'll now end up at the block-start border edge. If the BFC offset was
+ // resolved due to a block-start border or padding, that must be added by the
+ // caller, for subsequent layout to continue at the right position. Whether we
+ // need to add border+padding or not isn't something we should determine here,
+ // so it must be dealt with as part of initializing the layout algorithm.
+ previous_inflow_position->bfc_block_offset = bfc_block_offset;
+ previous_inflow_position->logical_block_offset = LayoutUnit();
+ previous_inflow_position->margin_strut = NGMarginStrut();
return true;
}
+bool NGBlockLayoutAlgorithm::NeedsAbortOnBfcOffsetChange() const {
+ DCHECK(container_builder_.BfcOffset());
+ if (!abort_when_bfc_offset_updated_)
+ return false;
+ // If no previous BFC offset was set, we need to abort.
+ if (!ConstraintSpace().FloatsBfcOffset())
+ return true;
+ // If the previous BFC offset matches the new one, we can continue. Otherwise,
+ // we need to abort.
+ LayoutUnit old_bfc_block_offset =
+ ConstraintSpace().FloatsBfcOffset()->block_offset;
+ return container_builder_.BfcOffset()->block_offset != old_bfc_block_offset;
+}
+
void NGBlockLayoutAlgorithm::PositionPendingFloats(
LayoutUnit origin_block_offset) {
DCHECK(container_builder_.BfcOffset() || ConstraintSpace().FloatsBfcOffset())
@@ -1860,8 +1975,9 @@ void NGBlockLayoutAlgorithm::PositionOrPropagateListMarker(
return;
container_builder_.SetUnpositionedListMarker(NGUnpositionedListMarker());
}
- if (list_marker.AddToBox(constraint_space_, *layout_result.PhysicalFragment(),
- content_offset, &container_builder_))
+ if (list_marker.AddToBox(constraint_space_, Style().GetFontBaseline(),
+ *layout_result.PhysicalFragment(), content_offset,
+ &container_builder_))
return;
// If the list marker could not be positioned against this child because it
@@ -1877,7 +1993,7 @@ void NGBlockLayoutAlgorithm::PositionListMarkerWithoutLineBoxes() {
// Position the list marker without aligning to line boxes.
LayoutUnit marker_block_size =
container_builder_.UnpositionedListMarker().AddToBoxWithoutLineBoxes(
- constraint_space_, &container_builder_);
+ constraint_space_, Style().GetFontBaseline(), &container_builder_);
container_builder_.SetUnpositionedListMarker(NGUnpositionedListMarker());
// Whether the list marker should affect the block size or not is not
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 4ed60269ff6..8a51fde1456 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
@@ -19,9 +19,15 @@ class NGConstraintSpace;
class NGFragment;
class NGLayoutResult;
-// This struct is used for communicating to a child the position of the
-// previous inflow child.
+// 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.
struct NGPreviousInflowPosition {
+ // Return the BFC offset of the next block-start border edge we'd get if we
+ // commit pending margins.
+ LayoutUnit NextBorderEdge() const {
+ return bfc_block_offset + margin_strut.Sum();
+ }
+
LayoutUnit bfc_block_offset;
LayoutUnit logical_block_offset;
NGMarginStrut margin_strut;
@@ -34,6 +40,7 @@ struct NGInflowChildData {
NGBfcOffset bfc_offset_estimate;
NGMarginStrut margin_strut;
NGBoxStrut margins;
+ bool force_clearance;
};
// A class for general block layout (e.g. a <div> with no special style).
@@ -52,7 +59,10 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
const NGConstraintSpace& space,
NGBlockBreakToken* break_token = nullptr);
- Optional<MinMaxSize> ComputeMinMaxSize(const MinMaxSizeInput&) const override;
+ ~NGBlockLayoutAlgorithm() override;
+
+ base::Optional<MinMaxSize> ComputeMinMaxSize(
+ const MinMaxSizeInput&) const override;
scoped_refptr<NGLayoutResult> Layout() override;
private:
@@ -64,27 +74,24 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
const NGLayoutInputNode child,
const NGInflowChildData& child_data,
const NGLogicalSize child_available_size,
- const WTF::Optional<NGBfcOffset> floats_bfc_offset = WTF::nullopt);
+ const base::Optional<NGBfcOffset> floats_bfc_offset = base::nullopt);
// @return Estimated BFC offset for the "to be layout" child.
NGInflowChildData ComputeChildData(const NGPreviousInflowPosition&,
NGLayoutInputNode,
- const NGBreakToken* child_break_token);
+ const NGBreakToken* child_break_token,
+ bool force_clearance);
NGPreviousInflowPosition ComputeInflowPosition(
const NGPreviousInflowPosition& previous_inflow_position,
const NGLayoutInputNode child,
const NGInflowChildData& child_data,
- const WTF::Optional<NGBfcOffset>& child_bfc_offset,
+ const base::Optional<NGBfcOffset>& child_bfc_offset,
const NGLogicalOffset& logical_offset,
const NGLayoutResult& layout_result,
const NGFragment& fragment,
bool empty_block_affected_by_clearance);
- // Positions the fragment that knows its BFC offset.
- bool PositionWithBfcOffset(const NGBfcOffset& bfc_offset,
- WTF::Optional<NGBfcOffset>* child_bfc_offset);
-
// Position an empty child using the parent BFC offset.
// The fragment doesn't know its offset, but we can still calculate its BFC
// position because the parent fragment's BFC is known.
@@ -96,8 +103,7 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
const NGLayoutInputNode& child,
const NGConstraintSpace& child_space,
const NGInflowChildData& child_data,
- const NGLayoutResult&,
- bool* has_clearance) const;
+ const NGLayoutResult&) const;
void HandleOutOfFlowPositioned(const NGPreviousInflowPosition&, NGBlockNode);
void HandleFloat(const NGPreviousInflowPosition&,
@@ -178,8 +184,29 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
const NGPhysicalFragment*,
LayoutUnit child_offset);
- // Updates the fragment's BFC offset if it's not already set.
- bool MaybeUpdateFragmentBfcOffset(LayoutUnit bfc_block_offset);
+ // If still unresolved, resolve the fragment's BFC offset.
+ //
+ // This includes applying clearance, so the bfc_block_offset passed won't be
+ // the final BFC offset, if it wasn't large enough to get past all relevant
+ // floats. The updated BFC offset can be read out with ContainerBfcOffset().
+ //
+ // In addition to resolving our BFC offset, this will also position pending
+ // floats, and update our in-flow layout state. Returns false if resolving the
+ // BFC offset resulted in needing to abort layout. It will always return true
+ // otherwise. If the BFC offset was already resolved, this method does nothing
+ // (and returns true).
+ bool ResolveBfcOffset(NGPreviousInflowPosition*, LayoutUnit bfc_block_offset);
+
+ // A very common way to resolve the BFC offset is to simply commit the pending
+ // margin, so here's a convenience overload for that.
+ bool ResolveBfcOffset(NGPreviousInflowPosition* previous_inflow_position) {
+ return ResolveBfcOffset(previous_inflow_position,
+ previous_inflow_position->NextBorderEdge());
+ }
+
+ // Return true if the BFC offset has changed and this means that we need to
+ // abort layout.
+ bool NeedsAbortOnBfcOffsetChange() const;
// Positions pending floats starting from {@origin_block_offset}.
void PositionPendingFloats(LayoutUnit origin_block_offset);
@@ -201,7 +228,7 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
NGLayoutInputNode child,
const NGFragment&,
const NGBoxStrut& child_margins,
- const WTF::Optional<NGBfcOffset>& known_fragment_offset);
+ const base::Optional<NGBfcOffset>& known_fragment_offset);
// Computes default content size for HTML and BODY elements in quirks mode.
// Returns NGSizeIndefinite in all other cases.
@@ -231,7 +258,14 @@ class CORE_EXPORT NGBlockLayoutAlgorithm
// Set if we're resuming layout of a node that has already produced fragments.
bool is_resuming_;
- bool abort_when_bfc_resolved_;
+ // Set when we're to abort if the BFC offset gets resolved or updated.
+ // Sometimes we walk past elements (i.e. floats) that depend on the BFC offset
+ // being known (in order to position and lay themselves out properly). When
+ // this happens, and we finally manage to resolve (or update) the BFC offset
+ // at some subsequent element, we need to check if this flag is set, and abort
+ // layout if it is.
+ bool abort_when_bfc_offset_updated_ = false;
+
bool has_processed_first_child_ = false;
std::unique_ptr<NGExclusionSpace> exclusion_space_;
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 7d4e30976bd..fc1e2732a14 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
@@ -31,7 +31,6 @@ class NGBlockLayoutAlgorithmTest : public NGBaseLayoutAlgorithmTest {
protected:
void SetUp() override {
NGBaseLayoutAlgorithmTest::SetUp();
- style_ = ComputedStyle::Create();
}
scoped_refptr<NGPhysicalBoxFragment> RunBlockLayoutAlgorithm(
@@ -67,7 +66,13 @@ class NGBlockLayoutAlgorithmTest : public NGBaseLayoutAlgorithmTest {
return fragment->DumpFragmentTree(flags);
}
- scoped_refptr<ComputedStyle> style_;
+ scoped_refptr<ComputedStyle> MutableStyleForElement(Element* element) {
+ DCHECK(element->GetLayoutObject());
+ scoped_refptr<ComputedStyle> mutable_style =
+ ComputedStyle::Clone(element->GetLayoutObject()->StyleRef());
+ element->GetLayoutObject()->SetStyleInternal(mutable_style);
+ return mutable_style;
+ }
};
TEST_F(NGBlockLayoutAlgorithmTest, FixedSize) {
@@ -383,7 +388,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsCase3) {
scoped_refptr<const NGPhysicalBoxFragment> fragment;
auto run_test = [&](const Length& container_height) {
Element* container = GetDocument().getElementById("container");
- container->MutableComputedStyle()->SetHeight(container_height);
+ MutableStyleForElement(container)->SetHeight(container_height);
container->GetLayoutObject()->SetNeedsLayout("");
std::tie(fragment, std::ignore) = RunBlockLayoutAlgorithmForElement(
GetDocument().getElementsByTagName("html")->item(0));
@@ -435,7 +440,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsCase4) {
scoped_refptr<const NGPhysicalBoxFragment> fragment;
auto run_test = [&](const Length& container_padding_top) {
Element* container = GetDocument().getElementById("container");
- container->MutableComputedStyle()->SetPaddingTop(container_padding_top);
+ MutableStyleForElement(container)->SetPaddingTop(container_padding_top);
container->GetLayoutObject()->SetNeedsLayout("");
std::tie(fragment, std::ignore) = RunBlockLayoutAlgorithmForElement(
GetDocument().getElementsByTagName("html")->item(0));
@@ -722,19 +727,20 @@ TEST_F(NGBlockLayoutAlgorithmTest, CollapsingMarginsEmptyBlockWithClearance) {
const Length& inflow_margin_top) {
// Set the style of the elements we care about.
Element* zero_top = GetDocument().getElementById("zero-top");
- zero_top->MutableComputedStyle()->SetMarginBottom(zero_top_margin_bottom);
+ MutableStyleForElement(zero_top)->SetMarginBottom(zero_top_margin_bottom);
zero_top->GetLayoutObject()->SetNeedsLayout("");
Element* zero_inner = GetDocument().getElementById("zero-inner");
- zero_inner->MutableComputedStyle()->SetMarginTop(zero_inner_margin_top);
- zero_inner->MutableComputedStyle()->SetMarginBottom(
- zero_inner_margin_bottom);
+ scoped_refptr<ComputedStyle> zero_inner_style =
+ MutableStyleForElement(zero_inner);
+ zero_inner_style->SetMarginTop(zero_inner_margin_top);
+ zero_inner_style->SetMarginBottom(zero_inner_margin_bottom);
zero_inner->GetLayoutObject()->SetNeedsLayout("");
Element* zero_element = GetDocument().getElementById("zero");
- zero_element->MutableComputedStyle()->SetMarginBottom(zero_margin_bottom);
+ MutableStyleForElement(zero_element)->SetMarginBottom(zero_margin_bottom);
zero_element->GetLayoutObject()->SetNeedsLayout("");
Element* inflow_element = GetDocument().getElementById("inflow");
- inflow_element->MutableComputedStyle()->SetMarginTop(inflow_margin_top);
+ MutableStyleForElement(inflow_element)->SetMarginTop(inflow_margin_top);
inflow_element->GetLayoutObject()->SetNeedsLayout("");
GetDocument().View()->UpdateAllLifecyclePhases();
@@ -1283,7 +1289,7 @@ TEST_F(NGBlockLayoutAlgorithmTest, PositionFragmentsWithClear) {
scoped_refptr<const NGPhysicalBoxFragment> fragment;
auto run_with_clearance = [&](EClear clear_value) {
Element* el_with_clear = GetDocument().getElementById("clearance");
- el_with_clear->MutableComputedStyle()->SetClear(clear_value);
+ MutableStyleForElement(el_with_clear)->SetClear(clear_value);
el_with_clear->GetLayoutObject()->SetNeedsLayout("");
std::tie(fragment, std::ignore) = RunBlockLayoutAlgorithmForElement(
GetDocument().getElementsByTagName("html")->item(0));
@@ -2127,7 +2133,7 @@ TEST_F(NGBlockLayoutAlgorithmTest,
scoped_refptr<const NGPhysicalBoxFragment> fragment;
auto run_test = [&](const Length& block_width) {
Element* new_fc_block = GetDocument().getElementById("new-fc");
- new_fc_block->MutableComputedStyle()->SetWidth(block_width);
+ MutableStyleForElement(new_fc_block)->SetWidth(block_width);
new_fc_block->GetLayoutObject()->SetNeedsLayout("");
std::tie(fragment, std::ignore) = RunBlockLayoutAlgorithmForElement(
GetDocument().getElementsByTagName("html")->item(0));
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 92ed7e92724..e30210096e9 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
@@ -9,11 +9,8 @@
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_multi_column_flow_thread.h"
#include "third_party/blink/renderer/core/layout/layout_multi_column_set.h"
-#include "third_party/blink/renderer/core/layout/layout_table.h"
#include "third_party/blink/renderer/core/layout/min_max_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_line_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/legacy_layout_tree_walking.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"
@@ -26,8 +23,10 @@
#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/core/layout/ng/ng_layout_result.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_page_layout_algorithm.h"
+#include "third_party/blink/renderer/core/layout/shapes/shape_outside_info.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
@@ -125,6 +124,8 @@ void UpdateLegacyMultiColumnFlowThread(
// handles such cases.
void CopyFragmentDataToLayoutBoxForInlineChildren(
const NGPhysicalContainerFragment& container,
+ LayoutUnit initial_container_width,
+ bool initial_container_is_flipped,
NGPhysicalOffset offset = {}) {
for (const auto& child : container.Children()) {
if (child->IsContainer()) {
@@ -135,7 +136,13 @@ void CopyFragmentDataToLayoutBoxForInlineChildren(
LayoutObject* layout_object = child->GetLayoutObject();
if (layout_object && layout_object->IsBox()) {
LayoutBox& layout_box = ToLayoutBox(*layout_object);
- layout_box.SetLocation(child_offset.ToLayoutPoint());
+ NGPhysicalOffset maybe_flipped_offset = child_offset;
+ if (initial_container_is_flipped) {
+ maybe_flipped_offset.left = initial_container_width -
+ child->Size().width -
+ maybe_flipped_offset.left;
+ }
+ layout_box.SetLocation(maybe_flipped_offset.ToLayoutPoint());
}
// The Location() of inline LayoutObject is relative to the
@@ -144,7 +151,8 @@ void CopyFragmentDataToLayoutBoxForInlineChildren(
// to its descendants in this case.
if (!child->IsBlockLayoutRoot()) {
CopyFragmentDataToLayoutBoxForInlineChildren(
- ToNGPhysicalContainerFragment(*child), child_offset);
+ ToNGPhysicalContainerFragment(*child), initial_container_width,
+ initial_container_is_flipped, child_offset);
}
}
}
@@ -169,9 +177,30 @@ scoped_refptr<NGLayoutResult> NGBlockNode::Layout(
layout_result = ToLayoutBlockFlow(box_)->CachedLayoutResult(
constraint_space, break_token);
if (layout_result) {
- block_flow->ClearPaintFragment();
- if (first_child && first_child.IsInline())
- block_flow->SetPaintFragment(layout_result->PhysicalFragment());
+ // TODO(layoutng): Figure out why these two call can't be inside the
+ // !constraint_space.IsIntermediateLayout() block below.
+ UpdateShapeOutsideInfoIfNeeded(
+ constraint_space.PercentageResolutionSize().inline_size);
+ // We may need paint invalidation even if we can reuse layout, as our
+ // paint offset/visual rect may have changed due to relative
+ // positioning changes. Otherwise we fail fast/css/
+ // fast/css/relative-positioned-block-with-inline-ancestor-and-parent
+ // -dynamic.html
+ // TODO(layoutng): See if we can optimize this. When we natively
+ // support relative positioning in NG we can probably remove this,
+ box_->SetMayNeedPaintInvalidation();
+
+ // We have to re-set the cached result here, because it is used for
+ // LayoutNGMixin::CurrentFragment and therefore has to be up-to-date.
+ // In particular, that fragment would have an incorrect offset if we
+ // don't re-set the result here.
+ ToLayoutBlockFlow(box_)->SetCachedLayoutResult(
+ constraint_space, break_token, layout_result);
+ if (!constraint_space.IsIntermediateLayout()) {
+ block_flow->ClearPaintFragment();
+ if (first_child && first_child.IsInline())
+ block_flow->SetPaintFragment(layout_result->PhysicalFragment());
+ }
return layout_result;
}
}
@@ -181,16 +210,21 @@ scoped_refptr<NGLayoutResult> NGBlockNode::Layout(
if (block_flow) {
block_flow->SetCachedLayoutResult(constraint_space, break_token,
layout_result);
- block_flow->ClearPaintFragment();
+ if (layout_result->Status() == NGLayoutResult::kSuccess &&
+ !constraint_space.IsIntermediateLayout())
+ block_flow->ClearPaintFragment();
}
- if (layout_result->Status() == NGLayoutResult::kSuccess &&
- layout_result->UnpositionedFloats().IsEmpty()) {
+ if (IsBlockLayoutComplete(constraint_space, *layout_result)) {
DCHECK(layout_result->PhysicalFragment());
if (block_flow && first_child && first_child.IsInline()) {
- CopyFragmentDataToLayoutBoxForInlineChildren(
- ToNGPhysicalBoxFragment(*layout_result->PhysicalFragment()));
+ NGBoxStrut scrollbars = GetScrollbarSizes();
+ CopyFragmentDataToLayoutBoxForInlineChildren(
+ ToNGPhysicalBoxFragment(*layout_result->PhysicalFragment()),
+ layout_result->PhysicalFragment()->Size().width -
+ scrollbars.block_start,
+ Style().IsFlippedBlocksWritingMode());
block_flow->SetPaintFragment(layout_result->PhysicalFragment());
}
@@ -204,6 +238,7 @@ scoped_refptr<NGLayoutResult> NGBlockNode::Layout(
}
MinMaxSize NGBlockNode::ComputeMinMaxSize(
+ WritingMode container_writing_mode,
const MinMaxSizeInput& input,
const NGConstraintSpace* constraint_space) {
MinMaxSize sizes;
@@ -224,21 +259,35 @@ MinMaxSize NGBlockNode::ComputeMinMaxSize(
NGConstraintSpaceBuilder(Style().GetWritingMode(),
InitialContainingBlockSize())
.SetTextDirection(Style().Direction())
+ .SetIsIntermediateLayout(true)
+ .SetFloatsBfcOffset(NGBfcOffset())
.ToConstraintSpace(Style().GetWritingMode());
if (!constraint_space)
constraint_space = zero_constraint_space.get();
- // TODO(cbiesinger): For orthogonal children, we need to always synthesize.
+ if (!IsParallelWritingMode(container_writing_mode,
+ Style().GetWritingMode())) {
+ scoped_refptr<NGLayoutResult> layout_result = Layout(*constraint_space);
+ DCHECK_EQ(layout_result->Status(), NGLayoutResult::kSuccess);
+ NGBoxFragment fragment(
+ container_writing_mode,
+ ToNGPhysicalBoxFragment(*layout_result->PhysicalFragment()));
+ sizes.min_size = sizes.max_size = fragment.Size().inline_size;
+ return sizes;
+ }
+
+ // TODO(layout-ng): We need to make sure to use the right algorithm
NGBlockLayoutAlgorithm minmax_algorithm(*this, *constraint_space);
- Optional<MinMaxSize> maybe_sizes = minmax_algorithm.ComputeMinMaxSize(input);
+ base::Optional<MinMaxSize> maybe_sizes =
+ minmax_algorithm.ComputeMinMaxSize(input);
if (maybe_sizes.has_value())
return *maybe_sizes;
// Have to synthesize this value.
scoped_refptr<NGLayoutResult> layout_result = Layout(*zero_constraint_space);
NGBoxFragment min_fragment(
- Style().GetWritingMode(),
+ container_writing_mode,
ToNGPhysicalBoxFragment(*layout_result->PhysicalFragment()));
sizes.min_size = min_fragment.Size().inline_size;
@@ -249,11 +298,12 @@ MinMaxSize NGBlockNode::ComputeMinMaxSize(
.SetTextDirection(Style().Direction())
.SetAvailableSize({LayoutUnit::Max(), LayoutUnit()})
.SetPercentageResolutionSize({LayoutUnit(), LayoutUnit()})
+ .SetIsIntermediateLayout(true)
.ToConstraintSpace(Style().GetWritingMode());
layout_result = Layout(*infinite_constraint_space);
NGBoxFragment max_fragment(
- Style().GetWritingMode(),
+ container_writing_mode,
ToNGPhysicalBoxFragment(*layout_result->PhysicalFragment()));
sizes.max_size = max_fragment.Size().inline_size;
return sizes;
@@ -261,18 +311,17 @@ MinMaxSize NGBlockNode::ComputeMinMaxSize(
NGBoxStrut NGBlockNode::GetScrollbarSizes() const {
NGPhysicalBoxStrut sizes;
- const ComputedStyle* style = GetLayoutObject()->Style();
- if (!style->IsOverflowVisible()) {
- const LayoutBox* box = ToLayoutBox(GetLayoutObject());
- LayoutUnit vertical = LayoutUnit(box->VerticalScrollbarWidth());
- LayoutUnit horizontal = LayoutUnit(box->HorizontalScrollbarHeight());
+ const ComputedStyle& style = box_->StyleRef();
+ if (!style.IsOverflowVisible()) {
+ LayoutUnit vertical = LayoutUnit(box_->VerticalScrollbarWidth());
+ LayoutUnit horizontal = LayoutUnit(box_->HorizontalScrollbarHeight());
sizes.bottom = horizontal;
- if (box->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
+ if (box_->ShouldPlaceBlockDirectionScrollbarOnLogicalLeft())
sizes.left = vertical;
else
sizes.right = vertical;
}
- return sizes.ConvertToLogical(style->GetWritingMode(), style->Direction());
+ return sizes.ConvertToLogical(style.GetWritingMode(), style.Direction());
}
NGLayoutInputNode NGBlockNode::NextSibling() const {
@@ -285,21 +334,23 @@ NGLayoutInputNode NGBlockNode::NextSibling() const {
}
NGLayoutInputNode NGBlockNode::FirstChild() const {
- auto* block = ToLayoutBlockFlow(box_);
+ auto* block = ToLayoutBlock(box_);
auto* child = GetLayoutObjectForFirstChildNode(block);
if (!child)
return nullptr;
if (AreNGBlockFlowChildrenInline(block))
- return NGInlineNode(block);
+ return NGInlineNode(ToLayoutBlockFlow(block));
return NGBlockNode(ToLayoutBox(child));
}
bool NGBlockNode::CanUseNewLayout(const LayoutBox& box) {
DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled());
+ if (box.StyleRef().ForceLegacyLayout())
+ return false;
// When the style has |ForceLegacyLayout|, it's usually not LayoutNGMixin,
// but anonymous block can be.
- return box.IsLayoutNGMixin() && !box.StyleRef().ForceLegacyLayout();
+ return box.IsLayoutNGMixin() || box.IsLayoutNGFlexibleBox();
}
bool NGBlockNode::CanUseNewLayout() const {
@@ -315,6 +366,9 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
const NGConstraintSpace& constraint_space,
const NGLayoutResult& layout_result) {
DCHECK(layout_result.PhysicalFragment());
+ if (constraint_space.IsIntermediateLayout())
+ return;
+
const NGPhysicalBoxFragment& physical_fragment =
ToNGPhysicalBoxFragment(*layout_result.PhysicalFragment());
@@ -338,9 +392,12 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
}
logical_height += fragment_logical_size.block_size;
intrinsic_content_logical_height += layout_result.IntrinsicBlockSize();
- NGBoxStrut border_scrollbar_padding =
- ComputeBorders(constraint_space, Style()) +
- ComputePadding(constraint_space, Style()) + GetScrollbarSizes();
+
+ NGBoxStrut borders = ComputeBorders(constraint_space, Style());
+ NGBoxStrut scrollbars = GetScrollbarSizes();
+ NGBoxStrut padding = ComputePadding(constraint_space, Style());
+ NGBoxStrut border_scrollbar_padding = borders + scrollbars + padding;
+
if (IsLastFragment(physical_fragment))
intrinsic_content_logical_height -= border_scrollbar_padding.BlockSum();
box_->SetLogicalHeight(logical_height);
@@ -382,14 +439,17 @@ void NGBlockNode::CopyFragmentDataToLayoutBox(
}
// |ComputeOverflow()| below calls |AddOverflowFromChildren()|, which
- // computes visual overflow from |RootInlineBox| if |ChildrenInline()|.
- block->ComputeOverflow(intrinsic_block_size -
- border_scrollbar_padding.block_end);
+ // computes visual overflow from |RootInlineBox| if |ChildrenInline()|
+ block->ComputeOverflow(intrinsic_block_size - borders.block_end -
+ scrollbars.BlockSum());
}
box_->UpdateAfterLayout();
box_->ClearNeedsLayout();
+ UpdateShapeOutsideInfoIfNeeded(
+ constraint_space.PercentageResolutionSize().inline_size);
+
if (box_->IsLayoutBlockFlow()) {
LayoutBlockFlow* block_flow = ToLayoutBlockFlow(box_);
block_flow->UpdateIsSelfCollapsing();
@@ -463,7 +523,9 @@ void NGBlockNode::CopyChildFragmentPosition(
// LegacyLayout flips vertical-rl horizontal coordinates before paint.
// NGLayout flips X location for LegacyLayout compatibility.
if (containing_block->StyleRef().IsFlippedBlocksWritingMode()) {
- LayoutUnit container_width = containing_block->Size().Width();
+ NGBoxStrut scrollbars = GetScrollbarSizes();
+ LayoutUnit container_width =
+ containing_block->Size().Width() - scrollbars.block_start;
layout_box->SetX(container_width - fragment.Offset().left -
additional_offset.left - fragment.Size().width);
} else {
@@ -487,6 +549,7 @@ void NGBlockNode::CopyChildFragmentPosition(
scoped_refptr<NGLayoutResult> NGBlockNode::LayoutAtomicInline(
const NGConstraintSpace& parent_constraint_space,
+ FontBaseline baseline_type,
bool use_first_line_style) {
NGConstraintSpaceBuilder space_builder(parent_constraint_space);
space_builder.SetUseFirstLineStyle(use_first_line_style);
@@ -495,10 +558,7 @@ scoped_refptr<NGLayoutResult> NGBlockNode::LayoutAtomicInline(
// would synthesize box-baseline.
if (NGBaseline::ShouldPropagateBaselines(ToLayoutBox(GetLayoutObject()))) {
space_builder.AddBaselineRequest(
- {NGBaselineAlgorithmType::kAtomicInline,
- IsHorizontalWritingMode(parent_constraint_space.GetWritingMode())
- ? FontBaseline::kAlphabeticBaseline
- : FontBaseline::kIdeographicBaseline});
+ {NGBaselineAlgorithmType::kAtomicInline, baseline_type});
}
const ComputedStyle& style = Style();
@@ -541,18 +601,11 @@ scoped_refptr<NGLayoutResult> NGBlockNode::RunOldLayout(
box_->SetOverrideContainingBlockContentLogicalHeight(inline_size);
}
- // TODO(layout-ng): Does this handle scrollbars correctly?
if (constraint_space.IsFixedSizeInline()) {
- box_->SetOverrideLogicalContentWidth(
- (constraint_space.AvailableSize().inline_size -
- box_->BorderAndPaddingLogicalWidth())
- .ClampNegativeToZero());
+ box_->SetOverrideLogicalWidth(constraint_space.AvailableSize().inline_size);
}
if (constraint_space.IsFixedSizeBlock()) {
- box_->SetOverrideLogicalContentHeight(
- (constraint_space.AvailableSize().block_size -
- box_->BorderAndPaddingLogicalHeight())
- .ClampNegativeToZero());
+ box_->SetOverrideLogicalHeight(constraint_space.AvailableSize().block_size);
}
if (box_->IsLayoutNGMixin() && box_->NeedsLayout()) {
@@ -577,6 +630,8 @@ scoped_refptr<NGLayoutResult> NGBlockNode::RunOldLayout(
std::make_unique<NGExclusionSpace>(constraint_space.ExclusionSpace()));
CopyBaselinesFromOldLayout(constraint_space, &builder);
+ UpdateShapeOutsideInfoIfNeeded(
+ constraint_space.PercentageResolutionSize().inline_size);
return builder.ToBoxFragment();
}
@@ -588,44 +643,74 @@ void NGBlockNode::CopyBaselinesFromOldLayout(
if (requests.IsEmpty())
return;
+ if (UNLIKELY(constraint_space.GetWritingMode() != Style().GetWritingMode()))
+ return;
+
for (const auto& request : requests) {
switch (request.algorithm_type) {
- case NGBaselineAlgorithmType::kAtomicInline:
- AddAtomicInlineBaselineFromOldLayout(
- request, constraint_space.UseFirstLineStyle(), builder);
+ case NGBaselineAlgorithmType::kAtomicInline: {
+ LayoutUnit position =
+ AtomicInlineBaselineFromOldLayout(request, constraint_space);
+ if (position != -1)
+ builder->AddBaseline(request, position);
break;
+ }
case NGBaselineAlgorithmType::kFirstLine: {
LayoutUnit position = box_->FirstLineBoxBaseline();
- if (position != -1) {
+ if (position != -1)
builder->AddBaseline(request, position);
- }
break;
}
}
}
}
-void NGBlockNode::AddAtomicInlineBaselineFromOldLayout(
+LayoutUnit NGBlockNode::AtomicInlineBaselineFromOldLayout(
const NGBaselineRequest& request,
- bool is_first_line,
- NGFragmentBuilder* builder) {
- // Block-level boxes do not have atomic inline baseline.
- // This includes form controls when 'display:block' is applied.
- if (box_->IsLayoutBlock() && !box_->IsInline())
- return;
+ const NGConstraintSpace& constraint_space) {
+ LineDirectionMode line_direction = box_->IsHorizontalWritingMode()
+ ? LineDirectionMode::kHorizontalLine
+ : LineDirectionMode::kVerticalLine;
+
+ // If this is an inline box, use |BaselinePosition()|. Some LayoutObject
+ // classes override it assuming inline layout calls |BaselinePosition()|.
+ if (box_->IsInline()) {
+ LayoutUnit position = LayoutUnit(box_->BaselinePosition(
+ request.baseline_type, constraint_space.UseFirstLineStyle(),
+ line_direction, kPositionOnContainingLine));
+
+ // BaselinePosition() uses margin edge for atomic inlines. Subtract
+ // margin-over so that the position is relative to the border box.
+ if (box_->IsAtomicInlineLevel())
+ position -= box_->MarginOver();
+
+ return position;
+ }
- LineDirectionMode line_direction =
- IsHorizontalWritingMode(builder->GetWritingMode())
- ? LineDirectionMode::kHorizontalLine
- : LineDirectionMode::kVerticalLine;
- LayoutUnit position = LayoutUnit(box_->BaselinePosition(
- request.baseline_type, is_first_line, line_direction));
+ // If this is a block box, use |InlineBlockBaseline()|. When an inline block
+ // has block children, their inline block baselines need to be propagated.
+ return box_->InlineBlockBaseline(line_direction);
+}
- // BaselinePosition() uses margin edge for atomic inlines.
- if (box_->IsAtomicInlineLevel())
- position -= box_->MarginOver();
+// Floats can optionally have a shape area, specifed by "shape-outside". The
+// current shape machinery requires setting the size of the float after layout
+// in the parents writing mode.
+void NGBlockNode::UpdateShapeOutsideInfoIfNeeded(
+ LayoutUnit percentage_resolution_inline_size) {
+ if (!box_->IsFloating() || !box_->GetShapeOutsideInfo())
+ return;
- builder->AddBaseline(request, position);
+ // TODO(ikilpatrick): Ideally this should be moved to a NGLayoutResult
+ // computing the shape area. There may be an issue with the new fragmentation
+ // model and computing the correct sizes of shapes.
+ ShapeOutsideInfo* shape_outside = box_->GetShapeOutsideInfo();
+ LayoutBlock* containing_block = box_->ContainingBlock();
+ shape_outside->SetReferenceBoxLogicalSize(
+ containing_block->IsHorizontalWritingMode()
+ ? box_->Size()
+ : box_->Size().TransposedSize());
+ shape_outside->SetPercentageResolutionInlineSize(
+ percentage_resolution_inline_size);
}
void NGBlockNode::UseOldOutOfFlowPositioning() {
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 05f50c3cbfa..7120a177c1b 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
@@ -8,6 +8,7 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_input_node.h"
+#include "third_party/blink/renderer/platform/fonts/font_baseline.h"
namespace blink {
@@ -46,7 +47,8 @@ class CORE_EXPORT NGBlockNode final : public NGLayoutInputNode {
// min/max calculation (e.g. the node that will undergo shrink-to-fit). This
// constraint space will not be passed on to children. If no constraint space
// is specified, a zero-sized one will be used.
- MinMaxSize ComputeMinMaxSize(const MinMaxSizeInput&,
+ MinMaxSize ComputeMinMaxSize(WritingMode container_writing_mode,
+ const MinMaxSizeInput&,
const NGConstraintSpace* = nullptr);
NGBoxStrut GetScrollbarSizes() const;
@@ -55,6 +57,7 @@ class CORE_EXPORT NGBlockNode final : public NGLayoutInputNode {
// Layout an atomic inline; e.g., inline block.
scoped_refptr<NGLayoutResult> LayoutAtomicInline(const NGConstraintSpace&,
+ FontBaseline,
bool use_first_line_style);
// Runs layout on the underlying LayoutObject and creates a fragment for the
@@ -89,9 +92,11 @@ class CORE_EXPORT NGBlockNode final : public NGLayoutInputNode {
const NGPhysicalOffset& additional_offset = NGPhysicalOffset());
void CopyBaselinesFromOldLayout(const NGConstraintSpace&, NGFragmentBuilder*);
- void AddAtomicInlineBaselineFromOldLayout(const NGBaselineRequest&,
- bool,
- NGFragmentBuilder*);
+ LayoutUnit AtomicInlineBaselineFromOldLayout(const NGBaselineRequest&,
+ const NGConstraintSpace&);
+
+ void UpdateShapeOutsideInfoIfNeeded(
+ LayoutUnit percentage_resolution_inline_size);
};
DEFINE_TYPE_CASTS(NGBlockNode,
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 95c934ddc10..202a5744538 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
@@ -159,7 +159,8 @@ TEST_F(NGBlockNodeForTest, MinAndMaxContent) {
const int kWidth = 30;
NGBlockNode box(ToLayoutBox(GetLayoutObjectByElementId("box")));
- MinMaxSize sizes = box.ComputeMinMaxSize(MinMaxSizeInput());
+ MinMaxSize sizes =
+ box.ComputeMinMaxSize(WritingMode::kHorizontalTb, MinMaxSizeInput());
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 3ee4744c3ce..b5a5bf1bb27 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
@@ -6,7 +6,6 @@
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
-#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_line_height_metrics.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
@@ -14,29 +13,36 @@
namespace blink {
NGLineHeightMetrics NGBoxFragment::BaselineMetricsWithoutSynthesize(
- const NGBaselineRequest& request,
- const NGConstraintSpace& constraint_space) const {
+ const NGBaselineRequest& request) const {
+ // 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 = ToNGPhysicalBoxFragment(physical_fragment_);
- bool is_parallel_writing_mode =
- IsParallelWritingMode(constraint_space.GetWritingMode(),
- physical_fragment.Style().GetWritingMode());
- if (is_parallel_writing_mode) {
- // Find the baseline from the computed results.
- if (const NGBaseline* baseline = physical_fragment.Baseline(request)) {
- LayoutUnit ascent = baseline->offset;
- LayoutUnit descent = BlockSize() - ascent;
+ DCHECK(physical_fragment_.GetLayoutObject());
+ const LayoutBox& layout_box =
+ ToLayoutBox(*physical_fragment_.GetLayoutObject());
+ const ComputedStyle& style = physical_fragment.Style();
+ if (style.HasAppearance() &&
+ !LayoutTheme::GetTheme().IsControlContainer(style.Appearance())) {
+ return NGLineHeightMetrics(
+ BlockSize() + layout_box.MarginOver() +
+ LayoutTheme::GetTheme().BaselinePositionAdjustment(style),
+ layout_box.MarginUnder());
+ }
- // 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
- LayoutBox* layout_box = ToLayoutBox(physical_fragment_.GetLayoutObject());
- if (layout_box->IsAtomicInlineLevel()) {
- ascent += layout_box->MarginOver();
- descent += layout_box->MarginUnder();
- }
+ // Check if we have a propagated baseline.
+ if (const NGBaseline* baseline = physical_fragment.Baseline(request)) {
+ LayoutUnit ascent = baseline->offset;
+ LayoutUnit descent = BlockSize() - ascent;
- return NGLineHeightMetrics(ascent, descent);
+ // 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();
}
+
+ return NGLineHeightMetrics(ascent, descent);
}
return NGLineHeightMetrics();
@@ -45,36 +51,31 @@ NGLineHeightMetrics NGBoxFragment::BaselineMetricsWithoutSynthesize(
NGLineHeightMetrics NGBoxFragment::BaselineMetrics(
const NGBaselineRequest& request,
const NGConstraintSpace& constraint_space) const {
- NGLineHeightMetrics metrics =
- BaselineMetricsWithoutSynthesize(request, constraint_space);
- if (!metrics.IsEmpty())
- return metrics;
+ // 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;
+ }
// 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();
- const auto& physical_fragment = ToNGPhysicalBoxFragment(physical_fragment_);
- const ComputedStyle& style = physical_fragment.Style();
- LayoutBox* layout_box = ToLayoutBox(physical_fragment_.GetLayoutObject());
- if (style.HasAppearance() &&
- !LayoutTheme::GetTheme().IsControlContainer(style.Appearance())) {
- return NGLineHeightMetrics(
- block_size + layout_box->MarginOver() +
- LayoutTheme::GetTheme().BaselinePositionAdjustment(style),
- layout_box->MarginUnder());
- }
-
// If atomic inline, use the margin box. See above.
- if (layout_box->IsAtomicInlineLevel()) {
+ const auto& physical_fragment = ToNGPhysicalBoxFragment(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();
+ block_size += layout_box.MarginLogicalHeight();
else
- block_size += layout_box->MarginLogicalWidth();
+ block_size += layout_box.MarginLogicalWidth();
}
if (request.baseline_type == kAlphabeticBaseline)
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 3f3b3dbe9b4..93c08fc9c10 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
@@ -12,7 +12,6 @@
namespace blink {
-class NGPhysicalBoxFragment;
struct NGBaselineRequest;
struct NGLineHeightMetrics;
@@ -31,8 +30,7 @@ class CORE_EXPORT NGBoxFragment final : public NGFragment {
// not have any baselines, while the other version synthesize the baseline
// from the box.
NGLineHeightMetrics BaselineMetricsWithoutSynthesize(
- const NGBaselineRequest&,
- const NGConstraintSpace&) const;
+ const NGBaselineRequest&) const;
NGLineHeightMetrics BaselineMetrics(const NGBaselineRequest&,
const NGConstraintSpace&) const;
};
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 4c260973cf0..2f25a62eb2b 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
@@ -5,6 +5,7 @@
#include "third_party/blink/renderer/core/layout/ng/ng_column_layout_algorithm.h"
#include <algorithm>
+#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.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"
@@ -12,6 +13,7 @@
#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/style/computed_style.h"
namespace blink {
@@ -44,26 +46,20 @@ LayoutUnit ConstrainColumnBlockSize(LayoutUnit size,
LayoutUnit extra = border_scrollbar_padding.BlockSum();
size += extra;
- Optional<LayoutUnit> max_length;
const ComputedStyle& style = node.Style();
- Length logical_max_height = style.LogicalMaxHeight();
- if (!logical_max_height.IsMaxSizeNone()) {
- max_length = ResolveBlockLength(space, style, logical_max_height, size,
- LengthResolveType::kMaxSize);
- }
+ LayoutUnit max = ResolveBlockLength(space, style, style.LogicalMaxHeight(),
+ size, LengthResolveType::kMaxSize,
+ LengthResolvePhase::kLayout);
LayoutUnit extent = ResolveBlockLength(space, style, style.LogicalHeight(),
- size, LengthResolveType::kContentSize);
+ size, LengthResolveType::kContentSize,
+ LengthResolvePhase::kLayout);
if (extent != NGSizeIndefinite) {
// A specified height/width will just constrain the maximum length.
- if (max_length.has_value())
- max_length = std::min(max_length.value(), extent);
- else
- max_length = extent;
+ max = std::min(max, extent);
}
// Constrain and convert the value back to content-box.
- if (max_length.has_value())
- size = std::min(size, max_length.value());
+ size = std::min(size, max);
return size - extra;
}
@@ -75,7 +71,7 @@ NGColumnLayoutAlgorithm::NGColumnLayoutAlgorithm(NGBlockNode node,
: NGLayoutAlgorithm(node, space, ToNGBlockBreakToken(break_token)) {}
scoped_refptr<NGLayoutResult> NGColumnLayoutAlgorithm::Layout() {
- Optional<MinMaxSize> min_max_size;
+ base::Optional<MinMaxSize> min_max_size;
if (NeedMinMaxSize(ConstraintSpace(), Style()))
min_max_size = ComputeMinMaxSize(MinMaxSizeInput());
NGBoxStrut border_scrollbar_padding =
@@ -193,11 +189,11 @@ scoped_refptr<NGLayoutResult> NGColumnLayoutAlgorithm::Layout() {
return container_builder_.ToBoxFragment();
}
-Optional<MinMaxSize> NGColumnLayoutAlgorithm::ComputeMinMaxSize(
+base::Optional<MinMaxSize> NGColumnLayoutAlgorithm::ComputeMinMaxSize(
const MinMaxSizeInput& input) const {
// First calculate the min/max sizes of columns.
NGBlockLayoutAlgorithm algorithm(Node(), ConstraintSpace());
- Optional<MinMaxSize> min_max_sizes = algorithm.ComputeMinMaxSize(input);
+ base::Optional<MinMaxSize> min_max_sizes = algorithm.ComputeMinMaxSize(input);
DCHECK(min_max_sizes.has_value());
MinMaxSize sizes = min_max_sizes.value();
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 1c07e5e99ef..19262a4bc7d 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
@@ -5,7 +5,6 @@
#ifndef NGColumnLayoutAlgorithm_h
#define NGColumnLayoutAlgorithm_h
-#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_algorithm.h"
@@ -15,6 +14,7 @@ class NGBlockNode;
class NGBlockBreakToken;
class NGBreakToken;
class NGConstraintSpace;
+struct NGLogicalSize;
class CORE_EXPORT NGColumnLayoutAlgorithm
: public NGLayoutAlgorithm<NGBlockNode,
@@ -27,7 +27,8 @@ class CORE_EXPORT NGColumnLayoutAlgorithm
scoped_refptr<NGLayoutResult> Layout() override;
- Optional<MinMaxSize> ComputeMinMaxSize(const MinMaxSizeInput&) const override;
+ base::Optional<MinMaxSize> ComputeMinMaxSize(
+ const MinMaxSizeInput&) const override;
private:
NGLogicalSize CalculateColumnSize(const NGLogicalSize& content_box_size);
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 99bdc8955f9..5d5f59ec473 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
@@ -7,6 +7,7 @@
#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_column_layout_algorithm.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
namespace blink {
namespace {
@@ -1971,13 +1972,15 @@ TEST_F(NGColumnLayoutAlgorithmTest, MinMax) {
ASSERT_TRUE(layout_object);
ASSERT_TRUE(layout_object->IsBox());
NGBlockNode node = NGBlockNode(ToLayoutBox(layout_object));
- ComputedStyle* style = layout_object->MutableStyle();
+ scoped_refptr<ComputedStyle> style =
+ ComputedStyle::Clone(layout_object->StyleRef());
+ layout_object->SetStyle(style);
scoped_refptr<NGConstraintSpace> space =
ConstructBlockLayoutTestConstraintSpace(
WritingMode::kHorizontalTb, TextDirection::kLtr,
NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite));
NGColumnLayoutAlgorithm algorithm(node, *space.get());
- Optional<MinMaxSize> size;
+ base::Optional<MinMaxSize> size;
MinMaxSizeInput zero_input;
// Both column-count and column-width set.
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 6448236c189..e6c27f43071 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
@@ -8,25 +8,13 @@
#include <memory>
#include "third_party/blink/renderer/core/layout/layout_block.h"
+#include "third_party/blink/renderer/core/layout/layout_flexible_box.h"
#include "third_party/blink/renderer/core/layout/layout_view.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"
namespace blink {
-namespace {
-
-bool ShouldComputeBaseline(const LayoutBox& box) {
- if (box.IsLayoutBlock() &&
- ToLayoutBlock(box).UseLogicalBottomMarginEdgeForInlineBlockBaseline())
- return false;
- if (box.IsWritingModeRoot())
- return false;
- return true;
-}
-
-} // namespace
-
NGConstraintSpace::NGConstraintSpace(
WritingMode writing_mode,
bool is_orthogonal_writing_mode_root,
@@ -39,20 +27,21 @@ NGConstraintSpace::NGConstraintSpace(
LayoutUnit fragmentainer_space_at_bfc_start,
bool is_fixed_size_inline,
bool is_fixed_size_block,
+ bool fixed_size_block_is_definite,
bool is_shrink_to_fit,
- bool is_inline_direction_triggers_scrollbar,
- bool is_block_direction_triggers_scrollbar,
+ bool is_intermediate_layout,
NGFragmentationType block_direction_fragmentation_type,
bool separate_leading_fragmentainer_margins,
bool is_new_fc,
bool is_anonymous,
bool use_first_line_style,
+ bool should_force_clearance,
+ NGFloatTypes adjoining_floats,
const NGMarginStrut& margin_strut,
const NGBfcOffset& bfc_offset,
- const WTF::Optional<NGBfcOffset>& floats_bfc_offset,
+ const base::Optional<NGBfcOffset>& floats_bfc_offset,
const NGExclusionSpace& exclusion_space,
- Vector<scoped_refptr<NGUnpositionedFloat>>& unpositioned_floats,
- const WTF::Optional<LayoutUnit>& clearance_offset,
+ LayoutUnit clearance_offset,
Vector<NGBaselineRequest>& baseline_requests)
: available_size_(available_size),
percentage_resolution_size_(percentage_resolution_size),
@@ -63,17 +52,17 @@ NGConstraintSpace::NGConstraintSpace(
fragmentainer_space_at_bfc_start_(fragmentainer_space_at_bfc_start),
is_fixed_size_inline_(is_fixed_size_inline),
is_fixed_size_block_(is_fixed_size_block),
+ fixed_size_block_is_definite_(fixed_size_block_is_definite),
is_shrink_to_fit_(is_shrink_to_fit),
- is_inline_direction_triggers_scrollbar_(
- is_inline_direction_triggers_scrollbar),
- is_block_direction_triggers_scrollbar_(
- is_block_direction_triggers_scrollbar),
+ is_intermediate_layout_(is_intermediate_layout),
block_direction_fragmentation_type_(block_direction_fragmentation_type),
separate_leading_fragmentainer_margins_(
separate_leading_fragmentainer_margins),
is_new_fc_(is_new_fc),
is_anonymous_(is_anonymous),
use_first_line_style_(use_first_line_style),
+ should_force_clearance_(should_force_clearance),
+ adjoining_floats_(adjoining_floats),
writing_mode_(static_cast<unsigned>(writing_mode)),
is_orthogonal_writing_mode_root_(is_orthogonal_writing_mode_root),
direction_(static_cast<unsigned>(direction)),
@@ -82,7 +71,6 @@ NGConstraintSpace::NGConstraintSpace(
floats_bfc_offset_(floats_bfc_offset),
exclusion_space_(std::make_unique<NGExclusionSpace>(exclusion_space)),
clearance_offset_(clearance_offset) {
- unpositioned_floats_.swap(unpositioned_floats);
baseline_requests_.swap(baseline_requests);
}
@@ -92,42 +80,62 @@ scoped_refptr<NGConstraintSpace> NGConstraintSpace::CreateFromLayoutObject(
bool parallel_containing_block = IsParallelWritingMode(
box.ContainingBlock()->StyleRef().GetWritingMode(), writing_mode);
bool fixed_inline = false, fixed_block = false;
+ bool fixed_block_is_definite = true;
LayoutUnit available_logical_width;
- if (parallel_containing_block)
- available_logical_width = box.ContainingBlockLogicalWidthForContent();
- else
- available_logical_width = box.PerpendicularContainingBlockLogicalHeight();
+ if (parallel_containing_block &&
+ box.HasOverrideContainingBlockContentLogicalWidth()) {
+ // Grid layout sets OverrideContainingBlockContentLogicalWidth|Height
+ available_logical_width = box.OverrideContainingBlockContentLogicalWidth();
+ } else if (!parallel_containing_block &&
+ box.HasOverrideContainingBlockContentLogicalHeight()) {
+ available_logical_width = box.OverrideContainingBlockContentLogicalHeight();
+ } else {
+ if (parallel_containing_block)
+ available_logical_width = box.ContainingBlockLogicalWidthForContent();
+ else
+ available_logical_width = box.PerpendicularContainingBlockLogicalHeight();
+ }
available_logical_width = std::max(LayoutUnit(), available_logical_width);
LayoutUnit available_logical_height;
- if (!box.Parent()) {
- available_logical_height = box.View()->ViewLogicalHeightForPercentages();
- } else if (box.ContainingBlock()) {
- if (parallel_containing_block) {
- available_logical_height =
- box.ContainingBlock()
- ->AvailableLogicalHeightForPercentageComputation();
- } else {
- available_logical_height = box.ContainingBlockLogicalWidthForContent();
+ if (parallel_containing_block &&
+ box.HasOverrideContainingBlockContentLogicalHeight()) {
+ // Grid layout sets OverrideContainingBlockContentLogicalWidth|Height
+ available_logical_height =
+ box.OverrideContainingBlockContentLogicalHeight();
+ } else if (!parallel_containing_block &&
+ box.HasOverrideContainingBlockContentLogicalWidth()) {
+ available_logical_height = box.OverrideContainingBlockContentLogicalWidth();
+ } else {
+ if (!box.Parent()) {
+ available_logical_height = box.View()->ViewLogicalHeightForPercentages();
+ } else if (box.ContainingBlock()) {
+ if (parallel_containing_block) {
+ available_logical_height =
+ box.ContainingBlock()
+ ->AvailableLogicalHeightForPercentageComputation();
+ } else {
+ available_logical_height = box.ContainingBlockLogicalWidthForContent();
+ }
}
}
NGLogicalSize percentage_size = {available_logical_width,
available_logical_height};
NGLogicalSize available_size = percentage_size;
- // When we have an override size, the available_logical_{width,height} will be
- // used as the final size of the box, so it has to include border and
- // padding.
- if (box.HasOverrideLogicalContentWidth()) {
- available_size.inline_size =
- box.BorderAndPaddingLogicalWidth() + box.OverrideLogicalContentWidth();
+ if (box.HasOverrideLogicalWidth()) {
+ available_size.inline_size = box.OverrideLogicalWidth();
fixed_inline = true;
}
- if (box.HasOverrideLogicalContentHeight()) {
- available_size.block_size = box.BorderAndPaddingLogicalHeight() +
- box.OverrideLogicalContentHeight();
+ if (box.HasOverrideLogicalHeight()) {
+ available_size.block_size = box.OverrideLogicalHeight();
fixed_block = true;
}
+ if (box.IsFlexItem() && fixed_block) {
+ fixed_block_is_definite =
+ ToLayoutFlexibleBox(box.Parent())
+ ->UseOverrideLogicalHeightForPerentageResolution(box);
+ }
bool is_new_fc = true;
// TODO(ikilpatrick): This DCHECK needs to be enabled once we've switched
@@ -149,26 +157,25 @@ scoped_refptr<NGConstraintSpace> NGConstraintSpace::CreateFromLayoutObject(
NGConstraintSpaceBuilder builder(writing_mode, initial_containing_block_size);
- if (ShouldComputeBaseline(box)) {
- FontBaseline baseline_type = IsHorizontalWritingMode(writing_mode)
- ? kAlphabeticBaseline
- : kIdeographicBaseline;
+ if (!box.IsWritingModeRoot()) {
// Add all types because we don't know which baselines will be requested.
- builder
- .AddBaselineRequest(
- {NGBaselineAlgorithmType::kAtomicInline, baseline_type})
- .AddBaselineRequest(
- {NGBaselineAlgorithmType::kFirstLine, baseline_type});
+ FontBaseline baseline_type = box.StyleRef().GetFontBaseline();
+ bool synthesize_inline_block_baseline =
+ box.IsLayoutBlock() &&
+ ToLayoutBlock(box).UseLogicalBottomMarginEdgeForInlineBlockBaseline();
+ if (!synthesize_inline_block_baseline) {
+ builder.AddBaselineRequest(
+ {NGBaselineAlgorithmType::kAtomicInline, baseline_type});
+ }
+ builder.AddBaselineRequest(
+ {NGBaselineAlgorithmType::kFirstLine, baseline_type});
}
return builder.SetAvailableSize(available_size)
.SetPercentageResolutionSize(percentage_size)
- .SetIsInlineDirectionTriggersScrollbar(
- box.StyleRef().OverflowInlineDirection() == EOverflow::kAuto)
- .SetIsBlockDirectionTriggersScrollbar(
- box.StyleRef().OverflowBlockDirection() == EOverflow::kAuto)
.SetIsFixedSizeInline(fixed_inline)
.SetIsFixedSizeBlock(fixed_block)
+ .SetFixedSizeBlockIsDefinite(fixed_block_is_definite)
.SetIsShrinkToFit(
box.SizesLogicalWidthToFitContent(box.StyleRef().LogicalWidth()))
.SetIsNewFormattingContext(is_new_fc)
@@ -199,12 +206,6 @@ NGFragmentationType NGConstraintSpace::BlockFragmentationType() const {
}
bool NGConstraintSpace::operator==(const NGConstraintSpace& other) const {
- // TODO(cbiesinger): For simplicity and performance, for now, we only
- // consider two constraint spaces equal if neither one has unpositioned
- // floats. We should consider changing this in the future.
- if (unpositioned_floats_.size() || other.unpositioned_floats_.size())
- return false;
-
if (exclusion_space_ && other.exclusion_space_ &&
*exclusion_space_ != *other.exclusion_space_)
return false;
@@ -221,16 +222,15 @@ bool NGConstraintSpace::operator==(const NGConstraintSpace& other) const {
is_fixed_size_inline_ == other.is_fixed_size_inline_ &&
is_fixed_size_block_ == other.is_fixed_size_block_ &&
is_shrink_to_fit_ == other.is_shrink_to_fit_ &&
- is_inline_direction_triggers_scrollbar_ ==
- other.is_inline_direction_triggers_scrollbar_ &&
- is_block_direction_triggers_scrollbar_ ==
- other.is_block_direction_triggers_scrollbar_ &&
+ is_intermediate_layout_ == other.is_intermediate_layout_ &&
block_direction_fragmentation_type_ ==
other.block_direction_fragmentation_type_ &&
is_new_fc_ == other.is_new_fc_ &&
separate_leading_fragmentainer_margins_ ==
other.separate_leading_fragmentainer_margins_ &&
is_anonymous_ == other.is_anonymous_ &&
+ should_force_clearance_ == other.should_force_clearance_ &&
+ adjoining_floats_ == other.adjoining_floats_ &&
writing_mode_ == other.writing_mode_ &&
direction_ == other.direction_ &&
margin_strut_ == other.margin_strut_ &&
@@ -245,15 +245,14 @@ bool NGConstraintSpace::operator!=(const NGConstraintSpace& other) const {
}
String NGConstraintSpace::ToString() const {
- return String::Format(
- "Offset: %s,%s Size: %sx%s Clearance: %s",
- bfc_offset_.line_offset.ToString().Ascii().data(),
- bfc_offset_.block_offset.ToString().Ascii().data(),
- AvailableSize().inline_size.ToString().Ascii().data(),
- AvailableSize().block_size.ToString().Ascii().data(),
- clearance_offset_.has_value()
- ? clearance_offset_.value().ToString().Ascii().data()
- : "none");
+ return String::Format("Offset: %s,%s Size: %sx%s Clearance: %s",
+ bfc_offset_.line_offset.ToString().Ascii().data(),
+ bfc_offset_.block_offset.ToString().Ascii().data(),
+ AvailableSize().inline_size.ToString().Ascii().data(),
+ AvailableSize().block_size.ToString().Ascii().data(),
+ HasClearanceOffset()
+ ? ClearanceOffset().ToString().Ascii().data()
+ : "none");
}
} // namespace blink
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 f3bd0b7c848..2fc95583958 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
@@ -5,6 +5,7 @@
#ifndef NGConstraintSpace_h
#define NGConstraintSpace_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_bfc_offset.h"
@@ -12,10 +13,9 @@
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
@@ -116,18 +116,6 @@ class CORE_EXPORT NGConstraintSpace final
// Also note this is true only when the document has ':first-line' rules.
bool UseFirstLineStyle() const { return use_first_line_style_; }
- // Whether exceeding the AvailableSize() triggers the presence of a scrollbar
- // for the indicated direction.
- // If exceeded the current layout should be aborted and invoked again with a
- // constraint space modified to reserve space for a scrollbar.
- bool IsInlineDirectionTriggersScrollbar() const {
- return is_inline_direction_triggers_scrollbar_;
- }
-
- bool IsBlockDirectionTriggersScrollbar() const {
- return is_block_direction_triggers_scrollbar_;
- }
-
// 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
@@ -139,10 +127,20 @@ class CORE_EXPORT NGConstraintSpace final
bool IsFixedSizeBlock() const { return is_fixed_size_block_; }
+ // Whether a fixed block size should be considered definite.
+ bool FixedSizeBlockIsDefinite() const {
+ return fixed_size_block_is_definite_;
+ }
+
// Whether an auto inline-size should be interpreted as shrink-to-fit
// (ie. fit-content). This is used for inline-block, floats, etc.
bool IsShrinkToFit() const { return is_shrink_to_fit_; }
+ // Whether this constraint space is used for an intermediate layout in a
+ // multi-pass layout. In such a case, we should not copy back the resulting
+ // layout data to the legacy tree or create a paint fragment from it.
+ bool IsIntermediateLayout() const { return is_intermediate_layout_; }
+
// If specified a layout should produce a Fragment which fragments at the
// blockSize if possible.
NGFragmentationType BlockFragmentationType() const;
@@ -170,28 +168,62 @@ class CORE_EXPORT NGConstraintSpace final
// - block_start border or padding in the current layout.
// - Text content, atomic inlines, (see NGLineBreaker).
// - The current layout having a block_size.
+ // - Clearance before a child.
NGBfcOffset BfcOffset() const { return bfc_offset_; }
// If present, and the current layout hasn't resolved its BFC offset yet (see
// BfcOffset), the layout should position all of its unpositioned floats at
- // this offset.
+ // this offset. This value is the BFC offset that we calculated in the
+ // previous pass, a pass which aborted once the BFC offset got resolved,
+ // because we had walked past content (i.e. floats) that depended on it being
+ // resolved.
//
// This value should be propogated to child layouts if the current layout
// hasn't resolved its BFC offset yet.
//
- // This value is calculated *after* an initial pass of the tree, this value
- // should only be present during the second pass.
- WTF::Optional<NGBfcOffset> FloatsBfcOffset() const {
+ // This value is calculated *after* an initial pass of the tree, and should
+ // only be present during subsequent passes.
+ base::Optional<NGBfcOffset> FloatsBfcOffset() const {
return floats_bfc_offset_;
}
- const Vector<scoped_refptr<NGUnpositionedFloat>>& UnpositionedFloats() const {
- return unpositioned_floats_;
+ // Return the types (none, left, right, both) of preceding adjoining
+ // floats. These are floats that are added while the in-flow BFC offset is
+ // still unknown. The floats may or may not be unpositioned (pending). That
+ // depends on which layout pass we're in. They are typically positioned if
+ // FloatsBfcOffset() is known. Adjoining floats should be treated differently
+ // when calculating clearance on a block with adjoining block-start margin.
+ // (in such cases we will know up front that the block will need clearance,
+ // since, if it doesn't, the float will be pulled along with the block, and
+ // the block will fail to clear).
+ NGFloatTypes AdjoiningFloatTypes() const { return adjoining_floats_; }
+
+ bool HasClearanceOffset() const {
+ return clearance_offset_ != LayoutUnit::Min();
}
+ LayoutUnit ClearanceOffset() const { return clearance_offset_; }
- WTF::Optional<LayoutUnit> ClearanceOffset() const {
- return clearance_offset_;
- }
+ // Return true if the fragment needs to have clearance applied to it,
+ // regardless of its hypothetical position. The fragment will then go exactly
+ // below the relevant floats. This happens when a cleared child gets separated
+ // from floats that would otherwise be adjoining; example:
+ //
+ // <div id="container">
+ // <div id="float" style="float:left; width:100px; height:100px;"></div>
+ // <div id="clearee" style="clear:left; margin-top:12345px;">text</div>
+ // </div>
+ //
+ // Clearance separates #clearee from #container, and #float is positioned at
+ // the block-start content edge of #container. Without clearance, margins
+ // would have been adjoining and the large margin on #clearee would have
+ // pulled both #container and #float along with it. No margin, no matter how
+ // large, would ever be able to pull #clearee below the float then. But we
+ // have clearance, the margins are separated, and in this case we know that we
+ // have clearance even before we have laid out (because of the adjoing
+ // float). So it would just be wrong to check for clearance when we position
+ // #clearee. Nothing can prevent clearance here. A large margin on the cleared
+ // child will be canceled out with negative clearance.
+ bool ShouldForceClearance() const { return should_force_clearance_; }
const Vector<NGBaselineRequest>& BaselineRequests() const {
return baseline_requests_;
@@ -205,33 +237,33 @@ class CORE_EXPORT NGConstraintSpace final
private:
friend class NGConstraintSpaceBuilder;
// Default constructor.
- NGConstraintSpace(
- WritingMode,
- bool is_orthogonal_writing_mode_root,
- TextDirection,
- NGLogicalSize available_size,
- NGLogicalSize percentage_resolution_size,
- LayoutUnit parent_percentage_resolution_inline_size,
- NGPhysicalSize initial_containing_block_size,
- LayoutUnit fragmentainer_block_size,
- LayoutUnit fragmentainer_space_at_bfc_start,
- bool is_fixed_size_inline,
- bool is_fixed_size_block,
- bool is_shrink_to_fit,
- bool is_inline_direction_triggers_scrollbar,
- bool is_block_direction_triggers_scrollbar,
- NGFragmentationType block_direction_fragmentation_type,
- bool separate_leading_fragmentainer_margins_,
- bool is_new_fc,
- bool is_anonymous,
- bool use_first_line_style,
- const NGMarginStrut& margin_strut,
- const NGBfcOffset& bfc_offset,
- const WTF::Optional<NGBfcOffset>& floats_bfc_offset,
- const NGExclusionSpace& exclusion_space,
- Vector<scoped_refptr<NGUnpositionedFloat>>& unpositioned_floats,
- const WTF::Optional<LayoutUnit>& clearance_offset,
- Vector<NGBaselineRequest>& baseline_requests);
+ NGConstraintSpace(WritingMode,
+ bool is_orthogonal_writing_mode_root,
+ TextDirection,
+ NGLogicalSize available_size,
+ NGLogicalSize percentage_resolution_size,
+ LayoutUnit parent_percentage_resolution_inline_size,
+ NGPhysicalSize initial_containing_block_size,
+ LayoutUnit fragmentainer_block_size,
+ LayoutUnit fragmentainer_space_at_bfc_start,
+ bool is_fixed_size_inline,
+ bool is_fixed_size_block,
+ bool fixed_size_block_is_definite,
+ bool is_shrink_to_fit,
+ bool is_intermediate_layout,
+ NGFragmentationType block_direction_fragmentation_type,
+ bool separate_leading_fragmentainer_margins_,
+ bool is_new_fc,
+ bool is_anonymous,
+ bool use_first_line_style,
+ bool should_force_clearance,
+ NGFloatTypes adjoining_floats,
+ const NGMarginStrut& margin_strut,
+ const NGBfcOffset& bfc_offset,
+ const base::Optional<NGBfcOffset>& floats_bfc_offset,
+ const NGExclusionSpace& exclusion_space,
+ LayoutUnit clearance_offset,
+ Vector<NGBaselineRequest>& baseline_requests);
NGLogicalSize available_size_;
NGLogicalSize percentage_resolution_size_;
@@ -243,11 +275,10 @@ class CORE_EXPORT NGConstraintSpace final
unsigned is_fixed_size_inline_ : 1;
unsigned is_fixed_size_block_ : 1;
+ unsigned fixed_size_block_is_definite_ : 1;
unsigned is_shrink_to_fit_ : 1;
-
- unsigned is_inline_direction_triggers_scrollbar_ : 1;
- unsigned is_block_direction_triggers_scrollbar_ : 1;
+ unsigned is_intermediate_layout_ : 1;
unsigned block_direction_fragmentation_type_ : 2;
unsigned separate_leading_fragmentainer_margins_ : 1;
@@ -258,6 +289,8 @@ class CORE_EXPORT NGConstraintSpace final
unsigned is_anonymous_ : 1;
unsigned use_first_line_style_ : 1;
+ unsigned should_force_clearance_ : 1;
+ unsigned adjoining_floats_ : 2; // NGFloatTypes
unsigned writing_mode_ : 3;
unsigned is_orthogonal_writing_mode_root_ : 1;
@@ -265,11 +298,10 @@ class CORE_EXPORT NGConstraintSpace final
NGMarginStrut margin_strut_;
NGBfcOffset bfc_offset_;
- WTF::Optional<NGBfcOffset> floats_bfc_offset_;
+ base::Optional<NGBfcOffset> floats_bfc_offset_;
const std::unique_ptr<const NGExclusionSpace> exclusion_space_;
- WTF::Optional<LayoutUnit> clearance_offset_;
- Vector<scoped_refptr<NGUnpositionedFloat>> unpositioned_floats_;
+ LayoutUnit clearance_offset_;
Vector<NGBaselineRequest> baseline_requests_;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc
index 9e60a1dc247..f1ed8bb3579 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_constraint_space_builder.cc
@@ -13,26 +13,13 @@ NGConstraintSpaceBuilder::NGConstraintSpaceBuilder(
: NGConstraintSpaceBuilder(parent_space.GetWritingMode(),
parent_space.InitialContainingBlockSize()) {
parent_percentage_resolution_size_ = parent_space.PercentageResolutionSize();
+ is_intermediate_layout_ = parent_space.IsIntermediateLayout();
}
NGConstraintSpaceBuilder::NGConstraintSpaceBuilder(WritingMode writing_mode,
NGPhysicalSize icb_size)
: initial_containing_block_size_(icb_size),
- fragmentainer_block_size_(NGSizeIndefinite),
- fragmentainer_space_at_bfc_start_(NGSizeIndefinite),
- parent_writing_mode_(static_cast<unsigned>(writing_mode)),
- is_fixed_size_inline_(false),
- is_fixed_size_block_(false),
- is_shrink_to_fit_(false),
- is_inline_direction_triggers_scrollbar_(false),
- is_block_direction_triggers_scrollbar_(false),
- fragmentation_type_(kFragmentNone),
- separate_leading_fragmentainer_margins_(false),
- is_new_fc_(false),
- is_anonymous_(false),
- use_first_line_style_(false),
- text_direction_(static_cast<unsigned>(TextDirection::kLtr)),
- exclusion_space_(nullptr) {}
+ parent_writing_mode_(writing_mode) {}
NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetAvailableSize(
NGLogicalSize available_size) {
@@ -48,7 +35,7 @@ NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetPercentageResolutionSize(
NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetTextDirection(
TextDirection text_direction) {
- text_direction_ = static_cast<unsigned>(text_direction);
+ text_direction_ = text_direction;
return *this;
}
@@ -65,13 +52,13 @@ NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetBfcOffset(
}
NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetFloatsBfcOffset(
- const WTF::Optional<NGBfcOffset>& floats_bfc_offset) {
+ const base::Optional<NGBfcOffset>& floats_bfc_offset) {
floats_bfc_offset_ = floats_bfc_offset;
return *this;
}
NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetClearanceOffset(
- const WTF::Optional<LayoutUnit>& clearance_offset) {
+ LayoutUnit clearance_offset) {
clearance_offset_ = clearance_offset;
return *this;
}
@@ -94,25 +81,21 @@ NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetIsFixedSizeBlock(
return *this;
}
-NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetIsShrinkToFit(
- bool shrink_to_fit) {
- is_shrink_to_fit_ = shrink_to_fit;
+NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetFixedSizeBlockIsDefinite(
+ bool fixed_size_block_is_definite) {
+ fixed_size_block_is_definite_ = fixed_size_block_is_definite;
return *this;
}
-NGConstraintSpaceBuilder&
-NGConstraintSpaceBuilder::SetIsInlineDirectionTriggersScrollbar(
- bool is_inline_direction_triggers_scrollbar) {
- is_inline_direction_triggers_scrollbar_ =
- is_inline_direction_triggers_scrollbar;
+NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetIsShrinkToFit(
+ bool shrink_to_fit) {
+ is_shrink_to_fit_ = shrink_to_fit;
return *this;
}
-NGConstraintSpaceBuilder&
-NGConstraintSpaceBuilder::SetIsBlockDirectionTriggersScrollbar(
- bool is_block_direction_triggers_scrollbar) {
- is_block_direction_triggers_scrollbar_ =
- is_block_direction_triggers_scrollbar;
+NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetIsIntermediateLayout(
+ bool is_intermediate_layout) {
+ is_intermediate_layout_ = is_intermediate_layout;
return *this;
}
@@ -140,12 +123,6 @@ NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetUseFirstLineStyle(
return *this;
}
-NGConstraintSpaceBuilder& NGConstraintSpaceBuilder::SetUnpositionedFloats(
- Vector<scoped_refptr<NGUnpositionedFloat>>& unpositioned_floats) {
- unpositioned_floats_ = unpositioned_floats;
- return *this;
-}
-
void NGConstraintSpaceBuilder::AddBaselineRequests(
const Vector<NGBaselineRequest>& requests) {
DCHECK(baseline_requests_.IsEmpty());
@@ -166,17 +143,23 @@ scoped_refptr<NGConstraintSpace> NGConstraintSpaceBuilder::ToConstraintSpace(
WritingMode out_writing_mode) {
// Whether the child and the containing block are parallel to each other.
// Example: vertical-rl and vertical-lr
- bool is_in_parallel_flow = IsParallelWritingMode(
- static_cast<WritingMode>(parent_writing_mode_), out_writing_mode);
+ bool is_in_parallel_flow =
+ IsParallelWritingMode(parent_writing_mode_, out_writing_mode);
NGLogicalSize available_size = available_size_;
NGLogicalSize percentage_resolution_size = percentage_resolution_size_;
NGLogicalSize parent_percentage_resolution_size =
parent_percentage_resolution_size_.value_or(percentage_resolution_size);
+ bool is_fixed_size_inline = is_fixed_size_inline_;
+ bool is_fixed_size_block = is_fixed_size_block_;
+ bool fixed_size_block_is_definite = fixed_size_block_is_definite_;
if (!is_in_parallel_flow) {
available_size.Flip();
percentage_resolution_size.Flip();
parent_percentage_resolution_size.Flip();
+ is_fixed_size_inline = is_fixed_size_block_;
+ is_fixed_size_block = is_fixed_size_inline_;
+ fixed_size_block_is_definite = true;
}
// If inline size is indefinite, use size of initial containing block.
@@ -202,56 +185,34 @@ scoped_refptr<NGConstraintSpace> NGConstraintSpaceBuilder::ToConstraintSpace(
DEFINE_STATIC_LOCAL(NGExclusionSpace, empty_exclusion_space, ());
- // Reset things that do not pass the Formatting Context boundary.
- if (is_new_fc_)
- DCHECK(unpositioned_floats_.IsEmpty());
+ DCHECK(!is_new_fc_ || !adjoining_floats_);
const NGExclusionSpace& exclusion_space = (is_new_fc_ || !exclusion_space_)
? empty_exclusion_space
: *exclusion_space_;
NGBfcOffset bfc_offset = is_new_fc_ ? NGBfcOffset() : bfc_offset_;
NGMarginStrut margin_strut = is_new_fc_ ? NGMarginStrut() : margin_strut_;
- WTF::Optional<LayoutUnit> clearance_offset =
- is_new_fc_ ? WTF::nullopt : clearance_offset_;
- WTF::Optional<NGBfcOffset> floats_bfc_offset =
- is_new_fc_ ? WTF::nullopt : floats_bfc_offset_;
+ LayoutUnit clearance_offset =
+ is_new_fc_ ? LayoutUnit::Min() : clearance_offset_;
+ base::Optional<NGBfcOffset> floats_bfc_offset =
+ is_new_fc_ ? base::nullopt : floats_bfc_offset_;
if (floats_bfc_offset) {
floats_bfc_offset = NGBfcOffset(
{bfc_offset.line_offset, floats_bfc_offset.value().block_offset});
}
- if (is_in_parallel_flow) {
- return base::AdoptRef(new NGConstraintSpace(
- static_cast<WritingMode>(out_writing_mode), false,
- static_cast<TextDirection>(text_direction_), available_size,
- percentage_resolution_size,
- parent_percentage_resolution_size.inline_size,
- initial_containing_block_size_, fragmentainer_block_size_,
- fragmentainer_space_at_bfc_start_, is_fixed_size_inline_,
- is_fixed_size_block_, is_shrink_to_fit_,
- is_inline_direction_triggers_scrollbar_,
- is_block_direction_triggers_scrollbar_,
- static_cast<NGFragmentationType>(fragmentation_type_),
- separate_leading_fragmentainer_margins_, is_new_fc_, is_anonymous_,
- use_first_line_style_, margin_strut, bfc_offset, floats_bfc_offset,
- exclusion_space, unpositioned_floats_, clearance_offset,
- baseline_requests_));
- }
return base::AdoptRef(new NGConstraintSpace(
- out_writing_mode, true, static_cast<TextDirection>(text_direction_),
- available_size, percentage_resolution_size,
- parent_percentage_resolution_size.inline_size,
+ out_writing_mode, !is_in_parallel_flow, text_direction_, available_size,
+ percentage_resolution_size, parent_percentage_resolution_size.inline_size,
initial_containing_block_size_, fragmentainer_block_size_,
- fragmentainer_space_at_bfc_start_, is_fixed_size_block_,
- is_fixed_size_inline_, is_shrink_to_fit_,
- is_block_direction_triggers_scrollbar_,
- is_inline_direction_triggers_scrollbar_,
- static_cast<NGFragmentationType>(fragmentation_type_),
+ fragmentainer_space_at_bfc_start_, is_fixed_size_inline,
+ is_fixed_size_block, fixed_size_block_is_definite, is_shrink_to_fit_,
+ is_intermediate_layout_, fragmentation_type_,
separate_leading_fragmentainer_margins_, is_new_fc_, is_anonymous_,
- use_first_line_style_, margin_strut, bfc_offset, floats_bfc_offset,
- exclusion_space, unpositioned_floats_, clearance_offset,
- baseline_requests_));
+ use_first_line_style_, should_force_clearance_, adjoining_floats_,
+ margin_strut, bfc_offset, floats_bfc_offset, exclusion_space,
+ clearance_offset, baseline_requests_));
}
} // namespace blink
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 9f4ab1f2b8b..a23c2d926bb 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
@@ -5,17 +5,21 @@
#ifndef NGConstraintSpaceBuilder_h
#define NGConstraintSpaceBuilder_h
+#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h"
+#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.h"
#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_exclusion.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
+#include "third_party/blink/renderer/platform/text/text_direction.h"
+#include "third_party/blink/renderer/platform/text/writing_mode.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink {
+class NGExclusionSpace;
+
class CORE_EXPORT NGConstraintSpaceBuilder final {
- DISALLOW_NEW();
+ STACK_ALLOCATED();
public:
// NOTE: This constructor doesn't act like a copy-constructor, it uses the
@@ -44,13 +48,13 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
NGConstraintSpaceBuilder& SetIsFixedSizeInline(bool is_fixed_size_inline);
NGConstraintSpaceBuilder& SetIsFixedSizeBlock(bool is_fixed_size_block);
+ NGConstraintSpaceBuilder& SetFixedSizeBlockIsDefinite(
+ bool fixed_size_block_is_definite);
NGConstraintSpaceBuilder& SetIsShrinkToFit(bool shrink_to_fit);
- NGConstraintSpaceBuilder& SetIsInlineDirectionTriggersScrollbar(
- bool is_inline_direction_triggers_scrollbar);
- NGConstraintSpaceBuilder& SetIsBlockDirectionTriggersScrollbar(
- bool is_block_direction_triggers_scrollbar);
+ NGConstraintSpaceBuilder& SetIsIntermediateLayout(
+ bool is_intermediate_layout);
NGConstraintSpaceBuilder& SetFragmentationType(NGFragmentationType);
@@ -63,17 +67,23 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
NGConstraintSpaceBuilder& SetIsAnonymous(bool is_anonymous);
NGConstraintSpaceBuilder& SetUseFirstLineStyle(bool use_first_line_style);
- NGConstraintSpaceBuilder& SetUnpositionedFloats(
- Vector<scoped_refptr<NGUnpositionedFloat>>& unpositioned_floats);
+ NGConstraintSpaceBuilder& SetAdjoiningFloatTypes(NGFloatTypes floats) {
+ adjoining_floats_ = floats;
+ return *this;
+ }
NGConstraintSpaceBuilder& SetMarginStrut(const NGMarginStrut& margin_strut);
NGConstraintSpaceBuilder& SetBfcOffset(const NGBfcOffset& bfc_offset);
NGConstraintSpaceBuilder& SetFloatsBfcOffset(
- const WTF::Optional<NGBfcOffset>& floats_bfc_offset);
+ const base::Optional<NGBfcOffset>& floats_bfc_offset);
- NGConstraintSpaceBuilder& SetClearanceOffset(
- const WTF::Optional<LayoutUnit>& clearance_offset);
+ NGConstraintSpaceBuilder& SetClearanceOffset(LayoutUnit clearance_offset);
+
+ NGConstraintSpaceBuilder& SetShouldForceClearance() {
+ should_force_clearance_ = true;
+ return *this;
+ }
NGConstraintSpaceBuilder& SetExclusionSpace(
const NGExclusionSpace& exclusion_space);
@@ -96,30 +106,31 @@ class CORE_EXPORT NGConstraintSpaceBuilder final {
NGLogicalSize available_size_;
// Relative to parent_writing_mode_.
NGLogicalSize percentage_resolution_size_;
- Optional<NGLogicalSize> parent_percentage_resolution_size_;
+ base::Optional<NGLogicalSize> parent_percentage_resolution_size_;
NGPhysicalSize initial_containing_block_size_;
- LayoutUnit fragmentainer_block_size_;
- LayoutUnit fragmentainer_space_at_bfc_start_;
-
- unsigned parent_writing_mode_ : 3;
- unsigned is_fixed_size_inline_ : 1;
- unsigned is_fixed_size_block_ : 1;
- unsigned is_shrink_to_fit_ : 1;
- unsigned is_inline_direction_triggers_scrollbar_ : 1;
- unsigned is_block_direction_triggers_scrollbar_ : 1;
- unsigned fragmentation_type_ : 2;
- unsigned separate_leading_fragmentainer_margins_ : 1;
- unsigned is_new_fc_ : 1;
- unsigned is_anonymous_ : 1;
- unsigned use_first_line_style_ : 1;
- unsigned text_direction_ : 1;
+ LayoutUnit fragmentainer_block_size_ = NGSizeIndefinite;
+ LayoutUnit fragmentainer_space_at_bfc_start_ = NGSizeIndefinite;
+
+ WritingMode parent_writing_mode_;
+ NGFragmentationType fragmentation_type_ = kFragmentNone;
+ NGFloatTypes adjoining_floats_ = kFloatTypeNone;
+ TextDirection text_direction_ = TextDirection::kLtr;
+ bool is_fixed_size_inline_ = false;
+ bool is_fixed_size_block_ = false;
+ bool fixed_size_block_is_definite_ = true;
+ bool is_shrink_to_fit_ = false;
+ bool is_intermediate_layout_ = false;
+ bool separate_leading_fragmentainer_margins_ = false;
+ bool is_new_fc_ = false;
+ bool is_anonymous_ = false;
+ bool use_first_line_style_ = false;
+ bool should_force_clearance_ = false;
NGMarginStrut margin_strut_;
NGBfcOffset bfc_offset_;
- WTF::Optional<NGBfcOffset> floats_bfc_offset_;
- const NGExclusionSpace* exclusion_space_;
- WTF::Optional<LayoutUnit> clearance_offset_;
- Vector<scoped_refptr<NGUnpositionedFloat>> unpositioned_floats_;
+ base::Optional<NGBfcOffset> floats_bfc_offset_;
+ const NGExclusionSpace* exclusion_space_ = nullptr;
+ LayoutUnit clearance_offset_;
Vector<NGBaselineRequest> baseline_requests_;
};
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 eb667bad00b..d3c783914e8 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
@@ -5,9 +5,9 @@
#include "third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h"
#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
namespace blink {
@@ -45,12 +45,6 @@ NGContainerFragmentBuilder& NGContainerFragmentBuilder::SetExclusionSpace(
return *this;
}
-NGContainerFragmentBuilder& NGContainerFragmentBuilder::SwapUnpositionedFloats(
- Vector<scoped_refptr<NGUnpositionedFloat>>* unpositioned_floats) {
- unpositioned_floats_.swap(*unpositioned_floats);
- return *this;
-}
-
NGContainerFragmentBuilder&
NGContainerFragmentBuilder::SetUnpositionedListMarker(
const NGUnpositionedListMarker& marker) {
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 84948148997..448360170e1 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
@@ -12,6 +12,7 @@
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_margin_strut.h"
#include "third_party/blink/renderer/core/layout/ng/list/ng_unpositioned_list_marker.h"
#include "third_party/blink/renderer/core/layout/ng/ng_base_fragment_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
@@ -23,7 +24,6 @@ class ComputedStyle;
class NGExclusionSpace;
class NGLayoutResult;
class NGPhysicalFragment;
-struct NGUnpositionedFloat;
class CORE_EXPORT NGContainerFragmentBuilder : public NGBaseFragmentBuilder {
STACK_ALLOCATED();
@@ -39,17 +39,18 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGBaseFragmentBuilder {
// The NGBfcOffset is where this fragment was positioned within the BFC. If
// it is not set, this fragment may be placed anywhere within the BFC.
- const WTF::Optional<NGBfcOffset>& BfcOffset() const { return bfc_offset_; }
+ const base::Optional<NGBfcOffset>& BfcOffset() const { return bfc_offset_; }
NGContainerFragmentBuilder& SetBfcOffset(const NGBfcOffset&);
+ NGContainerFragmentBuilder& ResetBfcOffset() {
+ bfc_offset_.reset();
+ return *this;
+ }
NGContainerFragmentBuilder& SetEndMarginStrut(const NGMarginStrut&);
NGContainerFragmentBuilder& SetExclusionSpace(
std::unique_ptr<const NGExclusionSpace> exclusion_space);
- NGContainerFragmentBuilder& SwapUnpositionedFloats(
- Vector<scoped_refptr<NGUnpositionedFloat>>*);
-
const NGUnpositionedListMarker& UnpositionedListMarker() const {
return unpositioned_list_marker_;
}
@@ -121,6 +122,16 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGBaseFragmentBuilder {
}
bool IsPushedByFloats() const { return is_pushed_by_floats_; }
+ NGContainerFragmentBuilder& ResetAdjoiningFloatTypes() {
+ adjoining_floats_ = kFloatTypeNone;
+ return *this;
+ }
+ NGContainerFragmentBuilder& AddAdjoiningFloatTypes(NGFloatTypes floats) {
+ adjoining_floats_ |= floats;
+ return *this;
+ }
+ NGFloatTypes AdjoiningFloatTypes() const { return adjoining_floats_; }
+
#ifndef NDEBUG
String ToString() const;
#endif
@@ -170,14 +181,10 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGBaseFragmentBuilder {
NGLogicalSize size_;
- WTF::Optional<NGBfcOffset> bfc_offset_;
+ base::Optional<NGBfcOffset> bfc_offset_;
NGMarginStrut end_margin_strut_;
std::unique_ptr<const NGExclusionSpace> exclusion_space_;
- // Floats that need to be positioned by the next in-flow fragment that can
- // determine its block position in space.
- Vector<scoped_refptr<NGUnpositionedFloat>> unpositioned_floats_;
-
Vector<NGOutOfFlowPositionedCandidate> oof_positioned_candidates_;
Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants_;
@@ -186,6 +193,8 @@ class CORE_EXPORT NGContainerFragmentBuilder : public NGBaseFragmentBuilder {
Vector<scoped_refptr<NGPhysicalFragment>> children_;
Vector<NGLogicalOffset> offsets_;
+ NGFloatTypes adjoining_floats_ = kFloatTypeNone;
+
bool has_last_resort_break_ = false;
bool is_pushed_by_floats_ = false;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_exclusion.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_exclusion.h
index 554a8fef5f3..a22f4409e6a 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_exclusion.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_exclusion.h
@@ -12,23 +12,41 @@
namespace blink {
+class LayoutBox;
+
+struct CORE_EXPORT NGExclusionShapeData {
+ NGExclusionShapeData(const LayoutBox* layout_box,
+ const NGBoxStrut& margins,
+ const NGBoxStrut& shape_insets)
+ : layout_box(layout_box), margins(margins), shape_insets(shape_insets) {}
+
+ const LayoutBox* layout_box;
+ const NGBoxStrut margins;
+ const NGBoxStrut shape_insets;
+};
+
// Struct that represents an exclusion. This currently is just a float but
// we've named it an exclusion to potentially support other types in the future.
struct CORE_EXPORT NGExclusion : public RefCounted<NGExclusion> {
- static scoped_refptr<NGExclusion> Create(const NGBfcRect& rect,
- const EFloat type) {
- return base::AdoptRef(new NGExclusion(rect, type));
+ static scoped_refptr<NGExclusion> Create(
+ const NGBfcRect& rect,
+ const EFloat type,
+ std::unique_ptr<NGExclusionShapeData> shape_data = nullptr) {
+ return base::AdoptRef(new NGExclusion(rect, type, std::move(shape_data)));
}
const NGBfcRect rect;
const EFloat type;
+ const std::unique_ptr<NGExclusionShapeData> shape_data;
bool operator==(const NGExclusion& other) const;
bool operator!=(const NGExclusion& other) const { return !(*this == other); }
private:
- NGExclusion(const NGBfcRect& rect, const EFloat type)
- : rect(rect), type(type) {}
+ NGExclusion(const NGBfcRect& rect,
+ const EFloat type,
+ std::unique_ptr<NGExclusionShapeData> shape_data)
+ : rect(rect), type(type), shape_data(std::move(shape_data)) {}
};
} // namespace blink
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 3d82603bf5e..4445b9b5f0a 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
@@ -4,16 +4,13 @@
#include "third_party/blink/renderer/core/layout/ng/ng_flex_layout_algorithm.h"
-#include <algorithm>
+#include <memory>
#include "third_party/blink/renderer/core/layout/flexible_box_algorithm.h"
#include "third_party/blink/renderer/core/layout/layout_box.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_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"
#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/wtf/vector.h"
namespace blink {
@@ -30,7 +27,7 @@ scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
<< "Don't support that yet";
LayoutUnit container_logical_width = ComputeInlineSizeForFragment(
- ConstraintSpace(), Style(), /* MinMaxSize */ WTF::nullopt);
+ ConstraintSpace(), Style(), /* MinMaxSize */ base::nullopt);
Vector<FlexItem> flex_items;
for (NGLayoutInputNode child = Node().FirstChild(); child;
@@ -39,11 +36,15 @@ scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
continue;
// Assume row flexbox with no orthogonal items, which lets us just use
// MinMaxSize for flex base size. An orthogonal item would need full layout.
+ // TODO(layout-ng): Now that ComputeMinMaxSize takes a writing mode, this
+ // should be easy to fix by just passing an appropriate constraint space to
+ // ComputeMinMaxSize.
DCHECK(IsParallelWritingMode(Node().Style().GetWritingMode(),
child.Style().GetWritingMode()))
<< "Orthogonal items aren't supported yet.";
MinMaxSizeInput zero_input;
- MinMaxSize min_max_sizes = child.ComputeMinMaxSize(zero_input);
+ MinMaxSize min_max_sizes =
+ child.ComputeMinMaxSize(ConstraintSpace().GetWritingMode(), zero_input);
LayoutUnit flex_base_content_size;
if (child.Style().FlexBasis().IsAuto() && child.Style().Width().IsAuto()) {
@@ -124,19 +125,13 @@ scoped_refptr<NGLayoutResult> NGFlexLayoutAlgorithm::Layout() {
{flex_item.desired_location.X(), flex_item.desired_location.Y()});
}
}
- // TODO(dgrogan): This line is only needed because we erroneously tell the
- // parent block layout algorithm that the flexbox doesn't create a new BFC, so
- // a DCHECK is triggered. Remove this line after adding a LayoutNGFlexibleBox
- // class and returning it from LayoutObject::CreateLayoutObject().
- container_builder_.SetExclusionSpace(
- std::make_unique<NGExclusionSpace>(ConstraintSpace().ExclusionSpace()));
return container_builder_.ToBoxFragment();
}
-Optional<MinMaxSize> NGFlexLayoutAlgorithm::ComputeMinMaxSize(
+base::Optional<MinMaxSize> NGFlexLayoutAlgorithm::ComputeMinMaxSize(
const MinMaxSizeInput& input) const {
// TODO(dgrogan): Implement this.
- return WTF::nullopt;
+ return base::nullopt;
}
} // 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 9df0e0b12cf..1b079c744dc 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
@@ -25,7 +25,8 @@ class CORE_EXPORT NGFlexLayoutAlgorithm
scoped_refptr<NGLayoutResult> Layout() override;
- Optional<MinMaxSize> ComputeMinMaxSize(const MinMaxSizeInput&) const override;
+ base::Optional<MinMaxSize> ComputeMinMaxSize(
+ const MinMaxSizeInput&) const override;
};
} // namespace blink
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 7badb8b057f..0adf9fbfd3b 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
@@ -4,13 +4,18 @@
#include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.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/ng/ng_box_fragment.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"
+#include "third_party/blink/renderer/core/layout/ng/ng_container_fragment_builder.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_fragment.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"
#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/style/computed_style.h"
namespace blink {
@@ -37,7 +42,7 @@ NGLayoutOpportunity FindLayoutOpportunityForFloat(
LayoutUnit inline_size) {
NGBfcOffset adjusted_origin_point =
AdjustToTopEdgeAlignmentRule(exclusion_space, origin_offset);
- WTF::Optional<LayoutUnit> clearance_offset =
+ LayoutUnit clearance_offset =
exclusion_space.ClearanceOffset(unpositioned_float.ClearType());
AdjustToClearance(clearance_offset, &adjusted_origin_point);
@@ -51,26 +56,6 @@ NGLayoutOpportunity FindLayoutOpportunityForFloat(
float_size);
}
-// Creates an exclusion from the fragment that will be placed in the provided
-// layout opportunity.
-scoped_refptr<NGExclusion> CreateExclusion(
- const NGFragment& fragment,
- const NGBfcOffset& float_margin_bfc_offset,
- const NGBoxStrut& margins,
- EFloat type) {
- // TODO(ikilpatrick): Don't include the block-start margin of a float which
- // has fragmented.
- NGBfcOffset start_offset = float_margin_bfc_offset;
-
- NGBfcOffset end_offset(
- /* line_offset */ start_offset.line_offset +
- (fragment.InlineSize() + margins.InlineSum()).ClampNegativeToZero(),
- /* block_offset */ start_offset.block_offset +
- (fragment.BlockSize() + margins.BlockSum()).ClampNegativeToZero());
-
- return NGExclusion::Create(NGBfcRect(start_offset, end_offset), type);
-}
-
scoped_refptr<NGConstraintSpace> CreateConstraintSpaceForFloatFromBuilder(
const NGUnpositionedFloat& unpositioned_float,
NGConstraintSpaceBuilder& builder) {
@@ -115,6 +100,86 @@ CreateConstraintSpaceForFloatForInlineSizeCalculation(
return CreateConstraintSpaceForFloatFromBuilder(unpositioned_float, builder);
}
+std::unique_ptr<NGExclusionShapeData> CreateExclusionShapeData(
+ const NGBoxStrut& margins,
+ const LayoutBox* layout_box,
+ const NGUnpositionedFloat& unpositioned_float,
+ const NGConstraintSpace& parent_space,
+ TextDirection direction) {
+ DCHECK(layout_box->GetShapeOutsideInfo());
+
+ // We make the margins on the shape-data relative to line-left/line-right.
+ NGBoxStrut new_margins(margins.LineLeft(direction),
+ margins.LineRight(direction), margins.block_start,
+ margins.block_end);
+ NGBoxStrut shape_insets;
+
+ const ComputedStyle& style = layout_box->StyleRef();
+ switch (style.ShapeOutside()->CssBox()) {
+ case CSSBoxType::kMissing:
+ case CSSBoxType::kMargin:
+ shape_insets -= new_margins;
+ break;
+ case CSSBoxType::kBorder:
+ break;
+ case CSSBoxType::kPadding:
+ shape_insets =
+ ComputeBorders(*CreateConstraintSpaceForFloatForInlineSizeCalculation(
+ unpositioned_float, parent_space),
+ style)
+ .ConvertToPhysical(style.GetWritingMode(), style.Direction())
+ .ConvertToLogical(parent_space.GetWritingMode(),
+ TextDirection::kLtr);
+ break;
+ case CSSBoxType::kContent:
+ const scoped_refptr<NGConstraintSpace> space =
+ CreateConstraintSpaceForFloatForInlineSizeCalculation(
+ unpositioned_float, parent_space);
+ NGBoxStrut border_padding =
+ ComputeBorders(*space, style) + ComputePadding(*space, style);
+ shape_insets =
+ border_padding
+ .ConvertToPhysical(style.GetWritingMode(), style.Direction())
+ .ConvertToLogical(parent_space.GetWritingMode(),
+ TextDirection::kLtr);
+ break;
+ }
+
+ return std::make_unique<NGExclusionShapeData>(layout_box, new_margins,
+ shape_insets);
+}
+
+// Creates an exclusion from the fragment that will be placed in the provided
+// layout opportunity.
+scoped_refptr<NGExclusion> CreateExclusion(
+ const NGFragment& fragment,
+ const NGBfcOffset& float_margin_bfc_offset,
+ const NGBoxStrut& margins,
+ const LayoutBox* layout_box,
+ const NGUnpositionedFloat& unpositioned_float,
+ const NGConstraintSpace& parent_space,
+ TextDirection direction,
+ EFloat type) {
+ // TODO(ikilpatrick): Don't include the block-start margin of a float which
+ // has fragmented.
+ NGBfcOffset start_offset = float_margin_bfc_offset;
+
+ NGBfcOffset end_offset(
+ /* line_offset */ start_offset.line_offset +
+ (fragment.InlineSize() + margins.InlineSum()).ClampNegativeToZero(),
+ /* block_offset */ start_offset.block_offset +
+ (fragment.BlockSize() + margins.BlockSum()).ClampNegativeToZero());
+
+ std::unique_ptr<NGExclusionShapeData> shape_data =
+ layout_box->GetShapeOutsideInfo()
+ ? CreateExclusionShapeData(margins, layout_box, unpositioned_float,
+ parent_space, direction)
+ : nullptr;
+
+ return NGExclusion::Create(NGBfcRect(start_offset, end_offset), type,
+ std::move(shape_data));
+}
+
} // namespace
LayoutUnit ComputeInlineSizeForUnpositionedFloat(
@@ -130,6 +195,7 @@ LayoutUnit ComputeInlineSizeForUnpositionedFloat(
// If we've already performed layout on the unpositioned float, just return
// the cached value.
if (unpositioned_float->layout_result) {
+ // TODO(layout-ng): Should this use IsParallelWritingMode()?
DCHECK(!is_same_writing_mode);
DCHECK(unpositioned_float->layout_result->PhysicalFragment());
return NGFragment(parent_space.GetWritingMode(),
@@ -148,10 +214,11 @@ LayoutUnit ComputeInlineSizeForUnpositionedFloat(
// because NG cannot figure out the size of such objects on its own,
// especially not for tables.
if (is_same_writing_mode && unpositioned_float->node.CanUseNewLayout()) {
- WTF::Optional<MinMaxSize> min_max_size;
+ base::Optional<MinMaxSize> min_max_size;
if (NeedMinMaxSize(*space.get(), style)) {
MinMaxSizeInput zero_input; // Floats do not intrude into floats.
- min_max_size = unpositioned_float->node.ComputeMinMaxSize(zero_input);
+ min_max_size = unpositioned_float->node.ComputeMinMaxSize(
+ style.GetWritingMode(), zero_input);
}
return ComputeInlineSizeForFragment(*space.get(), style, min_max_size);
}
@@ -222,18 +289,6 @@ NGPositionedFloat PositionFloat(LayoutUnit origin_block_offset,
NGFragment float_fragment(parent_space.GetWritingMode(),
*layout_result->PhysicalFragment());
- // TODO(glebl): This should check for infinite opportunity instead.
- // TODO(ikilpatrick): Remove.
- if (opportunity.rect.IsEmpty()) {
- // Because of the implementation specific of the layout opportunity iterator
- // an empty opportunity can mean 2 things:
- // - search for layout opportunities is exhausted.
- // - opportunity has an infinite size. That's because CS is infinite.
- opportunity = NGLayoutOpportunity(NGBfcRect(
- /* start_offset */ NGBfcOffset(), /* end_offset */ NGBfcOffset(
- float_fragment.InlineSize(), float_fragment.BlockSize())));
- }
-
LayoutUnit float_margin_box_inline_size =
float_fragment.InlineSize() + unpositioned_float->margins.InlineSum();
@@ -247,6 +302,8 @@ NGPositionedFloat PositionFloat(LayoutUnit origin_block_offset,
// Add the float as an exclusion.
scoped_refptr<NGExclusion> exclusion = CreateExclusion(
float_fragment, float_margin_bfc_offset, unpositioned_float->margins,
+ ToLayoutBox(unpositioned_float->node.GetLayoutObject()),
+ *unpositioned_float, parent_space, parent_space.Direction(),
unpositioned_float->IsRight() ? EFloat::kRight : EFloat::kLeft);
exclusion_space->Add(std::move(exclusion));
@@ -278,4 +335,31 @@ const Vector<NGPositionedFloat> PositionFloats(
return positioned_floats;
}
+void AddUnpositionedFloat(
+ Vector<scoped_refptr<NGUnpositionedFloat>>* unpositioned_floats,
+ NGContainerFragmentBuilder* fragment_builder,
+ scoped_refptr<NGUnpositionedFloat> unpositioned_float) {
+ if (fragment_builder && !fragment_builder->BfcOffset()) {
+ fragment_builder->AddAdjoiningFloatTypes(
+ unpositioned_float->IsLeft() ? kFloatTypeLeft : kFloatTypeRight);
+ }
+ unpositioned_floats->push_back(std::move(unpositioned_float));
+}
+
+NGFloatTypes ToFloatTypes(EClear clear) {
+ switch (clear) {
+ default:
+ NOTREACHED();
+ FALLTHROUGH;
+ case EClear::kNone:
+ return kFloatTypeNone;
+ case EClear::kLeft:
+ return kFloatTypeLeft;
+ case EClear::kRight:
+ return kFloatTypeRight;
+ case EClear::kBoth:
+ return kFloatTypeBoth;
+ };
+}
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h
index 2fd9b00bd72..10973f6693a 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_floats_utils.h
@@ -7,16 +7,26 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/platform/layout_unit.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
class NGConstraintSpace;
+class NGContainerFragmentBuilder;
class NGExclusionSpace;
struct NGPositionedFloat;
struct NGUnpositionedFloat;
+enum NGFloatTypeValue {
+ kFloatTypeNone = 0b00,
+ kFloatTypeLeft = 0b01,
+ kFloatTypeRight = 0b10,
+ kFloatTypeBoth = 0b11
+};
+typedef int NGFloatTypes;
+
// Returns the inline size (relative to {@code parent_space}) of the
// unpositioned float. If the float is in a different writing mode, this will
// perform a layout.
@@ -42,6 +52,15 @@ CORE_EXPORT const Vector<NGPositionedFloat> PositionFloats(
const NGConstraintSpace& space,
NGExclusionSpace* exclusion_space);
+// Add a pending float to the list. It will be committed (positioned) once we
+// have resolved the BFC offset.
+void AddUnpositionedFloat(
+ Vector<scoped_refptr<NGUnpositionedFloat>>* unpositioned_floats,
+ NGContainerFragmentBuilder* fragment_builder,
+ scoped_refptr<NGUnpositionedFloat> unpositioned_float);
+
+NGFloatTypes ToFloatTypes(EClear clear);
+
} // namespace blink
#endif // NGFloatsUtils_h
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc
index 93823b4247f..028a6d2283e 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_fragment_builder.cc
@@ -13,7 +13,6 @@
#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_break_token.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_physical_box_fragment.h"
@@ -285,7 +284,7 @@ scoped_refptr<NGLayoutResult> NGFragmentBuilder::ToBoxFragment() {
scoped_refptr<NGPhysicalBoxFragment> fragment =
base::AdoptRef(new NGPhysicalBoxFragment(
- layout_object_, Style(), physical_size, children_,
+ layout_object_, Style(), style_variant_, physical_size, children_,
padding_.ConvertToPhysical(GetWritingMode(), Direction())
.SnapToDevicePixels(),
contents_visual_rect, baselines_, BoxType(), is_old_layout_root_,
@@ -295,11 +294,10 @@ scoped_refptr<NGLayoutResult> NGFragmentBuilder::ToBoxFragment() {
return base::AdoptRef(new NGLayoutResult(
std::move(fragment), oof_positioned_descendants_, positioned_floats,
- unpositioned_floats_, unpositioned_list_marker_,
- std::move(exclusion_space_), bfc_offset_, end_margin_strut_,
- intrinsic_block_size_, minimal_space_shortage_, initial_break_before_,
- previous_break_after_, has_forced_break_, is_pushed_by_floats_,
- NGLayoutResult::kSuccess));
+ unpositioned_list_marker_, std::move(exclusion_space_), bfc_offset_,
+ end_margin_strut_, intrinsic_block_size_, minimal_space_shortage_,
+ initial_break_before_, previous_break_after_, has_forced_break_,
+ is_pushed_by_floats_, adjoining_floats_, NGLayoutResult::kSuccess));
}
scoped_refptr<NGLayoutResult> NGFragmentBuilder::Abort(
@@ -308,9 +306,9 @@ scoped_refptr<NGLayoutResult> NGFragmentBuilder::Abort(
Vector<NGPositionedFloat> positioned_floats;
return base::AdoptRef(new NGLayoutResult(
nullptr, oof_positioned_descendants, positioned_floats,
- unpositioned_floats_, NGUnpositionedListMarker(), nullptr, bfc_offset_,
- end_margin_strut_, LayoutUnit(), LayoutUnit(), EBreakBetween::kAuto,
- EBreakBetween::kAuto, false, false, status));
+ NGUnpositionedListMarker(), nullptr, bfc_offset_, end_margin_strut_,
+ LayoutUnit(), LayoutUnit(), EBreakBetween::kAuto, EBreakBetween::kAuto,
+ false, false, kFloatTypeNone, status));
}
// Finds FragmentPairs that define inline containing blocks.
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 e2c79e6241c..478b43e42d4 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
@@ -8,15 +8,14 @@
#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_physical_offset_rect.h"
-#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_rect.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_baseline.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"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+
namespace blink {
class NGPhysicalFragment;
@@ -40,8 +39,6 @@ class CORE_EXPORT NGFragmentBuilder final : public NGContainerFragmentBuilder {
~NGFragmentBuilder() override;
- using WeakBoxList = PersistentHeapLinkedHashSet<WeakMember<NGBlockNode>>;
-
NGFragmentBuilder& SetIntrinsicBlockSize(LayoutUnit);
NGFragmentBuilder& SetPadding(const NGBoxStrut&);
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_inline_layout_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_inline_layout_test.cc
index 03b89dc7989..4f94e8f7805 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_inline_layout_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_inline_layout_test.cc
@@ -3,8 +3,8 @@
// found in the LICENSE file.
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
+#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_node.h"
-#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_layout_result.h"
@@ -54,7 +54,9 @@ TEST_F(NGInlineLayoutTest, BlockWithSingleTextNode) {
EXPECT_TRUE(result);
String expected_text("Hello World!");
- EXPECT_EQ(expected_text, ToNGInlineNode(node.FirstChild()).Text(0, 12));
+ NGInlineNode first_child = ToNGInlineNode(node.FirstChild());
+ EXPECT_EQ(expected_text,
+ StringView(first_child.ItemsData(false).text_content, 0, 12));
}
TEST_F(NGInlineLayoutTest, BlockWithTextAndAtomicInline) {
@@ -80,7 +82,9 @@ TEST_F(NGInlineLayoutTest, BlockWithTextAndAtomicInline) {
String expected_text("Hello ");
expected_text.append(kObjectReplacementCharacter);
expected_text.append(".");
- EXPECT_EQ(expected_text, ToNGInlineNode(node.FirstChild()).Text(0, 8));
+ NGInlineNode first_child = ToNGInlineNode(node.FirstChild());
+ EXPECT_EQ(expected_text,
+ StringView(first_child.ItemsData(false).text_content, 0, 8));
// Delete the line box tree to avoid leaks in the test.
block_flow->DeleteLineBoxTree();
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 71f5fb54f7e..428255389d8 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
@@ -5,11 +5,11 @@
#ifndef NGLayoutAlgorithm_h
#define NGLayoutAlgorithm_h
+#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/ng/ng_constraint_space.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink {
@@ -56,8 +56,9 @@ class CORE_EXPORT NGLayoutAlgorithm {
// 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 Optional<MinMaxSize> ComputeMinMaxSize(const MinMaxSizeInput&) const {
- return WTF::nullopt;
+ virtual base::Optional<MinMaxSize> ComputeMinMaxSize(
+ const MinMaxSizeInput&) const {
+ return base::nullopt;
}
protected:
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 ced495d4277..63cb0d76d03 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
@@ -9,7 +9,6 @@
#include "third_party/blink/renderer/core/layout/min_max_size.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.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"
@@ -42,7 +41,8 @@ void AppendNodeToString(NGLayoutInputNode node,
}
if (node.IsInline()) {
- for (const NGInlineItem& inline_item : ToNGInlineNode(node).Items()) {
+ const auto& items = ToNGInlineNode(node).ItemsData(false).items;
+ for (const NGInlineItem& inline_item : items) {
string_builder->Append(indent_builder.ToString());
string_builder->Append(inline_item.ToString());
string_builder->Append("\n");
@@ -95,6 +95,10 @@ bool NGLayoutInputNode::IsListMarker() const {
return IsBlock() && box_->IsLayoutNGListMarker();
}
+bool NGLayoutInputNode::IsAnonymous() const {
+ return box_->IsAnonymous();
+}
+
bool NGLayoutInputNode::IsQuirkyContainer() const {
return box_->GetDocument().InQuirksMode() &&
(box_->IsBody() || box_->IsTableCell());
@@ -128,16 +132,18 @@ scoped_refptr<NGLayoutResult> NGLayoutInputNode::Layout(
}
MinMaxSize NGLayoutInputNode::ComputeMinMaxSize(
+ WritingMode writing_mode,
const MinMaxSizeInput& input,
const NGConstraintSpace* space) {
return IsInline() ? ToNGInlineNode(*this).ComputeMinMaxSize(input)
- : ToNGBlockNode(*this).ComputeMinMaxSize(input, space);
+ : ToNGBlockNode(*this).ComputeMinMaxSize(writing_mode,
+ input, space);
}
void NGLayoutInputNode::IntrinsicSize(
NGLogicalSize* default_intrinsic_size,
- Optional<LayoutUnit>* computed_inline_size,
- Optional<LayoutUnit>* computed_block_size,
+ base::Optional<LayoutUnit>* computed_inline_size,
+ base::Optional<LayoutUnit>* computed_block_size,
NGLogicalSize* aspect_ratio) const {
DCHECK(IsReplaced());
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 bdf26b58bc0..4ac0d3ec824 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
@@ -5,9 +5,10 @@
#ifndef NGLayoutInputNode_h
#define NGLayoutInputNode_h
+#include "base/optional.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/layout_unit.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
+#include "third_party/blink/renderer/platform/text/writing_mode.h"
namespace blink {
@@ -59,6 +60,7 @@ class CORE_EXPORT NGLayoutInputNode {
bool ShouldBeConsideredAsReplaced() const;
bool IsListItem() const;
bool IsListMarker() const;
+ bool IsAnonymous() const;
// If the node is a quirky container for margin collapsing, see:
// https://html.spec.whatwg.org/#margin-collapsing-quirks
@@ -70,7 +72,8 @@ class CORE_EXPORT NGLayoutInputNode {
// Performs layout on this input node, will return the layout result.
scoped_refptr<NGLayoutResult> Layout(const NGConstraintSpace&, NGBreakToken*);
- MinMaxSize ComputeMinMaxSize(const MinMaxSizeInput&,
+ MinMaxSize ComputeMinMaxSize(WritingMode,
+ const MinMaxSizeInput&,
const NGConstraintSpace* = nullptr);
// Returns intrinsic sizing information for replaced elements.
@@ -79,8 +82,8 @@ class CORE_EXPORT NGLayoutInputNode {
// computations: LayoutReplaced::IntrinsicSizingInfo,
// and LayoutReplaced::IntrinsicSize.
void IntrinsicSize(NGLogicalSize* default_intrinsic_size,
- Optional<LayoutUnit>* computed_inline_size,
- Optional<LayoutUnit>* computed_block_size,
+ base::Optional<LayoutUnit>* computed_inline_size,
+ base::Optional<LayoutUnit>* computed_block_size,
NGLogicalSize* aspect_ratio) const;
// Returns the next sibling.
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 724aec2a0fa..5982eb02b4c 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
@@ -9,7 +9,6 @@
#include "third_party/blink/renderer/core/layout/ng/exclusions/ng_exclusion_space.h"
#include "third_party/blink/renderer/core/layout/ng/ng_positioned_float.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
namespace blink {
@@ -17,10 +16,9 @@ NGLayoutResult::NGLayoutResult(
scoped_refptr<NGPhysicalFragment> physical_fragment,
Vector<NGOutOfFlowPositionedDescendant>& oof_positioned_descendants,
Vector<NGPositionedFloat>& positioned_floats,
- Vector<scoped_refptr<NGUnpositionedFloat>>& unpositioned_floats,
const NGUnpositionedListMarker& unpositioned_list_marker,
std::unique_ptr<const NGExclusionSpace> exclusion_space,
- const WTF::Optional<NGBfcOffset> bfc_offset,
+ const base::Optional<NGBfcOffset> bfc_offset,
const NGMarginStrut end_margin_strut,
const LayoutUnit intrinsic_block_size,
LayoutUnit minimal_space_shortage,
@@ -28,6 +26,7 @@ NGLayoutResult::NGLayoutResult(
EBreakBetween final_break_after,
bool has_forced_break,
bool is_pushed_by_floats,
+ NGFloatTypes adjoining_floats,
NGLayoutResultStatus status)
: physical_fragment_(std::move(physical_fragment)),
unpositioned_list_marker_(unpositioned_list_marker),
@@ -40,22 +39,20 @@ NGLayoutResult::NGLayoutResult(
final_break_after_(final_break_after),
has_forced_break_(has_forced_break),
is_pushed_by_floats_(is_pushed_by_floats),
+ adjoining_floats_(adjoining_floats),
status_(status) {
oof_positioned_descendants_.swap(oof_positioned_descendants);
positioned_floats_.swap(positioned_floats);
- unpositioned_floats_.swap(unpositioned_floats);
}
-// Keep the implementation of the destructor here, to avoid dependencies on
-// NGUnpositionedFloat in the header file.
+// Define the destructor here, so that we can forward-declare more in the
+// header.
NGLayoutResult::~NGLayoutResult() = default;
scoped_refptr<NGLayoutResult> NGLayoutResult::CloneWithoutOffset() const {
Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants(
oof_positioned_descendants_);
Vector<NGPositionedFloat> positioned_floats(positioned_floats_);
- Vector<scoped_refptr<NGUnpositionedFloat>> unpositioned_floats(
- unpositioned_floats_);
std::unique_ptr<const NGExclusionSpace> exclusion_space;
// TODO(layoutng) Replace this with DCHECK(exclusion_space_) when
// callers guarantee exclusion_space_ != null.
@@ -64,10 +61,10 @@ scoped_refptr<NGLayoutResult> NGLayoutResult::CloneWithoutOffset() const {
}
return base::AdoptRef(new NGLayoutResult(
physical_fragment_->CloneWithoutOffset(), oof_positioned_descendants,
- positioned_floats, unpositioned_floats, unpositioned_list_marker_,
- std::move(exclusion_space), bfc_offset_, end_margin_strut_,
- intrinsic_block_size_, minimal_space_shortage_, initial_break_before_,
- final_break_after_, has_forced_break_, is_pushed_by_floats_, Status()));
+ positioned_floats, unpositioned_list_marker_, std::move(exclusion_space),
+ bfc_offset_, end_margin_strut_, intrinsic_block_size_,
+ minimal_space_shortage_, initial_break_before_, final_break_after_,
+ has_forced_break_, is_pushed_by_floats_, adjoining_floats_, Status()));
}
} // namespace blink
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 9112e0d94b8..89aa6cce96a 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
@@ -10,6 +10,7 @@
#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/list/ng_unpositioned_list_marker.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_floats_utils.h"
#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_positioned_descendant.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
@@ -19,7 +20,6 @@ namespace blink {
class NGExclusionSpace;
struct NGPositionedFloat;
-struct NGUnpositionedFloat;
// The NGLayoutResult stores the resulting data from layout. This includes
// geometry information in form of a NGPhysicalFragment, which is kept around
@@ -59,18 +59,6 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
return positioned_floats_;
}
- // List of floats that need to be positioned by the next in-flow child that
- // can determine its position in space.
- // Use case example where it may be needed:
- // <div><float></div>
- // <div style="margin-top: 10px; height: 20px"></div>
- // The float cannot be positioned right away inside of the 1st div because
- // the vertical position is not known at that moment. It will be known only
- // after the 2nd div collapses its margin with its parent.
- const Vector<scoped_refptr<NGUnpositionedFloat>>& UnpositionedFloats() const {
- return unpositioned_floats_;
- }
-
const NGUnpositionedListMarker& UnpositionedListMarker() const {
return unpositioned_list_marker_;
}
@@ -83,7 +71,7 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
return static_cast<NGLayoutResultStatus>(status_);
}
- const WTF::Optional<NGBfcOffset>& BfcOffset() const { return bfc_offset_; }
+ const base::Optional<NGBfcOffset>& BfcOffset() const { return bfc_offset_; }
const NGMarginStrut EndMarginStrut() const { return end_margin_strut_; }
@@ -109,40 +97,48 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
// of floats.
bool IsPushedByFloats() const { return is_pushed_by_floats_; }
+ // Return the types (none, left, right, both) of preceding adjoining
+ // floats. These are floats that are added while the in-flow BFC offset is
+ // still unknown. The floats may or may not be unpositioned (pending). That
+ // depends on which layout pass we're in. Adjoining floats should be treated
+ // differently when calculating clearance on a block with adjoining
+ // block-start margin (in such cases we will know up front that the block will
+ // need clearance, since, if it doesn't, the float will be pulled along with
+ // the block, and the block will fail to clear).
+ NGFloatTypes AdjoiningFloatTypes() const { return adjoining_floats_; }
+
scoped_refptr<NGLayoutResult> CloneWithoutOffset() const;
private:
friend class NGFragmentBuilder;
friend class NGLineBoxFragmentBuilder;
- NGLayoutResult(
- scoped_refptr<NGPhysicalFragment> physical_fragment,
- Vector<NGOutOfFlowPositionedDescendant>&
- out_of_flow_positioned_descendants,
- Vector<NGPositionedFloat>& positioned_floats,
- Vector<scoped_refptr<NGUnpositionedFloat>>& unpositioned_floats,
- const NGUnpositionedListMarker& unpositioned_list_marker,
- std::unique_ptr<const NGExclusionSpace> exclusion_space,
- const WTF::Optional<NGBfcOffset> bfc_offset,
- const NGMarginStrut end_margin_strut,
- const LayoutUnit intrinsic_block_size,
- LayoutUnit minimal_space_shortage,
- EBreakBetween initial_break_before,
- EBreakBetween final_break_after,
- bool has_forced_break,
- bool is_pushed_by_floats,
- NGLayoutResultStatus status);
+ NGLayoutResult(scoped_refptr<NGPhysicalFragment> physical_fragment,
+ Vector<NGOutOfFlowPositionedDescendant>&
+ out_of_flow_positioned_descendants,
+ Vector<NGPositionedFloat>& positioned_floats,
+ const NGUnpositionedListMarker& unpositioned_list_marker,
+ std::unique_ptr<const NGExclusionSpace> exclusion_space,
+ const base::Optional<NGBfcOffset> bfc_offset,
+ const NGMarginStrut end_margin_strut,
+ const LayoutUnit intrinsic_block_size,
+ LayoutUnit minimal_space_shortage,
+ EBreakBetween initial_break_before,
+ EBreakBetween final_break_after,
+ bool has_forced_break,
+ bool is_pushed_by_floats,
+ NGFloatTypes adjoining_floats,
+ NGLayoutResultStatus status);
scoped_refptr<NGPhysicalFragment> physical_fragment_;
Vector<NGOutOfFlowPositionedDescendant> oof_positioned_descendants_;
Vector<NGPositionedFloat> positioned_floats_;
- Vector<scoped_refptr<NGUnpositionedFloat>> unpositioned_floats_;
NGUnpositionedListMarker unpositioned_list_marker_;
const std::unique_ptr<const NGExclusionSpace> exclusion_space_;
- const WTF::Optional<NGBfcOffset> bfc_offset_;
+ const base::Optional<NGBfcOffset> bfc_offset_;
const NGMarginStrut end_margin_strut_;
const LayoutUnit intrinsic_block_size_;
const LayoutUnit minimal_space_shortage_;
@@ -153,6 +149,7 @@ class CORE_EXPORT NGLayoutResult : public RefCounted<NGLayoutResult> {
unsigned has_forced_break_ : 1;
unsigned is_pushed_by_floats_ : 1;
+ unsigned adjoining_floats_ : 2; // NGFloatTypes
unsigned status_ : 1;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_test.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_test.h
index 40a8ffb3f48..7f881af1fa1 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_test.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_test.h
@@ -7,7 +7,6 @@
#include "third_party/blink/renderer/core/frame/local_frame_client.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
namespace blink {
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
new file mode 100644
index 00000000000..029a7e4bcef
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.cc
@@ -0,0 +1,23 @@
+// 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/ng_layout_utils.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"
+
+namespace blink {
+
+bool IsBlockLayoutComplete(const NGConstraintSpace& space,
+ const NGLayoutResult& result) {
+ if (result.Status() != NGLayoutResult::kSuccess)
+ return false;
+ if (space.IsIntermediateLayout())
+ return false;
+ // Check that we're done positioning pending floats.
+ return !result.AdjoiningFloatTypes() || result.BfcOffset() ||
+ space.FloatsBfcOffset();
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.h
new file mode 100644
index 00000000000..f93fc5e8f43
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_layout_utils.h
@@ -0,0 +1,21 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_LAYOUT_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_LAYOUT_UTILS_H_
+
+namespace blink {
+
+class NGConstraintSpace;
+class NGLayoutResult;
+
+// Return true if layout is considered complete. In some cases we require more
+// than one layout pass.
+// This function never considers intermediate layouts
+// (space,IsIntermediateLayout()) to be complete.
+bool IsBlockLayoutComplete(const NGConstraintSpace&, const NGLayoutResult&);
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_LAYOUT_UTILS_H_
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 d9e42256902..06afd4f1d9f 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
@@ -5,19 +5,17 @@
#include "third_party/blink/renderer/core/layout/ng/ng_length_utils.h"
#include <algorithm>
+#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_table_cell.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/core/layout/ng/ng_constraint_space_builder.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/layout_unit.h"
#include "third_party/blink/renderer/platform/length.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink {
-// TODO(layout-ng):
-// - replaced calculations
-// - Take scrollbars into account
bool NeedMinMaxSize(const NGConstraintSpace& constraint_space,
const ComputedStyle& style) {
@@ -33,18 +31,30 @@ bool NeedMinMaxSize(const ComputedStyle& style) {
style.LogicalMaxWidth().IsIntrinsic();
}
-bool NeedMinMaxSizeForContentContribution(const ComputedStyle& style) {
- return style.LogicalWidth().IsIntrinsicOrAuto() ||
- style.LogicalMinWidth().IsIntrinsic() ||
- style.LogicalMaxWidth().IsIntrinsic();
+bool NeedMinMaxSizeForContentContribution(WritingMode mode,
+ const ComputedStyle& style) {
+ // During the intrinsic sizes pass percentages/calc() are defined to behave
+ // like 'auto'. As a result we need to calculate the intrinsic sizes for any
+ // children with percentages. E.g.
+ // <div style="float:left;">
+ // <div style="width:30%;">text text</div>
+ // </div>
+ if (mode == WritingMode::kHorizontalTb) {
+ return style.Width().IsIntrinsicOrAuto() ||
+ style.Width().IsPercentOrCalc() || style.MinWidth().IsIntrinsic() ||
+ style.MaxWidth().IsIntrinsic();
+ }
+ return style.Height().IsIntrinsicOrAuto() ||
+ style.Height().IsPercentOrCalc() || style.MinHeight().IsIntrinsic() ||
+ style.MaxHeight().IsIntrinsic();
}
LayoutUnit ResolveInlineLength(const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
- const WTF::Optional<MinMaxSize>& min_and_max,
+ const base::Optional<MinMaxSize>& min_and_max,
const Length& length,
- LengthResolveType type) {
- DCHECK(!length.IsMaxSizeNone());
+ LengthResolveType type,
+ LengthResolvePhase phase) {
DCHECK_GE(constraint_space.AvailableSize().inline_size, LayoutUnit());
DCHECK_GE(constraint_space.PercentageResolutionSize().inline_size,
LayoutUnit());
@@ -53,12 +63,29 @@ LayoutUnit ResolveInlineLength(const NGConstraintSpace& constraint_space,
if (constraint_space.IsAnonymous())
return constraint_space.AvailableSize().inline_size;
+ if (length.IsMaxSizeNone()) {
+ DCHECK_EQ(type, LengthResolveType::kMaxSize);
+ return LayoutUnit::Max();
+ }
+
NGBoxStrut border_and_padding = ComputeBorders(constraint_space, style) +
ComputePadding(constraint_space, style);
if (type == LengthResolveType::kMinSize && length.IsAuto())
return border_and_padding.InlineSum();
+ // Check if we shouldn't resolve a percentage/calc() if we are in the
+ // intrinsic sizes phase.
+ if (phase == LengthResolvePhase::kIntrinsic && length.IsPercentOrCalc()) {
+ // min-width/min-height should be "0", i.e. no min limit is applied.
+ if (type == LengthResolveType::kMinSize)
+ return border_and_padding.InlineSum();
+
+ // max-width/max-height becomes "infinity", i.e. no max limit is applied.
+ if (type == LengthResolveType::kMaxSize)
+ return LayoutUnit::Max();
+ }
+
switch (length.GetType()) {
case kAuto:
case kFillAvailable: {
@@ -116,27 +143,16 @@ LayoutUnit ResolveBlockLength(const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
const Length& length,
LayoutUnit content_size,
- LengthResolveType type) {
- DCHECK(!length.IsMaxSizeNone());
+ LengthResolveType type,
+ LengthResolvePhase phase) {
DCHECK_EQ(constraint_space.GetWritingMode(), style.GetWritingMode());
if (constraint_space.IsAnonymous())
return content_size;
- if (length.IsPercentOrCalc() &&
- constraint_space.PercentageResolutionSize().block_size ==
- NGSizeIndefinite) {
- // We're unable to resolve this percentage, since there's nothing to resolve
- // it against. Height/width becomes 'auto', so we can just return the
- // content size. Min-height/min-width becomes 0. Max-height/max-width
- // becomes 'none', which means that we shouldn't impose any max limit, so
- // return "infinity".
- if (type == LengthResolveType::kContentSize)
- return content_size;
- if (type == LengthResolveType::kMaxSize)
- return LayoutUnit::Max();
- DCHECK_EQ(type, LengthResolveType::kMinSize);
- return LayoutUnit();
+ if (length.IsMaxSizeNone()) {
+ DCHECK_EQ(type, LengthResolveType::kMaxSize);
+ return LayoutUnit::Max();
}
NGBoxStrut border_and_padding = ComputeBorders(constraint_space, style) +
@@ -145,6 +161,28 @@ LayoutUnit ResolveBlockLength(const NGConstraintSpace& constraint_space,
if (type == LengthResolveType::kMinSize && length.IsAuto())
return border_and_padding.BlockSum();
+ bool is_percentage_indefinite =
+ constraint_space.PercentageResolutionSize().block_size ==
+ NGSizeIndefinite;
+
+ // Check if we can't/shouldn't resolve a percentage/calc() - because the
+ // percentage resolution size is indefinite or because we are in the
+ // intrinsic sizes phase.
+ if ((phase == LengthResolvePhase::kIntrinsic || is_percentage_indefinite) &&
+ length.IsPercentOrCalc()) {
+ // min-width/min-height should be "0", i.e. no min limit is applied.
+ if (type == LengthResolveType::kMinSize)
+ return border_and_padding.BlockSum();
+
+ // max-width/max-height becomes "infinity", i.e. no max limit is applied.
+ if (type == LengthResolveType::kMaxSize)
+ return LayoutUnit::Max();
+
+ // width/height becomes "auto", so we can just return the content size.
+ DCHECK_EQ(type, LengthResolveType::kContentSize);
+ return content_size;
+ }
+
switch (length.GetType()) {
case kFillAvailable: {
LayoutUnit content_size = constraint_space.AvailableSize().block_size;
@@ -224,49 +262,109 @@ LayoutUnit ResolveMarginPaddingLength(const NGConstraintSpace& constraint_space,
}
MinMaxSize ComputeMinAndMaxContentContribution(
+ WritingMode writing_mode,
const ComputedStyle& style,
- const WTF::Optional<MinMaxSize>& min_and_max) {
+ const base::Optional<MinMaxSize>& min_and_max) {
// Synthesize a zero-sized constraint space for passing to
// ResolveInlineLength.
- WritingMode writing_mode = style.GetWritingMode();
+ // The constraint space's writing mode has to match the style, so we can't
+ // use the passed-in mode here.
NGConstraintSpaceBuilder builder(
- writing_mode,
+ style.GetWritingMode(),
/* icb_size */ {NGSizeIndefinite, NGSizeIndefinite});
scoped_refptr<NGConstraintSpace> space =
- builder.ToConstraintSpace(writing_mode);
+ builder.ToConstraintSpace(style.GetWritingMode());
+
+ LayoutUnit content_size =
+ min_and_max ? min_and_max->max_size : NGSizeIndefinite;
MinMaxSize computed_sizes;
- Length inline_size = style.LogicalWidth();
- if (inline_size.IsAuto()) {
+ Length inline_size = writing_mode == WritingMode::kHorizontalTb
+ ? style.Width()
+ : style.Height();
+ if (inline_size.IsAuto() || inline_size.IsPercentOrCalc()) {
CHECK(min_and_max.has_value());
computed_sizes = *min_and_max;
} else {
- computed_sizes.min_size = computed_sizes.max_size =
- ResolveInlineLength(*space, style, min_and_max, inline_size,
- LengthResolveType::kContentSize);
+ if (IsParallelWritingMode(writing_mode, style.GetWritingMode())) {
+ computed_sizes.min_size = computed_sizes.max_size = ResolveInlineLength(
+ *space, style, min_and_max, inline_size,
+ LengthResolveType::kContentSize, LengthResolvePhase::kIntrinsic);
+ } else {
+ computed_sizes.min_size = computed_sizes.max_size = ResolveBlockLength(
+ *space, style, inline_size, content_size,
+ LengthResolveType::kContentSize, LengthResolvePhase::kIntrinsic);
+ }
}
- Length max_length = style.LogicalMaxWidth();
- if (!max_length.IsMaxSizeNone()) {
- LayoutUnit max = ResolveInlineLength(*space, style, min_and_max, max_length,
- LengthResolveType::kMaxSize);
- computed_sizes.min_size = std::min(computed_sizes.min_size, max);
- computed_sizes.max_size = std::min(computed_sizes.max_size, max);
+ Length max_length = writing_mode == WritingMode::kHorizontalTb
+ ? style.MaxWidth()
+ : style.MaxHeight();
+ LayoutUnit max;
+ if (IsParallelWritingMode(writing_mode, style.GetWritingMode())) {
+ max = ResolveInlineLength(*space, style, min_and_max, max_length,
+ LengthResolveType::kMaxSize,
+ LengthResolvePhase::kIntrinsic);
+ } else {
+ max = ResolveBlockLength(*space, style, max_length, content_size,
+ LengthResolveType::kMaxSize,
+ LengthResolvePhase::kIntrinsic);
+ }
+ computed_sizes.min_size = std::min(computed_sizes.min_size, max);
+ computed_sizes.max_size = std::min(computed_sizes.max_size, max);
+
+ Length min_length = writing_mode == WritingMode::kHorizontalTb
+ ? style.MinWidth()
+ : style.MinHeight();
+ LayoutUnit min;
+ if (IsParallelWritingMode(writing_mode, style.GetWritingMode())) {
+ min = ResolveInlineLength(*space, style, min_and_max, min_length,
+ LengthResolveType::kMinSize,
+ LengthResolvePhase::kIntrinsic);
+ } else {
+ min = ResolveBlockLength(*space, style, min_length, content_size,
+ LengthResolveType::kMinSize,
+ LengthResolvePhase::kIntrinsic);
}
-
- LayoutUnit min =
- ResolveInlineLength(*space, style, min_and_max, style.LogicalMinWidth(),
- LengthResolveType::kMinSize);
computed_sizes.min_size = std::max(computed_sizes.min_size, min);
computed_sizes.max_size = std::max(computed_sizes.max_size, min);
return computed_sizes;
}
+MinMaxSize ComputeMinAndMaxContentContribution(
+ WritingMode writing_mode,
+ NGLayoutInputNode node,
+ const MinMaxSizeInput& input,
+ const NGConstraintSpace* constraint_space) {
+ base::Optional<MinMaxSize> minmax;
+ if (NeedMinMaxSizeForContentContribution(writing_mode, node.Style())) {
+ scoped_refptr<NGConstraintSpace> adjusted_constraint_space;
+ if (constraint_space) {
+ // TODO(layout-ng): Check if our constraint space produces spec-compliant
+ // outputs.
+ // It is important to set a floats bfc offset so that we don't get a
+ // partial layout. It is also important that we shrink to fit, by
+ // definition.
+ NGConstraintSpaceBuilder builder(*constraint_space);
+ builder.SetAvailableSize(constraint_space->AvailableSize())
+ .SetFloatsBfcOffset(NGBfcOffset())
+ .SetIsShrinkToFit(true);
+ adjusted_constraint_space =
+ builder.ToConstraintSpace(node.Style().GetWritingMode());
+ constraint_space = adjusted_constraint_space.get();
+ }
+ minmax = node.ComputeMinMaxSize(writing_mode, input, constraint_space);
+ }
+
+ return ComputeMinAndMaxContentContribution(writing_mode, node.Style(),
+ minmax);
+}
+
LayoutUnit ComputeInlineSizeForFragment(
const NGConstraintSpace& space,
const ComputedStyle& style,
- const WTF::Optional<MinMaxSize>& min_and_max) {
+ const base::Optional<MinMaxSize>& min_and_max) {
if (space.IsFixedSizeInline())
return space.AvailableSize().inline_size;
@@ -274,20 +372,17 @@ LayoutUnit ComputeInlineSizeForFragment(
if (logical_width.IsAuto() && space.IsShrinkToFit())
logical_width = Length(kFitContent);
- LayoutUnit extent =
- ResolveInlineLength(space, style, min_and_max, logical_width,
- LengthResolveType::kContentSize);
-
- Optional<LayoutUnit> max_length;
- if (!style.LogicalMaxWidth().IsMaxSizeNone()) {
- max_length =
- ResolveInlineLength(space, style, min_and_max, style.LogicalMaxWidth(),
- LengthResolveType::kMaxSize);
- }
- Optional<LayoutUnit> min_length =
- ResolveInlineLength(space, style, min_and_max, style.LogicalMinWidth(),
- LengthResolveType::kMinSize);
- return ConstrainByMinMax(extent, min_length, max_length);
+ LayoutUnit extent = ResolveInlineLength(
+ space, style, min_and_max, logical_width, LengthResolveType::kContentSize,
+ LengthResolvePhase::kLayout);
+
+ LayoutUnit max = ResolveInlineLength(
+ space, style, min_and_max, style.LogicalMaxWidth(),
+ LengthResolveType::kMaxSize, LengthResolvePhase::kLayout);
+ LayoutUnit min = ResolveInlineLength(
+ space, style, min_and_max, style.LogicalMinWidth(),
+ LengthResolveType::kMinSize, LengthResolvePhase::kLayout);
+ return ConstrainByMinMax(extent, min, max);
}
LayoutUnit ComputeBlockSizeForFragment(
@@ -298,39 +393,39 @@ LayoutUnit ComputeBlockSizeForFragment(
return constraint_space.AvailableSize().block_size;
if (style.Display() == EDisplay::kTableCell) {
- // All handled by the table layout code or not applicable
+ // All handled by the table layout code or not applicable.
return content_size;
}
- LayoutUnit extent =
- ResolveBlockLength(constraint_space, style, style.LogicalHeight(),
- content_size, LengthResolveType::kContentSize);
+ LayoutUnit extent = ResolveBlockLength(
+ constraint_space, style, style.LogicalHeight(), content_size,
+ LengthResolveType::kContentSize, LengthResolvePhase::kLayout);
if (extent == NGSizeIndefinite) {
DCHECK_EQ(content_size, NGSizeIndefinite);
return extent;
}
- Optional<LayoutUnit> max_length;
- if (!style.LogicalMaxHeight().IsMaxSizeNone()) {
- max_length =
- ResolveBlockLength(constraint_space, style, style.LogicalMaxHeight(),
- content_size, LengthResolveType::kMaxSize);
- }
- Optional<LayoutUnit> min_length =
- ResolveBlockLength(constraint_space, style, style.LogicalMinHeight(),
- content_size, LengthResolveType::kMinSize);
- return ConstrainByMinMax(extent, min_length, max_length);
+
+ LayoutUnit max = ResolveBlockLength(
+ constraint_space, style, style.LogicalMaxHeight(), content_size,
+ LengthResolveType::kMaxSize, LengthResolvePhase::kLayout);
+ LayoutUnit min = ResolveBlockLength(
+ constraint_space, style, style.LogicalMinHeight(), content_size,
+ LengthResolveType::kMinSize, LengthResolvePhase::kLayout);
+
+ return ConstrainByMinMax(extent, min, max);
}
// Computes size for a replaced element.
-NGLogicalSize ComputeReplacedSize(const NGLayoutInputNode& node,
- const NGConstraintSpace& space,
- const Optional<MinMaxSize>& child_minmax) {
+NGLogicalSize ComputeReplacedSize(
+ const NGLayoutInputNode& node,
+ const NGConstraintSpace& space,
+ const base::Optional<MinMaxSize>& child_minmax) {
DCHECK(node.IsReplaced());
NGLogicalSize replaced_size;
NGLogicalSize default_intrinsic_size;
- Optional<LayoutUnit> computed_inline_size;
- Optional<LayoutUnit> computed_block_size;
+ base::Optional<LayoutUnit> computed_inline_size;
+ base::Optional<LayoutUnit> computed_block_size;
NGLogicalSize aspect_ratio;
node.IntrinsicSize(&default_intrinsic_size, &computed_inline_size,
@@ -354,16 +449,16 @@ NGLogicalSize ComputeReplacedSize(const NGLayoutInputNode& node,
} else {
// inline_size is computed from block_size.
replaced_size.inline_size =
- ResolveBlockLength(space, style, block_length,
- default_intrinsic_size.block_size,
- LengthResolveType::kContentSize) *
+ ResolveBlockLength(
+ space, style, block_length, default_intrinsic_size.block_size,
+ LengthResolveType::kContentSize, LengthResolvePhase::kLayout) *
aspect_ratio.inline_size / aspect_ratio.block_size;
}
} else {
// inline_size is resolved directly.
- replaced_size.inline_size =
- ResolveInlineLength(space, style, child_minmax, inline_length,
- LengthResolveType::kContentSize);
+ replaced_size.inline_size = ResolveInlineLength(
+ space, style, child_minmax, inline_length,
+ LengthResolveType::kContentSize, LengthResolvePhase::kLayout);
}
// Compute block size
@@ -381,13 +476,14 @@ NGLogicalSize ComputeReplacedSize(const NGLayoutInputNode& node,
// block_size is computed from inline_size.
replaced_size.block_size =
ResolveInlineLength(space, style, child_minmax, inline_length,
- LengthResolveType::kContentSize) *
+ LengthResolveType::kContentSize,
+ LengthResolvePhase::kLayout) *
aspect_ratio.block_size / aspect_ratio.inline_size;
}
} else {
replaced_size.block_size = ResolveBlockLength(
space, style, block_length, default_intrinsic_size.block_size,
- LengthResolveType::kContentSize);
+ LengthResolveType::kContentSize, LengthResolvePhase::kLayout);
}
return replaced_size;
}
@@ -600,7 +696,8 @@ void ApplyAutoMargins(const ComputedStyle& style,
LayoutUnit LineOffsetForTextAlign(ETextAlign text_align,
TextDirection direction,
- LayoutUnit space_left) {
+ LayoutUnit space_left,
+ LayoutUnit trailing_spaces_width) {
bool is_ltr = IsLtr(direction);
if (text_align == ETextAlign::kStart || text_align == ETextAlign::kJustify)
text_align = is_ltr ? ETextAlign::kLeft : ETextAlign::kRight;
@@ -619,19 +716,25 @@ LayoutUnit LineOffsetForTextAlign(ETextAlign text_align,
}
case ETextAlign::kRight:
case ETextAlign::kWebkitRight: {
+ // In RTL, trailing spaces appear on the left of the line.
+ if (UNLIKELY(!is_ltr))
+ return space_left - trailing_spaces_width;
// Wide lines spill out of the block based off direction.
// So even if text-align is right, if direction is LTR, wide lines
// should overflow out of the right side of the block.
- if (space_left > LayoutUnit() || !is_ltr)
+ if (space_left > LayoutUnit())
return space_left;
return LayoutUnit();
}
case ETextAlign::kCenter:
case ETextAlign::kWebkitCenter: {
- if (is_ltr || space_left > LayoutUnit())
+ if (is_ltr)
return (space_left / 2).ClampNegativeToZero();
+ // In RTL, trailing spaces appear on the left of the line.
+ if (space_left > LayoutUnit())
+ return (space_left / 2).ClampNegativeToZero() - trailing_spaces_width;
// In RTL, wide lines should spill out to the left, same as kRight.
- return space_left;
+ return space_left - trailing_spaces_width;
}
default:
NOTREACHED();
@@ -640,13 +743,9 @@ LayoutUnit LineOffsetForTextAlign(ETextAlign text_align,
}
LayoutUnit ConstrainByMinMax(LayoutUnit length,
- Optional<LayoutUnit> min,
- Optional<LayoutUnit> max) {
- if (max && length > max.value())
- length = max.value();
- if (min && length < min.value())
- length = min.value();
- return length;
+ LayoutUnit min,
+ LayoutUnit max) {
+ return std::max(min, std::min(length, max));
}
NGBoxStrut CalculateBorderScrollbarPadding(
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 7512770abf2..2960d4236fe 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
@@ -5,6 +5,7 @@
#ifndef NGLengthUtils_h
#define NGLengthUtils_h
+#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/ng/geometry/ng_box_strut.h"
@@ -12,15 +13,25 @@
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/text/writing_mode.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink {
class ComputedStyle;
class Length;
+struct MinMaxSizeInput;
class NGConstraintSpace;
class NGBlockNode;
class NGLayoutInputNode;
+// LengthResolvePhase indicates what type of layout pass we are currently in.
+// This changes how lengths are resolved. kIntrinsic must be used during the
+// intrinsic sizes pass, and kLayout must be used during the layout pass.
+enum class LengthResolvePhase { kIntrinsic, kLayout };
+
+// LengthResolveType indicates what type length the function is being passed
+// based on its CSS property. E.g.
+// kMinSize - min-width / min-height
+// kMaxSize - max-width / max-height
+// kContentSize - width / height
enum class LengthResolveType { kMinSize, kMaxSize, kContentSize };
// Whether the caller needs to compute min-content and max-content sizes to
@@ -33,15 +44,20 @@ CORE_EXPORT bool NeedMinMaxSize(const ComputedStyle&);
// Like NeedMinMaxSize, but for use when calling
// ComputeMinAndMaxContentContribution.
-CORE_EXPORT bool NeedMinMaxSizeForContentContribution(const ComputedStyle&);
+// Because content contributions are commonly needed by a block's parent,
+// we also take a writing mode here so we can check this in the parent's
+// coordinate system.
+CORE_EXPORT bool NeedMinMaxSizeForContentContribution(WritingMode mode,
+ const ComputedStyle&);
// Convert an inline-axis length to a layout unit using the given constraint
// space.
CORE_EXPORT LayoutUnit ResolveInlineLength(const NGConstraintSpace&,
const ComputedStyle&,
- const WTF::Optional<MinMaxSize>&,
+ const base::Optional<MinMaxSize>&,
const Length&,
- LengthResolveType);
+ LengthResolveType,
+ LengthResolvePhase);
// Convert a block-axis length to a layout unit using the given constraint
// space and content size.
@@ -49,7 +65,8 @@ CORE_EXPORT LayoutUnit ResolveBlockLength(const NGConstraintSpace&,
const ComputedStyle&,
const Length&,
LayoutUnit content_size,
- LengthResolveType);
+ LengthResolveType,
+ LengthResolvePhase);
// Convert margin/border/padding length to a layout unit using the
// given constraint space.
@@ -63,9 +80,28 @@ CORE_EXPORT LayoutUnit ResolveMarginPaddingLength(const NGConstraintSpace&,
// to zero) and that an auto inline size resolves to the respective min/max
// content size.
// Also, the min/max contribution does include the inline margins as well.
+// 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
-ComputeMinAndMaxContentContribution(const ComputedStyle&,
- const WTF::Optional<MinMaxSize>&);
+ComputeMinAndMaxContentContribution(WritingMode writing_mode,
+ const ComputedStyle&,
+ const base::Optional<MinMaxSize>&);
+
+// A version of ComputeMinAndMaxContentContribution that does not require you
+// to compute the min/max content size of the node. Instead, this function
+// will compute it if necessary.
+// writing_mode is the desired output writing mode (ie. often the writing mode
+// of the parent); node is the node of which to compute the min/max content
+// contribution.
+// If a constraint space is provided, this function will convert it to the
+// correct writing mode and otherwise make sure it is suitable for computing
+// the desired value.
+MinMaxSize ComputeMinAndMaxContentContribution(
+ WritingMode writing_mode,
+ NGLayoutInputNode node,
+ const MinMaxSizeInput& input,
+ const NGConstraintSpace* space = nullptr);
// Resolves the given length to a layout unit, constraining it by the min
// logical width and max logical width properties from the ComputedStyle
@@ -73,7 +109,7 @@ ComputeMinAndMaxContentContribution(const ComputedStyle&,
CORE_EXPORT LayoutUnit
ComputeInlineSizeForFragment(const NGConstraintSpace&,
const ComputedStyle&,
- const WTF::Optional<MinMaxSize>&);
+ const base::Optional<MinMaxSize>&);
// Resolves the given length to a layout unit, constraining it by the min
// logical height and max logical height properties from the ComputedStyle
@@ -83,9 +119,10 @@ CORE_EXPORT LayoutUnit ComputeBlockSizeForFragment(const NGConstraintSpace&,
LayoutUnit content_size);
// Computes intrinsic size for replaced elements.
-CORE_EXPORT NGLogicalSize ComputeReplacedSize(const NGLayoutInputNode&,
- const NGConstraintSpace&,
- const Optional<MinMaxSize>&);
+CORE_EXPORT NGLogicalSize
+ComputeReplacedSize(const NGLayoutInputNode&,
+ const NGConstraintSpace&,
+ const base::Optional<MinMaxSize>&);
// Based on available inline size, CSS computed column-width, CSS computed
// column-count and CSS used column-gap, return CSS used column-count.
@@ -150,11 +187,12 @@ CORE_EXPORT void ApplyAutoMargins(const ComputedStyle& child_style,
// text-align, direction and amount of unused space.
CORE_EXPORT LayoutUnit LineOffsetForTextAlign(ETextAlign,
TextDirection,
- LayoutUnit space_left);
+ LayoutUnit space_left,
+ LayoutUnit trailing_spaces_width);
CORE_EXPORT LayoutUnit ConstrainByMinMax(LayoutUnit length,
- Optional<LayoutUnit> min,
- Optional<LayoutUnit> max);
+ LayoutUnit min,
+ LayoutUnit max);
NGBoxStrut CalculateBorderScrollbarPadding(
const NGConstraintSpace& constraint_space,
@@ -163,7 +201,7 @@ NGBoxStrut CalculateBorderScrollbarPadding(
inline NGLogicalSize CalculateBorderBoxSize(
const NGConstraintSpace& constraint_space,
const ComputedStyle& style,
- const Optional<MinMaxSize>& min_and_max,
+ const base::Optional<MinMaxSize>& min_and_max,
LayoutUnit block_content_size = NGSizeIndefinite) {
return NGLogicalSize(
ComputeInlineSizeForFragment(constraint_space, style, min_and_max),
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 5297591b7bb..63dbcd82766 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,21 +41,23 @@ class NGLengthUtilsTest : public testing::Test {
LayoutUnit ResolveInlineLength(
const Length& length,
LengthResolveType type = LengthResolveType::kContentSize,
- const WTF::Optional<MinMaxSize>& sizes = WTF::nullopt) {
+ LengthResolvePhase phase = LengthResolvePhase::kLayout,
+ const base::Optional<MinMaxSize>& sizes = base::nullopt) {
scoped_refptr<NGConstraintSpace> constraint_space =
ConstructConstraintSpace(200, 300);
return ::blink::ResolveInlineLength(*constraint_space, *style_, sizes,
- length, type);
+ length, type, phase);
}
LayoutUnit ResolveBlockLength(
const Length& length,
LengthResolveType type = LengthResolveType::kContentSize,
+ LengthResolvePhase phase = LengthResolvePhase::kLayout,
LayoutUnit content_size = LayoutUnit()) {
scoped_refptr<NGConstraintSpace> constraint_space =
ConstructConstraintSpace(200, 300);
return ::blink::ResolveBlockLength(*constraint_space, *style_, length,
- content_size, type);
+ content_size, type, phase);
}
LayoutUnit ComputeInlineSizeForFragment(
@@ -81,30 +83,39 @@ TEST_F(NGLengthUtilsTest, testResolveInlineLength) {
EXPECT_EQ(LayoutUnit(60), ResolveInlineLength(Length(30, kPercent)));
EXPECT_EQ(LayoutUnit(150), ResolveInlineLength(Length(150, kFixed)));
EXPECT_EQ(LayoutUnit(0),
- ResolveInlineLength(Length(kAuto), LengthResolveType::kMinSize));
+ ResolveInlineLength(Length(kAuto), LengthResolveType::kMinSize,
+ LengthResolvePhase::kIntrinsic));
EXPECT_EQ(LayoutUnit(200), ResolveInlineLength(Length(kAuto)));
EXPECT_EQ(LayoutUnit(200), ResolveInlineLength(Length(kFillAvailable)));
- EXPECT_EQ(LayoutUnit(200),
- ResolveInlineLength(Length(kAuto), LengthResolveType::kMaxSize));
- EXPECT_EQ(LayoutUnit(200), ResolveInlineLength(Length(kFillAvailable),
- LengthResolveType::kMaxSize));
+ EXPECT_EQ(
+ LayoutUnit::Max(),
+ ResolveInlineLength(Length(30, kPercent), LengthResolveType::kMaxSize,
+ LengthResolvePhase::kIntrinsic));
+ EXPECT_EQ(
+ LayoutUnit(200),
+ ResolveInlineLength(Length(kFillAvailable), LengthResolveType::kMaxSize,
+ LengthResolvePhase::kIntrinsic));
MinMaxSize sizes;
sizes.min_size = LayoutUnit(30);
sizes.max_size = LayoutUnit(40);
- EXPECT_EQ(LayoutUnit(30),
- ResolveInlineLength(Length(kMinContent),
- LengthResolveType::kContentSize, sizes));
- EXPECT_EQ(LayoutUnit(40),
- ResolveInlineLength(Length(kMaxContent),
- LengthResolveType::kContentSize, sizes));
- EXPECT_EQ(LayoutUnit(40),
- ResolveInlineLength(Length(kFitContent),
- LengthResolveType::kContentSize, sizes));
+ EXPECT_EQ(
+ LayoutUnit(30),
+ ResolveInlineLength(Length(kMinContent), LengthResolveType::kContentSize,
+ LengthResolvePhase::kLayout, sizes));
+ EXPECT_EQ(
+ LayoutUnit(40),
+ ResolveInlineLength(Length(kMaxContent), LengthResolveType::kContentSize,
+ LengthResolvePhase::kLayout, sizes));
+ EXPECT_EQ(
+ LayoutUnit(40),
+ ResolveInlineLength(Length(kFitContent), LengthResolveType::kContentSize,
+ LengthResolvePhase::kLayout, sizes));
sizes.max_size = LayoutUnit(800);
- EXPECT_EQ(LayoutUnit(200),
- ResolveInlineLength(Length(kFitContent),
- LengthResolveType::kContentSize, sizes));
+ EXPECT_EQ(
+ LayoutUnit(200),
+ ResolveInlineLength(Length(kFitContent), LengthResolveType::kContentSize,
+ LengthResolvePhase::kLayout, sizes));
#if DCHECK_IS_ON()
// This should fail a DCHECK.
@@ -118,11 +129,8 @@ TEST_F(NGLengthUtilsTest, testResolveBlockLength) {
EXPECT_EQ(LayoutUnit(0), ResolveBlockLength(Length(kAuto)));
EXPECT_EQ(LayoutUnit(300), ResolveBlockLength(Length(kFillAvailable)));
- EXPECT_EQ(LayoutUnit(0),
- ResolveBlockLength(Length(kAuto), LengthResolveType::kContentSize));
- EXPECT_EQ(LayoutUnit(300),
- ResolveBlockLength(Length(kFillAvailable),
- LengthResolveType::kContentSize));
+ EXPECT_EQ(LayoutUnit(0), ResolveBlockLength(Length(kAuto)));
+ EXPECT_EQ(LayoutUnit(300), ResolveBlockLength(Length(kFillAvailable)));
}
TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
@@ -130,43 +138,51 @@ TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
sizes.min_size = LayoutUnit(30);
sizes.max_size = LayoutUnit(40);
- MinMaxSize expected{LayoutUnit(), LayoutUnit()};
+ MinMaxSize expected = sizes;
style_->SetLogicalWidth(Length(30, kPercent));
- EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(*style_, sizes));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes));
+ expected = MinMaxSize{LayoutUnit(), LayoutUnit()};
style_->SetLogicalWidth(Length(kFillAvailable));
- EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(*style_, sizes));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes));
expected = MinMaxSize{LayoutUnit(150), LayoutUnit(150)};
style_->SetLogicalWidth(Length(150, kFixed));
- EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(*style_, sizes));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes));
expected = sizes;
style_->SetLogicalWidth(Length(kAuto));
- EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(*style_, sizes));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes));
expected = MinMaxSize{LayoutUnit(430), LayoutUnit(440)};
style_->SetPaddingLeft(Length(400, kFixed));
auto sizes_padding400 = sizes;
sizes_padding400 += LayoutUnit(400);
- EXPECT_EQ(expected,
- ComputeMinAndMaxContentContribution(*style_, sizes_padding400));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes_padding400));
- expected = MinMaxSize{LayoutUnit(100), LayoutUnit(100)};
+ expected = MinMaxSize{LayoutUnit(30), LayoutUnit(40)};
style_->SetPaddingLeft(Length(0, kFixed));
style_->SetLogicalWidth(Length(CalculationValue::Create(
PixelsAndPercent(100, -10), kValueRangeNonNegative)));
- EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(*style_, sizes));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes));
expected = MinMaxSize{LayoutUnit(30), LayoutUnit(35)};
style_->SetLogicalWidth(Length(kAuto));
style_->SetMaxWidth(Length(35, kFixed));
- EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(*style_, sizes));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes));
expected = MinMaxSize{LayoutUnit(80), LayoutUnit(80)};
style_->SetLogicalWidth(Length(50, kFixed));
style_->SetMinWidth(Length(80, kFixed));
- EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(*style_, sizes));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes));
expected = MinMaxSize{LayoutUnit(150), LayoutUnit(150)};
style_ = ComputedStyle::Create();
@@ -174,35 +190,36 @@ TEST_F(NGLengthUtilsTest, testComputeContentContribution) {
style_->SetPaddingLeft(Length(50, kFixed));
auto sizes_padding50 = sizes;
sizes_padding50 += LayoutUnit(50);
- EXPECT_EQ(expected,
- ComputeMinAndMaxContentContribution(*style_, sizes_padding50));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes_padding50));
expected = MinMaxSize{LayoutUnit(100), LayoutUnit(100)};
style_->SetBoxSizing(EBoxSizing::kBorderBox);
- EXPECT_EQ(expected,
- ComputeMinAndMaxContentContribution(*style_, sizes_padding50));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes_padding50));
// Content size should never be below zero, even with box-sizing: border-box
// and a large padding...
expected = MinMaxSize{LayoutUnit(400), LayoutUnit(400)};
style_->SetPaddingLeft(Length(400, kFixed));
- EXPECT_EQ(expected,
- ComputeMinAndMaxContentContribution(*style_, sizes_padding400));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes_padding400));
expected.min_size = expected.max_size = sizes.min_size + LayoutUnit(400);
style_->SetLogicalWidth(Length(kMinContent));
- EXPECT_EQ(expected,
- ComputeMinAndMaxContentContribution(*style_, sizes_padding400));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes_padding400));
style_->SetLogicalWidth(Length(100, kFixed));
style_->SetMaxWidth(Length(kMaxContent));
// 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)};
- EXPECT_EQ(expected,
- ComputeMinAndMaxContentContribution(*style_, sizes_padding400));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes_padding400));
expected = MinMaxSize{LayoutUnit(40), LayoutUnit(40)};
style_->SetPaddingLeft(Length(0, kFixed));
- EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(*style_, sizes));
+ EXPECT_EQ(expected, ComputeMinAndMaxContentContribution(
+ style_->GetWritingMode(), *style_, sizes));
}
TEST_F(NGLengthUtilsTest, testComputeInlineSizeForFragment) {
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 25983fe0dcb..bd18926e320 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
@@ -8,11 +8,12 @@
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_line_box_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_absolute_utils.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_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_fragment_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_positioned_descendant.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
@@ -299,8 +300,8 @@ scoped_refptr<NGLayoutResult> NGOutOfFlowLayoutPart::LayoutDescendant(
.SetAvailableSize(container_info.content_size)
.SetPercentageResolutionSize(container_info.content_size)
.ToConstraintSpace(descendant_writing_mode);
- Optional<MinMaxSize> min_max_size;
- Optional<LayoutUnit> block_estimate;
+ base::Optional<MinMaxSize> min_max_size;
+ base::Optional<LayoutUnit> block_estimate;
scoped_refptr<NGLayoutResult> layout_result = nullptr;
@@ -311,11 +312,11 @@ scoped_refptr<NGLayoutResult> NGOutOfFlowLayoutPart::LayoutDescendant(
// This is a new formatting context, so whatever happened on the outside
// doesn't concern us.
MinMaxSizeInput zero_input;
- min_max_size =
- node.ComputeMinMaxSize(zero_input, descendant_constraint_space.get());
+ min_max_size = node.ComputeMinMaxSize(descendant_writing_mode, zero_input,
+ descendant_constraint_space.get());
}
- Optional<NGLogicalSize> replaced_size;
+ base::Optional<NGLogicalSize> replaced_size;
if (descendant.node.IsReplaced()) {
replaced_size = ComputeReplacedSize(
descendant.node, *descendant_constraint_space, min_max_size);
@@ -396,7 +397,7 @@ bool NGOutOfFlowLayoutPart::IsContainingBlockForDescendant(
scoped_refptr<NGLayoutResult> NGOutOfFlowLayoutPart::GenerateFragment(
NGBlockNode descendant,
const ContainingBlockInfo& container_info,
- const Optional<LayoutUnit>& block_estimate,
+ const base::Optional<LayoutUnit>& block_estimate,
const NGAbsolutePhysicalPosition node_position) {
// As the block_estimate is always in the descendant's writing mode, we build
// the constraint space in the descendant's writing mode.
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 9f6eeb3faee..d5e0f691fe6 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
@@ -7,17 +7,20 @@
#include "third_party/blink/renderer/core/core_export.h"
+#include "base/optional.h"
+#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset.h"
#include "third_party/blink/renderer/core/layout/ng/ng_absolute_utils.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_constraint_space.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
namespace blink {
class ComputedStyle;
+class LayoutObject;
class NGBlockNode;
class NGFragmentBuilder;
class NGConstraintSpace;
class NGLayoutResult;
+struct NGOutOfFlowPositionedDescendant;
// Helper class for positioning of out-of-flow blocks.
// It should be used together with NGFragmentBuilder.
@@ -79,7 +82,7 @@ class CORE_EXPORT NGOutOfFlowLayoutPart {
scoped_refptr<NGLayoutResult> GenerateFragment(
NGBlockNode node,
const ContainingBlockInfo&,
- const Optional<LayoutUnit>& block_estimate,
+ const base::Optional<LayoutUnit>& block_estimate,
const NGAbsolutePhysicalPosition node_position);
NGFragmentBuilder* container_builder_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
index c75b25b64ef..1fcbcd9b8dc 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part_test.cc
@@ -4,7 +4,8 @@
#include "third_party/blink/renderer/core/layout/ng/ng_out_of_flow_layout_part.h"
-#include "third_party/blink/renderer/core/layout/ng/layout_ng_block_flow.h"
+#include "third_party/blink/renderer/core/layout/layout_block_flow.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/layout/ng/ng_layout_test.h"
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
new file mode 100644
index 00000000000..f6b4a7edc95
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.cc
@@ -0,0 +1,69 @@
+// 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/ng_outline_utils.h"
+
+#include "third_party/blink/renderer/core/layout/ng/inline/ng_inline_fragment_traversal.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
+#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
+
+namespace blink {
+
+class LayoutObject;
+
+void NGOutlineUtils::CollectDescendantOutlines(
+ const NGPhysicalBoxFragment& container,
+ const NGPhysicalOffset& paint_offset,
+ FragmentMap* anchor_fragment_map,
+ OutlineRectMap* outline_rect_map) {
+ DCHECK(anchor_fragment_map->IsEmpty());
+ DCHECK(outline_rect_map->IsEmpty());
+ if (!container.ChildrenInline())
+ return;
+ for (auto& descendant : NGInlineFragmentTraversal::DescendantsOf(container)) {
+ if (!descendant.fragment->IsBox() || descendant.fragment->IsAtomicInline())
+ continue;
+
+ const ComputedStyle& descendant_style = descendant.fragment->Style();
+ if (!descendant_style.HasOutline() ||
+ descendant_style.Visibility() != EVisibility::kVisible)
+ continue;
+ if (descendant_style.OutlineStyleIsAuto() &&
+ !LayoutTheme::GetTheme().ShouldDrawDefaultFocusRing(
+ descendant.fragment->GetNode(), descendant_style))
+ continue;
+
+ const LayoutObject* layout_object = descendant.fragment->GetLayoutObject();
+ Vector<LayoutRect>* outline_rects;
+ auto iter = outline_rect_map->find(layout_object);
+ if (iter == outline_rect_map->end()) {
+ anchor_fragment_map->insert(layout_object, descendant.fragment.get());
+ outline_rects =
+ &outline_rect_map->insert(layout_object, Vector<LayoutRect>())
+ .stored_value->value;
+ } else {
+ outline_rects = &iter->value;
+ }
+ NGPhysicalOffsetRect outline(
+ paint_offset + descendant.offset_to_container_box,
+ descendant.fragment->Size());
+ outline_rects->push_back(outline.ToLayoutRect());
+ }
+}
+
+NGPhysicalOffsetRect NGOutlineUtils::ComputeEnclosingOutline(
+ const ComputedStyle& style,
+ const Vector<LayoutRect>& outlines) {
+ LayoutRect combined_outline;
+ for (auto& outline : outlines) {
+ combined_outline.Unite(outline);
+ }
+ combined_outline.Inflate(style.OutlineOffset() + style.OutlineWidth());
+ return NGPhysicalOffsetRect(
+ NGPhysicalOffset(combined_outline.X(), combined_outline.Y()),
+ NGPhysicalSize(combined_outline.Width(), combined_outline.Height()));
+}
+
+} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.h
new file mode 100644
index 00000000000..d225d11947d
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_outline_utils.h
@@ -0,0 +1,42 @@
+// 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.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_OUTLINE_UTILS_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_OUTLINE_UTILS_H_
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/wtf/hash_map.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
+
+namespace blink {
+
+class ComputedStyle;
+class LayoutObject;
+class LayoutRect;
+class NGPhysicalFragment;
+class NGPhysicalBoxFragment;
+struct NGPhysicalOffset;
+struct NGPhysicalOffsetRect;
+
+class CORE_EXPORT NGOutlineUtils {
+ STATIC_ONLY(NGOutlineUtils);
+
+ public:
+ using FragmentMap = HashMap<const LayoutObject*, const NGPhysicalFragment*>;
+ using OutlineRectMap = HashMap<const LayoutObject*, Vector<LayoutRect>>;
+
+ static void CollectDescendantOutlines(const NGPhysicalBoxFragment& container,
+ const NGPhysicalOffset& paint_offset,
+ FragmentMap* anchor_fragment_map,
+ OutlineRectMap* outline_rect_map);
+
+ // Union of all outline rectangles, including outline thickness.
+ static NGPhysicalOffsetRect ComputeEnclosingOutline(
+ const ComputedStyle& style,
+ const Vector<LayoutRect>& outlines);
+};
+
+} // namespace blink
+
+#endif // THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_OUTLINE_UTILS_H_
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 7e86fa919c1..110e07f58f9 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
@@ -12,6 +12,7 @@
#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/style/computed_style.h"
namespace blink {
@@ -21,7 +22,7 @@ NGPageLayoutAlgorithm::NGPageLayoutAlgorithm(NGBlockNode node,
: NGLayoutAlgorithm(node, space, ToNGBlockBreakToken(break_token)) {}
scoped_refptr<NGLayoutResult> NGPageLayoutAlgorithm::Layout() {
- Optional<MinMaxSize> min_max_size;
+ base::Optional<MinMaxSize> min_max_size;
if (NeedMinMaxSize(ConstraintSpace(), Style()))
min_max_size = ComputeMinMaxSize(MinMaxSizeInput());
NGBoxStrut border_scrollbar_padding =
@@ -84,7 +85,7 @@ scoped_refptr<NGLayoutResult> NGPageLayoutAlgorithm::Layout() {
return container_builder_.ToBoxFragment();
}
-Optional<MinMaxSize> NGPageLayoutAlgorithm::ComputeMinMaxSize(
+base::Optional<MinMaxSize> NGPageLayoutAlgorithm::ComputeMinMaxSize(
const MinMaxSizeInput& input) const {
NGBlockLayoutAlgorithm algorithm(Node(), ConstraintSpace());
return algorithm.ComputeMinMaxSize(input);
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 a8f4c406da8..86f0d67b003 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
@@ -28,7 +28,8 @@ class CORE_EXPORT NGPageLayoutAlgorithm
scoped_refptr<NGLayoutResult> Layout() override;
- Optional<MinMaxSize> ComputeMinMaxSize(const MinMaxSizeInput&) const override;
+ base::Optional<MinMaxSize> ComputeMinMaxSize(
+ const MinMaxSizeInput&) const override;
private:
scoped_refptr<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 16c291542fa..ff2e044f2f5 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
@@ -5,15 +5,19 @@
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
-#include "third_party/blink/renderer/core/layout/layout_block.h"
#include "third_party/blink/renderer/core/layout/layout_box.h"
#include "third_party/blink/renderer/core/layout/layout_object.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"
+#include "third_party/blink/renderer/core/layout/ng/ng_outline_utils.h"
namespace blink {
NGPhysicalBoxFragment::NGPhysicalBoxFragment(
LayoutObject* layout_object,
const ComputedStyle& style,
+ NGStyleVariant style_variant,
NGPhysicalSize size,
Vector<scoped_refptr<NGPhysicalFragment>>& children,
const NGPixelSnappedPhysicalBoxStrut& padding,
@@ -25,6 +29,7 @@ NGPhysicalBoxFragment::NGPhysicalBoxFragment(
scoped_refptr<NGBreakToken> break_token)
: NGPhysicalContainerFragment(layout_object,
style,
+ style_variant,
size,
kFragmentBox,
box_type,
@@ -36,6 +41,21 @@ NGPhysicalBoxFragment::NGPhysicalBoxFragment(
DCHECK(baselines.IsEmpty()); // Ensure move semantics is used.
is_old_layout_root_ = is_old_layout_root;
border_edge_ = border_edges;
+
+ // Compute visual contribution from descendant outlines.
+ NGOutlineUtils::FragmentMap anchor_fragment_map;
+ NGOutlineUtils::OutlineRectMap outline_rect_map;
+ NGOutlineUtils::CollectDescendantOutlines(
+ *this, NGPhysicalOffset(), &anchor_fragment_map, &outline_rect_map);
+ for (auto& anchor_iter : anchor_fragment_map) {
+ const NGPhysicalFragment* fragment = anchor_iter.value;
+ Vector<LayoutRect>* outline_rects =
+ &outline_rect_map.find(anchor_iter.key)->value;
+ descendant_outlines_.Unite(NGOutlineUtils::ComputeEnclosingOutline(
+ fragment->Style(), *outline_rects));
+ }
+ GetLayoutObject()->SetOutlineMayBeAffectedByDescendants(
+ !descendant_outlines_.IsEmpty());
}
const NGBaseline* NGPhysicalBoxFragment::Baseline(
@@ -73,34 +93,74 @@ bool NGPhysicalBoxFragment::ShouldClipOverflow() const {
ToLayoutBox(layout_object)->ShouldClipOverflow();
}
-NGPhysicalOffsetRect NGPhysicalBoxFragment::SelfVisualRect() const {
- const ComputedStyle& style = Style();
- if (!style.HasVisualOverflowingEffect())
- return {{}, Size()};
+LayoutRect NGPhysicalBoxFragment::OverflowClipRect(
+ const LayoutPoint& location,
+ OverlayScrollbarClipBehavior overlay_scrollbar_clip_behavior) const {
+ DCHECK(GetLayoutObject() && GetLayoutObject()->IsBox());
+ const LayoutBox* box = ToLayoutBox(GetLayoutObject());
+ return box->OverflowClipRect(location, overlay_scrollbar_clip_behavior);
+}
+NGPhysicalOffsetRect NGPhysicalBoxFragment::ScrollableOverflow() const {
+ DCHECK(GetLayoutObject());
LayoutObject* layout_object = GetLayoutObject();
- DCHECK(layout_object);
if (layout_object->IsBox()) {
- LayoutRect visual_rect({}, Size().ToLayoutSize());
- visual_rect.Expand(style.BoxDecorationOutsets());
-
- if (style.HasOutline()) {
- Vector<LayoutRect> outline_rects;
- // The result rects are in coordinates of this object's border box.
- AddSelfOutlineRects(&outline_rects, LayoutPoint());
- LayoutRect rect = UnionRectEvenIfEmpty(outline_rects);
- rect.Inflate(style.OutlineOutsetExtent());
- visual_rect.Unite(rect);
+ if (HasOverflowClip())
+ return NGPhysicalOffsetRect({}, Size());
+ // Legacy is the source of truth for overflow
+ return NGPhysicalOffsetRect(
+ ToLayoutBox(layout_object)->LayoutOverflowRect());
+ } else if (layout_object->IsLayoutInline()) {
+ // Inline overflow is a union of child overflows.
+ NGPhysicalOffsetRect overflow({}, Size());
+ for (const auto& child_fragment : Children()) {
+ NGPhysicalOffsetRect child_overflow =
+ child_fragment->ScrollableOverflow();
+ child_overflow.offset += child_fragment->Offset();
+ overflow.Unite(child_overflow);
}
-
- return NGPhysicalOffsetRect(visual_rect);
+ return overflow;
+ } else {
+ NOTREACHED();
}
+ return NGPhysicalOffsetRect({}, Size());
+}
+
+IntSize NGPhysicalBoxFragment::ScrolledContentOffset() const {
+ DCHECK(GetLayoutObject() && GetLayoutObject()->IsBox());
+ const LayoutBox* box = ToLayoutBox(GetLayoutObject());
+ return box->ScrolledContentOffset();
+}
+
+LayoutSize NGPhysicalBoxFragment::ScrollSize() const {
+ DCHECK(GetLayoutObject() && GetLayoutObject()->IsBox());
+ const LayoutBox* box = ToLayoutBox(GetLayoutObject());
+ return LayoutSize(box->ScrollWidth(), box->ScrollHeight());
+}
- // TODO(kojii): Implement for inline boxes.
- DCHECK(layout_object->IsLayoutInline());
+NGPhysicalOffsetRect NGPhysicalBoxFragment::SelfVisualRect() const {
+ const ComputedStyle& style = Style();
LayoutRect visual_rect({}, Size().ToLayoutSize());
- visual_rect.Expand(style.BoxDecorationOutsets());
+ DCHECK(GetLayoutObject());
+ if (style.HasVisualOverflowingEffect()) {
+ if (GetLayoutObject()->IsBox()) {
+ visual_rect.Expand(style.BoxDecorationOutsets());
+ if (style.HasOutline()) {
+ Vector<LayoutRect> outline_rects;
+ // The result rects are in coordinates of this object's border box.
+ AddSelfOutlineRects(&outline_rects, LayoutPoint());
+ LayoutRect rect = UnionRectEvenIfEmpty(outline_rects);
+ rect.Inflate(style.OutlineOutsetExtent());
+ visual_rect.Unite(rect);
+ }
+ } else {
+ // TODO(kojii): Implement for inline boxes.
+ DCHECK(GetLayoutObject()->IsLayoutInline());
+ visual_rect.Expand(style.BoxDecorationOutsets());
+ }
+ }
+ visual_rect.Unite(descendant_outlines_.ToLayoutRect());
return NGPhysicalOffsetRect(visual_rect);
}
@@ -108,19 +168,51 @@ void NGPhysicalBoxFragment::AddSelfOutlineRects(
Vector<LayoutRect>* outline_rects,
const LayoutPoint& additional_offset) const {
DCHECK(outline_rects);
- // TODO(kojii): Implement. This is quite incomplete yet.
-
- // bool include_block_visual_overflow =
- // layout_object->OutlineRectsShouldIncludeBlockVisualOverflow();
- //
LayoutRect outline_rect(additional_offset, Size().ToLayoutSize());
- // LayoutRect outline_rect = VisualRect();
- // outline_rect.MoveBy(additional_offset);
- // outline_rect.Inflate(-Style().OutlineOffset());
- // outline_rect.Inflate(-Style().OutlineWidth());
-
outline_rects->push_back(outline_rect);
+
+ DCHECK(GetLayoutObject());
+ if (!GetLayoutObject()->IsBox())
+ return;
+ if (!Style().OutlineStyleIsAuto() || GetLayoutObject()->HasOverflowClip() ||
+ ToLayoutBox(GetLayoutObject())->HasControlClip())
+ return;
+
+ // Focus outline includes chidlren
+ for (const auto& child : Children()) {
+ // List markers have no outline
+ if (child->IsListMarker())
+ continue;
+
+ if (child->IsLineBox()) {
+ // Traverse children of the linebox
+ Vector<NGPhysicalFragmentWithOffset> line_children =
+ NGInlineFragmentTraversal::DescendantsOf(
+ ToNGPhysicalLineBoxFragment(*child));
+ for (const auto& line_child : line_children) {
+ Vector<LayoutRect> line_child_rects;
+ line_child_rects.push_back(
+ line_child.RectInContainerBox().ToLayoutRect());
+ DCHECK(line_child.fragment->GetLayoutObject());
+ line_child.fragment->GetLayoutObject()->LocalToAncestorRects(
+ line_child_rects, ToLayoutBoxModelObject(GetLayoutObject()),
+ child->Offset().ToLayoutPoint(), additional_offset);
+ if (!line_child_rects.IsEmpty())
+ outline_rects->push_back(line_child_rects[0]);
+ }
+ } else {
+ DCHECK(child->GetLayoutObject());
+ LayoutObject* child_layout = child->GetLayoutObject();
+ Vector<LayoutRect> child_rects;
+ child_rects.push_back(child->VisualRectWithContents().ToLayoutRect());
+ child_layout->LocalToAncestorRects(
+ child_rects, ToLayoutBoxModelObject(GetLayoutObject()), LayoutPoint(),
+ additional_offset);
+ if (!child_rects.IsEmpty())
+ outline_rects->push_back(child_rects[0]);
+ }
+ }
}
NGPhysicalOffsetRect NGPhysicalBoxFragment::VisualRectWithContents() const {
@@ -132,12 +224,19 @@ NGPhysicalOffsetRect NGPhysicalBoxFragment::VisualRectWithContents() const {
return visual_rect;
}
-PositionWithAffinity NGPhysicalBoxFragment::PositionForPoint(
- const NGPhysicalOffset& point) const {
- if (!IsBlockFlow())
- return PositionForPointInInlineLevelBox(point);
-
- return PositionForPointInInlineFormattingContext(point);
+UBiDiLevel NGPhysicalBoxFragment::BidiLevel() const {
+ // TODO(xiaochengh): Make the implementation more efficient.
+ DCHECK(IsInline());
+ DCHECK(IsAtomicInline());
+ const auto& inline_items = InlineItemsOfContainingBlock();
+ const NGInlineItem* self_item =
+ std::find_if(inline_items.begin(), inline_items.end(),
+ [this](const NGInlineItem& item) {
+ return GetLayoutObject() == item.GetLayoutObject();
+ });
+ DCHECK(self_item);
+ DCHECK_NE(self_item, inline_items.end());
+ return self_item->BidiLevel();
}
scoped_refptr<NGPhysicalFragment> NGPhysicalBoxFragment::CloneWithoutOffset()
@@ -146,9 +245,9 @@ scoped_refptr<NGPhysicalFragment> NGPhysicalBoxFragment::CloneWithoutOffset()
Vector<NGBaseline> baselines_copy(baselines_);
scoped_refptr<NGPhysicalFragment> physical_fragment =
base::AdoptRef(new NGPhysicalBoxFragment(
- layout_object_, Style(), size_, children_copy, padding_,
- contents_visual_rect_, baselines_copy, BoxType(), is_old_layout_root_,
- border_edge_, break_token_));
+ layout_object_, Style(), StyleVariant(), size_, children_copy,
+ padding_, contents_visual_rect_, baselines_copy, BoxType(),
+ is_old_layout_root_, border_edge_, break_token_));
return physical_fragment;
}
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 6bc38d92972..f2f8a3b88c7 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
@@ -9,6 +9,7 @@
#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/ng_physical_container_fragment.h"
+#include "third_party/blink/renderer/platform/scroll/scroll_types.h"
namespace blink {
@@ -18,6 +19,7 @@ class CORE_EXPORT NGPhysicalBoxFragment final
// This modifies the passed-in children vector.
NGPhysicalBoxFragment(LayoutObject* layout_object,
const ComputedStyle& style,
+ NGStyleVariant style_variant,
NGPhysicalSize size,
Vector<scoped_refptr<NGPhysicalFragment>>& children,
const NGPixelSnappedPhysicalBoxStrut& padding,
@@ -40,6 +42,17 @@ class CORE_EXPORT NGPhysicalBoxFragment final
bool HasOverflowClip() const;
bool ShouldClipOverflow() const;
+ NGPhysicalOffsetRect ScrollableOverflow() const;
+
+ // TODO(layout-dev): These three methods delegate to legacy layout for now,
+ // update them to use LayoutNG based overflow information from the fragment
+ // and change them to use NG geometry types once LayoutNG supports overflow.
+ LayoutRect OverflowClipRect(
+ const LayoutPoint& location,
+ OverlayScrollbarClipBehavior = kIgnorePlatformOverlayScrollbarSize) const;
+ IntSize ScrolledContentOffset() const;
+ LayoutSize ScrollSize() const;
+
// Visual rect of this box in the local coordinate. Does not include children
// even if they overflow this box.
NGPhysicalOffsetRect SelfVisualRect() const;
@@ -50,13 +63,14 @@ class CORE_EXPORT NGPhysicalBoxFragment final
void AddSelfOutlineRects(Vector<LayoutRect>*,
const LayoutPoint& additional_offset) const;
- PositionWithAffinity PositionForPoint(const NGPhysicalOffset&) const override;
+ UBiDiLevel BidiLevel() const override;
scoped_refptr<NGPhysicalFragment> CloneWithoutOffset() const;
private:
Vector<NGBaseline> baselines_;
NGPixelSnappedPhysicalBoxStrut padding_;
+ NGPhysicalOffsetRect descendant_outlines_;
};
DEFINE_TYPE_CASTS(NGPhysicalBoxFragment,
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 8d5989cba0f..d0b66f10ea9 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
@@ -4,7 +4,6 @@
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/ng/ng_layout_test.h"
namespace blink {
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 bd925dd85e1..3c6fe5fbb87 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
@@ -4,57 +4,12 @@
#include "third_party/blink/renderer/core/layout/ng/ng_physical_container_fragment.h"
-#include "third_party/blink/renderer/core/editing/position_with_affinity.h"
-#include "third_party/blink/renderer/core/layout/layout_object.h"
-#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h"
-#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.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_fragment.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
-#include "third_party/blink/renderer/core/style/computed_style.h"
-
namespace blink {
-namespace {
-
-NGLogicalOffset ChildLogicalOffsetInParent(
- const NGPhysicalContainerFragment& parent,
- const NGPhysicalFragment& child) {
- return child.Offset().ConvertToLogical(parent.Style().GetWritingMode(),
- parent.Style().Direction(),
- parent.Size(), child.Size());
-}
-
-NGLogicalSize ChildLogicalSizeInParent(
- const NGPhysicalContainerFragment& parent,
- const NGPhysicalFragment& child) {
- return NGFragment(parent.Style().GetWritingMode(), child).Size();
-}
-
-Optional<PositionWithAffinity> PositionForPointInChild(
- const NGPhysicalFragment& child,
- const NGPhysicalOffset& point) {
- const NGPhysicalOffset& child_point = point - child.Offset();
- // 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.
- const PositionWithAffinity result =
- (child.IsBlockFlow() || child.IsOldLayoutRoot())
- ? child.GetLayoutObject()->PositionForPoint(
- child_point.ToLayoutPoint())
- : child.PositionForPoint(child_point);
- if (result.IsNotNull())
- return result;
- return WTF::nullopt;
-}
-
-} // namespace
-
NGPhysicalContainerFragment::NGPhysicalContainerFragment(
LayoutObject* layout_object,
const ComputedStyle& style,
+ NGStyleVariant style_variant,
NGPhysicalSize size,
NGFragmentType type,
unsigned sub_type,
@@ -63,7 +18,7 @@ NGPhysicalContainerFragment::NGPhysicalContainerFragment(
scoped_refptr<NGBreakToken> break_token)
: NGPhysicalFragment(layout_object,
style,
- NGStyleVariant::kStandard,
+ style_variant,
size,
type,
sub_type,
@@ -73,154 +28,4 @@ NGPhysicalContainerFragment::NGPhysicalContainerFragment(
DCHECK(children.IsEmpty()); // Ensure move semantics is used.
}
-PositionWithAffinity
-NGPhysicalContainerFragment::PositionForPointInInlineLevelBox(
- const NGPhysicalOffset& point) const {
- DCHECK(IsInline() || IsLineBox()) << ToString();
- DCHECK(!IsBlockFlow()) << ToString();
-
- const NGLogicalOffset logical_point = point.ConvertToLogical(
- Style().GetWritingMode(), Style().Direction(), Size(), NGPhysicalSize());
- const LayoutUnit inline_point = logical_point.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.
- const NGPhysicalFragment* closest_child_before = nullptr;
- 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.
- const NGPhysicalFragment* closest_child_after = nullptr;
- LayoutUnit closest_child_after_inline_offset = LayoutUnit::Max();
-
- for (const auto& child : children_) {
- const LayoutUnit child_inline_min =
- ChildLogicalOffsetInParent(*this, *child).inline_offset;
- const LayoutUnit child_inline_max =
- child_inline_min + ChildLogicalSizeInParent(*this, *child).inline_size;
-
- // Try to resolve if |point| falls in any child in inline direction.
- if (inline_point >= child_inline_min && inline_point <= child_inline_max) {
- if (auto child_position = PositionForPointInChild(*child, point))
- return child_position.value();
- continue;
- }
-
- if (inline_point < child_inline_min) {
- if (child_inline_min < closest_child_after_inline_offset) {
- closest_child_after = child.get();
- closest_child_after_inline_offset = child_inline_min;
- }
- }
-
- if (inline_point > child_inline_max) {
- if (child_inline_max > closest_child_before_inline_offset) {
- closest_child_before = child.get();
- closest_child_before_inline_offset = child_inline_max;
- }
- }
- }
-
- if (closest_child_after) {
- if (auto child_position =
- PositionForPointInChild(*closest_child_after, point))
- return child_position.value();
- }
-
- if (closest_child_before) {
- if (auto child_position =
- PositionForPointInChild(*closest_child_before, point))
- return child_position.value();
- }
-
- return PositionWithAffinity();
-}
-
-PositionWithAffinity
-NGPhysicalContainerFragment::PositionForPointInInlineFormattingContext(
- const NGPhysicalOffset& point) const {
- DCHECK(IsBlockFlow()) << ToString();
- DCHECK(IsBox()) << ToString();
- DCHECK(ToNGPhysicalBoxFragment(this)->ChildrenInline()) << ToString();
-
- const NGLogicalOffset logical_point = point.ConvertToLogical(
- Style().GetWritingMode(), Style().Direction(), Size(), NGPhysicalSize());
- const LayoutUnit block_point = logical_point.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.
- const NGPhysicalLineBoxFragment* closest_line_before = nullptr;
- 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.
- const NGPhysicalLineBoxFragment* closest_line_after = nullptr;
- LayoutUnit closest_line_after_block_offset = LayoutUnit::Max();
-
- for (const auto& child : children_) {
- // Try to resolve if |point| falls in a non-line-box child completely.
- if (!child->IsLineBox()) {
- if (point.left >= child->Offset().left &&
- point.left <= child->Offset().left + child->Size().width &&
- point.top >= child->Offset().top &&
- point.top <= child->Offset().top + child->Size().height) {
- if (auto child_position = PositionForPointInChild(*child, point))
- return child_position.value();
- }
- continue;
- }
-
- if (!child->IsLineBox() ||
- ToNGPhysicalLineBoxFragment(*child).Children().IsEmpty())
- continue;
-
- const LayoutUnit line_min =
- ChildLogicalOffsetInParent(*this, *child).block_offset;
- const LayoutUnit line_max =
- line_min + ChildLogicalSizeInParent(*this, *child).block_size;
-
- // Try to resolve if |point| falls in a line box in block direction.
- // Hitting on line bottom doesn't count, to match legacy behavior.
- // TODO(xiaochengh): Consider floats.
- if (block_point >= line_min && block_point < line_max) {
- if (auto child_position = PositionForPointInChild(*child, point))
- return child_position.value();
- continue;
- }
-
- if (block_point < line_min) {
- if (line_min < closest_line_after_block_offset) {
- closest_line_after = ToNGPhysicalLineBoxFragment(child.get());
- closest_line_after_block_offset = line_min;
- }
- }
-
- if (block_point >= line_max) {
- if (line_max > closest_line_before_block_offset) {
- closest_line_before = ToNGPhysicalLineBoxFragment(child.get());
- closest_line_before_block_offset = line_max;
- }
- }
- }
-
- if (closest_line_after) {
- if (auto child_position =
- PositionForPointInChild(*closest_line_after, point))
- return child_position.value();
- }
-
- if (closest_line_before) {
- if (auto child_position =
- PositionForPointInChild(*closest_line_before, point))
- return child_position.value();
- }
-
- // TODO(xiaochengh): Looking at only the closest lines may not be enough,
- // when we have multiple lines full of pseudo elements. Fix it.
-
- // TODO(xiaochengh): Consider floats.
-
- return PositionWithAffinity();
-}
-
} // namespace blink
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 be57b677a45..4d80ac63b5b 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
@@ -7,8 +7,8 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h"
-#include "third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
@@ -28,6 +28,7 @@ class CORE_EXPORT NGPhysicalContainerFragment : public NGPhysicalFragment {
NGPhysicalContainerFragment(
LayoutObject*,
const ComputedStyle&,
+ NGStyleVariant,
NGPhysicalSize,
NGFragmentType,
unsigned sub_type,
@@ -35,11 +36,6 @@ class CORE_EXPORT NGPhysicalContainerFragment : public NGPhysicalFragment {
const NGPhysicalOffsetRect& contents_visual_rect,
scoped_refptr<NGBreakToken> = nullptr);
- PositionWithAffinity PositionForPointInInlineLevelBox(
- const NGPhysicalOffset&) const;
- PositionWithAffinity PositionForPointInInlineFormattingContext(
- const NGPhysicalOffset&) const;
-
Vector<scoped_refptr<NGPhysicalFragment>> children_;
NGPhysicalOffsetRect contents_visual_rect_;
};
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 c8e9c220604..675d046c7c4 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
@@ -5,11 +5,12 @@
#include "third_party/blink/renderer/core/layout/ng/ng_physical_fragment.h"
#include "third_party/blink/renderer/core/layout/layout_block.h"
-#include "third_party/blink/renderer/core/layout/layout_object_inlines.h"
#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/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_block_node.h"
#include "third_party/blink/renderer/core/layout/ng/ng_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
@@ -241,9 +242,12 @@ void NGPhysicalFragment::Destroy() const {
const ComputedStyle& NGPhysicalFragment::Style() const {
DCHECK(style_);
+ // TODO(kojii): Returning |style_| locks the style at the layout time, and
+ // will not be updated when its base style is updated later. Line styles and
+ // ellipsis styles have this problem.
if (!GetLayoutObject())
return *style_;
- switch ((NGStyleVariant)style_variant_) {
+ switch (StyleVariant()) {
case NGStyleVariant::kStandard:
return *GetLayoutObject()->Style();
case NGStyleVariant::kFirstLine:
@@ -285,7 +289,9 @@ bool NGPhysicalFragment::IsPlacedByLayoutNG() const {
if (!layout_object_)
return false;
const LayoutBlock* container = layout_object_->ContainingBlock();
- return container && container->IsLayoutNGMixin();
+ if (!container)
+ return false;
+ return container->IsLayoutNGMixin() || container->IsLayoutNGFlexibleBox();
}
NGPixelSnappedPhysicalBoxStrut NGPhysicalFragment::BorderWidths() const {
@@ -324,6 +330,19 @@ NGPhysicalOffsetRect NGPhysicalFragment::VisualRectWithContents() const {
return {{}, Size()};
}
+NGPhysicalOffsetRect NGPhysicalFragment::ScrollableOverflow() const {
+ switch (Type()) {
+ case NGPhysicalFragment::kFragmentBox:
+ return ToNGPhysicalBoxFragment(*this).ScrollableOverflow();
+ case NGPhysicalFragment::kFragmentText:
+ return {{}, Size()};
+ case NGPhysicalFragment::kFragmentLineBox:
+ return ToNGPhysicalLineBoxFragment(*this).ScrollableOverflow();
+ }
+ NOTREACHED();
+ return {{}, Size()};
+}
+
void NGPhysicalFragment::PropagateContentsVisualRect(
NGPhysicalOffsetRect* parent_visual_rect) const {
NGPhysicalOffsetRect visual_rect = VisualRectWithContents();
@@ -331,6 +350,38 @@ void NGPhysicalFragment::PropagateContentsVisualRect(
parent_visual_rect->Unite(visual_rect);
}
+const Vector<NGInlineItem>& NGPhysicalFragment::InlineItemsOfContainingBlock()
+ const {
+ DCHECK(IsInline());
+ DCHECK(GetLayoutObject());
+ LayoutBlockFlow* block_flow =
+ GetLayoutObject()->Parent()->EnclosingNGBlockFlow();
+ // TODO(xiaochengh): Code below is copied from ng_offset_mapping.cc with
+ // modification. Unify them.
+ DCHECK(block_flow);
+ DCHECK(block_flow->ChildrenInline());
+ NGBlockNode block_node = NGBlockNode(block_flow);
+ DCHECK(block_node.CanUseNewLayout());
+ NGLayoutInputNode node = block_node.FirstChild();
+ DCHECK(node);
+ DCHECK(node.IsInline());
+
+ // TODO(xiaochengh): Handle ::first-line.
+ return ToNGInlineNode(node).ItemsData(false).items;
+}
+
+UBiDiLevel NGPhysicalFragment::BidiLevel() const {
+ NOTREACHED();
+ return 0;
+}
+
+TextDirection NGPhysicalFragment::ResolvedDirection() const {
+ DCHECK(IsInline());
+ DCHECK(IsText() || IsAtomicInline());
+ // TODO(xiaochengh): Store direction in |base_direction_| flag.
+ return DirectionFromLevel(BidiLevel());
+}
+
scoped_refptr<NGPhysicalFragment> NGPhysicalFragment::CloneWithoutOffset()
const {
switch (Type()) {
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 9591e027133..1932d3ebefb 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
@@ -9,17 +9,21 @@
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/editing/forward.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset.h"
+#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_offset_rect.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h"
#include "third_party/blink/renderer/core/layout/ng/ng_break_token.h"
#include "third_party/blink/renderer/core/layout/ng/ng_style_variant.h"
-#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
+#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
+
+#include <unicode/ubidi.h>
namespace blink {
class ComputedStyle;
class LayoutObject;
class Node;
-struct NGPhysicalOffsetRect;
+class NGBreakToken;
+class NGInlineItem;
struct NGPixelSnappedPhysicalBoxStrut;
class PaintLayer;
@@ -130,17 +134,28 @@ class CORE_EXPORT NGPhysicalFragment
// Returns the border-box size.
NGPhysicalSize Size() const { return size_; }
+ // Returns the rect in the local coordinate of this fragment; i.e., offset is
+ // (0, 0).
+ NGPhysicalOffsetRect LocalRect() const { return {{}, size_}; }
+
// Bitmask for border edges, see NGBorderEdges::Physical.
unsigned BorderEdges() const { return border_edge_; }
NGPixelSnappedPhysicalBoxStrut BorderWidths() const;
// Returns the offset relative to the parent fragment's content-box.
NGPhysicalOffset Offset() const {
- DCHECK(is_placed_);
+ DCHECK(is_placed_) << "this=" << this << " for layout object "
+ << layout_object_;
return offset_;
}
NGBreakToken* BreakToken() const { return break_token_.get(); }
+ NGStyleVariant StyleVariant() const {
+ return static_cast<NGStyleVariant>(style_variant_);
+ }
+ bool UsesFirstLineStyle() const {
+ return StyleVariant() == NGStyleVariant::kFirstLine;
+ }
const ComputedStyle& Style() const;
Node* GetNode() const;
@@ -160,6 +175,9 @@ class CORE_EXPORT NGPhysicalFragment
// VisualRect of itself including contents, in the local coordinate.
NGPhysicalOffsetRect VisualRectWithContents() const;
+ // Scrollable overflow. including contents, in the local coordinate.
+ NGPhysicalOffsetRect ScrollableOverflow() const;
+
// Unite visual rect to propagate to parent's ContentsVisualRect.
void PropagateContentsVisualRect(NGPhysicalOffsetRect*) const;
@@ -172,8 +190,12 @@ class CORE_EXPORT NGPhysicalFragment
bool IsPlaced() const { return is_placed_; }
- virtual PositionWithAffinity PositionForPoint(
- const NGPhysicalOffset&) const = 0;
+ // Returns the bidi level of a text or atomic inline fragment.
+ virtual UBiDiLevel BidiLevel() const;
+
+ // Returns the resolved direction of a text or atomic inline fragment. Not to
+ // be confused with the CSS 'direction' property.
+ virtual TextDirection ResolvedDirection() const;
scoped_refptr<NGPhysicalFragment> CloneWithoutOffset() const;
@@ -208,6 +230,8 @@ class CORE_EXPORT NGPhysicalFragment
unsigned sub_type,
scoped_refptr<NGBreakToken> break_token = nullptr);
+ const Vector<NGInlineItem>& InlineItemsOfContainingBlock() const;
+
LayoutObject* layout_object_;
scoped_refptr<const ComputedStyle> style_;
NGPhysicalSize size_;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_positioned_float.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_positioned_float.cc
index 71fdb1aa748..ef9bec90325 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_positioned_float.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_positioned_float.cc
@@ -13,4 +13,8 @@ NGPositionedFloat::NGPositionedFloat(
const NGBfcOffset& bfc_offset)
: layout_result(layout_result), bfc_offset(bfc_offset) {}
+// Define the destructor here, so that we can forward-declare more in the header
+// file.
+NGPositionedFloat::~NGPositionedFloat() = default;
+
} // namespace blink
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_positioned_float.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_positioned_float.h
index 7078151c948..09ac96614e9 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_positioned_float.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_positioned_float.h
@@ -5,16 +5,19 @@
#ifndef NGPositionedFloat_h
#define NGPositionedFloat_h
+#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_bfc_offset.h"
-#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
namespace blink {
+class NGLayoutResult;
+
// Contains the information necessary for copying back data to a FloatingObject.
struct CORE_EXPORT NGPositionedFloat {
NGPositionedFloat(scoped_refptr<NGLayoutResult> layout_result,
const NGBfcOffset& bfc_offset);
+ ~NGPositionedFloat();
scoped_refptr<NGLayoutResult> layout_result;
NGBfcOffset bfc_offset;
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_relative_utils.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_relative_utils.cc
index f058af41ef3..948b54dc2a0 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_relative_utils.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_relative_utils.cc
@@ -4,11 +4,11 @@
#include "third_party/blink/renderer/core/layout/ng/ng_relative_utils.h"
+#include "base/optional.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_offset.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_physical_size.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/length_functions.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink {
@@ -21,7 +21,7 @@ NGLogicalOffset ComputeRelativeOffset(const ComputedStyle& child_style,
NGPhysicalSize container_size =
container_logical_size.ConvertToPhysical(container_writing_mode);
- Optional<LayoutUnit> left, right, top, bottom;
+ base::Optional<LayoutUnit> left, right, top, bottom;
if (!child_style.Left().IsAuto())
left = ValueForLength(child_style.Left(), container_size.width);
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 2bbc9546f75..a06aa67c30f 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
@@ -21,11 +21,10 @@ bool ShouldShrinkToFit(const ComputedStyle& parent_style,
!is_in_parallel_flow;
}
-bool AdjustToClearance(const WTF::Optional<LayoutUnit>& clearance_offset,
- NGBfcOffset* offset) {
+bool AdjustToClearance(LayoutUnit clearance_offset, NGBfcOffset* offset) {
DCHECK(offset);
- if (clearance_offset && clearance_offset.value() > offset->block_offset) {
- offset->block_offset = clearance_offset.value();
+ if (clearance_offset > offset->block_offset) {
+ offset->block_offset = clearance_offset;
return true;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.h
index 71c92ac9cc3..66262ad16c3 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_space_utils.h
@@ -5,9 +5,9 @@
#ifndef NGSpaceUtils_h
#define NGSpaceUtils_h
+#include "base/optional.h"
#include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/layout_unit.h"
-#include "third_party/blink/renderer/platform/wtf/optional.h"
namespace blink {
@@ -21,9 +21,8 @@ bool ShouldShrinkToFit(const ComputedStyle& parent_style,
const ComputedStyle& style);
// Adjusts {@code offset} to the clearance line.
-CORE_EXPORT bool AdjustToClearance(
- const WTF::Optional<LayoutUnit>& clearance_offset,
- NGBfcOffset* offset);
+CORE_EXPORT bool AdjustToClearance(LayoutUnit clearance_offset,
+ NGBfcOffset* offset);
} // namespace blink
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 5e1c158c550..e8853136e82 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,10 +4,10 @@
#include "third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h"
-#include "third_party/blink/renderer/core/layout/line/root_inline_box.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_baseline.h"
#include "third_party/blink/renderer/core/layout/ng/inline/ng_physical_text_fragment.h"
#include "third_party/blink/renderer/core/layout/ng/ng_physical_box_fragment.h"
+#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/fonts/font_metrics.h"
namespace blink {
@@ -16,7 +16,8 @@ int NGTextDecorationOffset::ComputeUnderlineOffsetForUnder(
float text_decoration_thickness,
FontVerticalPositionType position_type) const {
LayoutUnit offset = LayoutUnit::Max();
- FontBaseline baseline_type = text_fragment_.BaselineType();
+ const ComputedStyle& style = text_fragment_.Style();
+ FontBaseline baseline_type = style.GetFontBaseline();
if (decorating_box_) {
// TODO(eae): Replace with actual baseline once available.
@@ -32,8 +33,7 @@ int NGTextDecorationOffset::ComputeUnderlineOffsetForUnder(
if (offset == LayoutUnit::Max()) {
// TODO(layout-dev): How do we compute the baseline offset with a
// decorating_box?
- const SimpleFontData* font_data =
- text_fragment_.Style().GetFont().PrimaryFont();
+ const SimpleFontData* font_data = style.GetFont().PrimaryFont();
if (!font_data)
return 0;
offset = font_data->GetFontMetrics().Ascent(baseline_type) -
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h
index 91936a8b651..68f45a41e8f 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_text_decoration_offset.h
@@ -6,7 +6,6 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_NG_NG_TEXT_DECORATION_OFFSET_H_
#include "third_party/blink/renderer/core/core_export.h"
-#include "third_party/blink/renderer/core/layout/api/line_layout_item.h"
#include "third_party/blink/renderer/core/layout/text_decoration_offset_base.h"
namespace blink {
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.cc b/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.cc
index ffab2fa7420..285bee17df4 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.cc
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.cc
@@ -4,10 +4,31 @@
#include "third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_block_break_token.h"
+#include "third_party/blink/renderer/core/layout/ng/ng_layout_result.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
namespace blink {
+// Define the constructor and destructor here, so that we can forward-declare
+// more in the header file.
+NGUnpositionedFloat::NGUnpositionedFloat(const NGBoxStrut& margins,
+ const NGLogicalSize& available_size,
+ const NGLogicalSize& percentage_size,
+ LayoutUnit origin_bfc_line_offset,
+ LayoutUnit bfc_line_offset,
+ NGBlockNode node,
+ NGBlockBreakToken* token)
+ : node(node),
+ token(token),
+ available_size(available_size),
+ percentage_size(percentage_size),
+ origin_bfc_line_offset(origin_bfc_line_offset),
+ bfc_line_offset(bfc_line_offset),
+ margins(margins) {}
+
+NGUnpositionedFloat::~NGUnpositionedFloat() = default;
+
bool NGUnpositionedFloat::IsLeft() const {
return node.Style().Floating() == EFloat::kLeft;
}
diff --git a/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h b/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h
index 82d662ab42a..761bcc657a2 100644
--- a/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h
+++ b/chromium/third_party/blink/renderer/core/layout/ng/ng_unpositioned_float.h
@@ -8,13 +8,15 @@
#include "base/memory/scoped_refptr.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_box_strut.h"
#include "third_party/blink/renderer/core/layout/ng/geometry/ng_logical_size.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_layout_result.h"
#include "third_party/blink/renderer/core/style/computed_style_constants.h"
+#include "third_party/blink/renderer/platform/wtf/ref_counted.h"
namespace blink {
+class NGBlockBreakToken;
+class NGLayoutResult;
+
// Struct that keeps all information needed to position floats in LayoutNG.
struct CORE_EXPORT NGUnpositionedFloat
: public RefCounted<NGUnpositionedFloat> {
@@ -32,6 +34,8 @@ struct CORE_EXPORT NGUnpositionedFloat
bfc_line_offset, node, token));
}
+ ~NGUnpositionedFloat();
+
NGBlockNode node;
scoped_refptr<NGBlockBreakToken> token;
@@ -68,14 +72,7 @@ struct CORE_EXPORT NGUnpositionedFloat
LayoutUnit origin_bfc_line_offset,
LayoutUnit bfc_line_offset,
NGBlockNode node,
- NGBlockBreakToken* token)
- : node(node),
- token(token),
- available_size(available_size),
- percentage_size(percentage_size),
- origin_bfc_line_offset(origin_bfc_line_offset),
- bfc_line_offset(bfc_line_offset),
- margins(margins) {}
+ NGBlockBreakToken* token);
};
} // namespace blink
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 7ecd208a2c8..04e9d99d1ae 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
@@ -18,16 +18,9 @@ namespace blink {
using Corner = ScrollAnchor::Corner;
-typedef bool TestParamRootLayerScrolling;
-class ScrollAnchorTest
- : public testing::WithParamInterface<TestParamRootLayerScrolling>,
- private ScopedRootLayerScrollingForTest,
- private ScopedScrollAnchoringForTest,
- public RenderingTest {
+class ScrollAnchorTest : public RenderingTest {
public:
- ScrollAnchorTest()
- : ScopedRootLayerScrollingForTest(GetParam()),
- ScopedScrollAnchoringForTest(true) {}
+ ScrollAnchorTest() {}
protected:
void Update() {
@@ -82,16 +75,11 @@ class ScrollAnchorTest
GetDocument().QuerySelectorAll(AtomicString(serialized.selector));
EXPECT_EQ(ele_list->length(), 1u);
}
-
- private:
- std::unique_ptr<ScopedScrollAnchoringForTest> scroll_anchoring_;
};
-INSTANTIATE_TEST_CASE_P(All, ScrollAnchorTest, testing::Bool());
-
// TODO(ymalik): Currently, this should be the first test in the file to avoid
// failure when running with other tests. Dig into this more and fix.
-TEST_P(ScrollAnchorTest, UMAMetricUpdated) {
+TEST_F(ScrollAnchorTest, UMAMetricUpdated) {
HistogramTester histogram_tester;
SetBodyInnerHTML(R"HTML(
<style> body { height: 1000px } div { height: 100px } </style>
@@ -156,7 +144,7 @@ TEST_P(ScrollAnchorTest, UMAMetricUpdated) {
// TODO(skobes): Convert this to web-platform-tests when visual viewport API is
// launched (http://crbug.com/635031).
-TEST_P(ScrollAnchorTest, VisualViewportAnchors) {
+TEST_F(ScrollAnchorTest, VisualViewportAnchors) {
SetBodyInnerHTML(R"HTML(
<style>
* { font-size: 1.2em; font-family: sans-serif; }
@@ -196,7 +184,7 @@ TEST_P(ScrollAnchorTest, VisualViewportAnchors) {
// Test that a non-anchoring scroll on scroller clears scroll anchors for all
// parent scrollers.
-TEST_P(ScrollAnchorTest, ClearScrollAnchorsOnAncestors) {
+TEST_F(ScrollAnchorTest, ClearScrollAnchorsOnAncestors) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px } div { height: 200px }
@@ -223,7 +211,7 @@ TEST_P(ScrollAnchorTest, ClearScrollAnchorsOnAncestors) {
EXPECT_EQ(nullptr, GetScrollAnchor(viewport).AnchorObject());
}
-TEST_P(ScrollAnchorTest, AncestorClearingWithSiblingReference) {
+TEST_F(ScrollAnchorTest, AncestorClearingWithSiblingReference) {
SetBodyInnerHTML(R"HTML(
<style>
.scroller {
@@ -265,7 +253,7 @@ TEST_P(ScrollAnchorTest, AncestorClearingWithSiblingReference) {
Update();
}
-TEST_P(ScrollAnchorTest, FractionalOffsetsAreRoundedBeforeComparing) {
+TEST_F(ScrollAnchorTest, FractionalOffsetsAreRoundedBeforeComparing) {
SetBodyInnerHTML(R"HTML(
<style> body { height: 1000px } </style>
<div id='block1' style='height: 50.4px'>abc</div>
@@ -282,7 +270,7 @@ TEST_P(ScrollAnchorTest, FractionalOffsetsAreRoundedBeforeComparing) {
EXPECT_EQ(101, viewport->ScrollOffsetInt().Height());
}
-TEST_P(ScrollAnchorTest, AvoidStickyAnchorWhichMovesWithScroll) {
+TEST_F(ScrollAnchorTest, AvoidStickyAnchorWhichMovesWithScroll) {
SetBodyInnerHTML(R"HTML(
<style> body { height: 1000px } </style>
<div id='block1' style='height: 50px'>abc</div>
@@ -300,7 +288,7 @@ TEST_P(ScrollAnchorTest, AvoidStickyAnchorWhichMovesWithScroll) {
EXPECT_EQ(60, viewport->ScrollOffsetInt().Height());
}
-TEST_P(ScrollAnchorTest, AnchorWithLayerInScrollingDiv) {
+TEST_F(ScrollAnchorTest, AnchorWithLayerInScrollingDiv) {
SetBodyInnerHTML(R"HTML(
<style>
#scroller { overflow: scroll; width: 500px; height: 400px; }
@@ -336,7 +324,7 @@ TEST_P(ScrollAnchorTest, AnchorWithLayerInScrollingDiv) {
// 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) {
+TEST_F(ScrollAnchorTest, RemoveScrollerWithLayerInScrollingDiv) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 2000px }
@@ -377,7 +365,7 @@ TEST_P(ScrollAnchorTest, RemoveScrollerWithLayerInScrollingDiv) {
Update();
}
-TEST_P(ScrollAnchorTest, FlexboxDelayedClampingAlsoDelaysAdjustment) {
+TEST_F(ScrollAnchorTest, FlexboxDelayedClampingAlsoDelaysAdjustment) {
SetBodyInnerHTML(R"HTML(
<style>
html { overflow: hidden; }
@@ -408,7 +396,7 @@ TEST_P(ScrollAnchorTest, FlexboxDelayedClampingAlsoDelaysAdjustment) {
EXPECT_EQ(150, ScrollerForElement(scroller)->ScrollOffsetInt().Height());
}
-TEST_P(ScrollAnchorTest, FlexboxDelayedAdjustmentRespectsSANACLAP) {
+TEST_F(ScrollAnchorTest, FlexboxDelayedAdjustmentRespectsSANACLAP) {
SetBodyInnerHTML(R"HTML(
<style>
html { overflow: hidden; }
@@ -442,7 +430,7 @@ TEST_P(ScrollAnchorTest, FlexboxDelayedAdjustmentRespectsSANACLAP) {
// TODO(skobes): Convert this to web-platform-tests when document.rootScroller
// is launched (http://crbug.com/505516).
-TEST_P(ScrollAnchorTest, NonDefaultRootScroller) {
+TEST_F(ScrollAnchorTest, NonDefaultRootScroller) {
SetBodyInnerHTML(R"HTML(
<style>
::-webkit-scrollbar {
@@ -500,7 +488,7 @@ TEST_P(ScrollAnchorTest, NonDefaultRootScroller) {
// This test verifies that scroll anchoring is disabled when the document is in
// printing mode.
-TEST_P(ScrollAnchorTest, AnchoringDisabledForPrinting) {
+TEST_F(ScrollAnchorTest, AnchoringDisabledForPrinting) {
SetBodyInnerHTML(R"HTML(
<style> body { height: 1000px } div { height: 100px } </style>
<div id='block1'>abc</div>
@@ -517,7 +505,7 @@ TEST_P(ScrollAnchorTest, AnchoringDisabledForPrinting) {
EXPECT_EQ(nullptr, GetScrollAnchor(viewport).AnchorObject());
}
-TEST_P(ScrollAnchorTest, SerializeAnchorSimple) {
+TEST_F(ScrollAnchorTest, SerializeAnchorSimple) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -530,7 +518,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorSimple) {
ValidateSerializedAnchor("#block2", LayoutPoint(0, -50));
}
-TEST_P(ScrollAnchorTest, SerializeAnchorUsesTagname) {
+TEST_F(ScrollAnchorTest, SerializeAnchorUsesTagname) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -545,7 +533,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorUsesTagname) {
ValidateSerializedAnchor("#ancestor>span", LayoutPoint(0, -50));
}
-TEST_P(ScrollAnchorTest, SerializeAnchorSetsIsAnchorBit) {
+TEST_F(ScrollAnchorTest, SerializeAnchorSetsIsAnchorBit) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -573,7 +561,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorSetsIsAnchorBit) {
ScrollLayoutViewport(ScrollOffset(0, 25));
}
-TEST_P(ScrollAnchorTest, SerializeAnchorSetsSavedRelativeOffset) {
+TEST_F(ScrollAnchorTest, SerializeAnchorSetsSavedRelativeOffset) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -590,7 +578,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorSetsSavedRelativeOffset) {
EXPECT_EQ(LayoutViewport()->ScrollOffsetInt().Height(), 250);
}
-TEST_P(ScrollAnchorTest, SerializeAnchorUsesClassname) {
+TEST_F(ScrollAnchorTest, SerializeAnchorUsesClassname) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -605,7 +593,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorUsesClassname) {
ValidateSerializedAnchor("#ancestor>.barbaz", LayoutPoint(0, -50));
}
-TEST_P(ScrollAnchorTest, SerializeAnchorUsesNthChild) {
+TEST_F(ScrollAnchorTest, SerializeAnchorUsesNthChild) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -620,7 +608,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorUsesNthChild) {
ValidateSerializedAnchor("#ancestor>:nth-child(2)", LayoutPoint(0, -50));
}
-TEST_P(ScrollAnchorTest, SerializeAnchorUsesLeastSpecificSelector) {
+TEST_F(ScrollAnchorTest, SerializeAnchorUsesLeastSpecificSelector) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -642,7 +630,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorUsesLeastSpecificSelector) {
LayoutPoint(0, -50));
}
-TEST_P(ScrollAnchorTest, SerializeAnchorWithNoIdAttribute) {
+TEST_F(ScrollAnchorTest, SerializeAnchorWithNoIdAttribute) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -664,7 +652,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorWithNoIdAttribute) {
LayoutPoint(0, -50));
}
-TEST_P(ScrollAnchorTest, SerializeAnchorChangesWithScroll) {
+TEST_F(ScrollAnchorTest, SerializeAnchorChangesWithScroll) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -688,7 +676,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorChangesWithScroll) {
ValidateSerializedAnchor("#ancestor>.foobar", LayoutPoint(0, -1));
}
-TEST_P(ScrollAnchorTest, SerializeAnchorVerticalWritingMode) {
+TEST_F(ScrollAnchorTest, SerializeAnchorVerticalWritingMode) {
SetBodyInnerHTML(R"HTML(
<style>
body {
@@ -713,7 +701,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorVerticalWritingMode) {
ValidateSerializedAnchor("html>body>.barbaz", LayoutPoint(-50, 0));
}
-TEST_P(ScrollAnchorTest, SerializeAnchorQualifiedTagName) {
+TEST_F(ScrollAnchorTest, SerializeAnchorQualifiedTagName) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -727,7 +715,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorQualifiedTagName) {
ValidateSerializedAnchor("html>body>ns\\:div", LayoutPoint(0, -50));
}
-TEST_P(ScrollAnchorTest, SerializeAnchorLimitsSelectorLength) {
+TEST_F(ScrollAnchorTest, SerializeAnchorLimitsSelectorLength) {
StringBuilder builder;
builder.Append("<style> body { height: 1000px; margin: 0; }</style>");
builder.Append("<div style='height:100px'>foobar</div>");
@@ -744,7 +732,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorLimitsSelectorLength) {
EXPECT_FALSE(serialized.IsValid());
}
-TEST_P(ScrollAnchorTest, SerializeAnchorIgnoresDuplicatedId) {
+TEST_F(ScrollAnchorTest, SerializeAnchorIgnoresDuplicatedId) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -762,7 +750,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorIgnoresDuplicatedId) {
LayoutPoint(0, -50));
}
-TEST_P(ScrollAnchorTest, SerializeAnchorFailsForPseudoElement) {
+TEST_F(ScrollAnchorTest, SerializeAnchorFailsForPseudoElement) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -776,7 +764,7 @@ TEST_P(ScrollAnchorTest, SerializeAnchorFailsForPseudoElement) {
EXPECT_FALSE(GetScrollAnchor(LayoutViewport()).AnchorObject());
}
-TEST_P(ScrollAnchorTest, RestoreAnchorSimple) {
+TEST_F(ScrollAnchorTest, RestoreAnchorSimple) {
SetBodyInnerHTML(
"<style> body { height: 1000px; margin: 0; } div { height: 100px } "
"</style>"
@@ -798,7 +786,7 @@ TEST_P(ScrollAnchorTest, RestoreAnchorSimple) {
EXPECT_EQ(LayoutViewport()->ScrollOffsetInt().Height(), 50);
}
-TEST_P(ScrollAnchorTest, RestoreAnchorNonTrivialSelector) {
+TEST_F(ScrollAnchorTest, RestoreAnchorNonTrivialSelector) {
SetBodyInnerHTML(R"HTML(
<style>
body { height: 1000px; margin: 0; }
@@ -828,7 +816,7 @@ TEST_P(ScrollAnchorTest, RestoreAnchorNonTrivialSelector) {
EXPECT_EQ(LayoutViewport()->ScrollOffsetInt().Height(), 450);
}
-TEST_P(ScrollAnchorTest, RestoreAnchorFailsForInvalidSelectors) {
+TEST_F(ScrollAnchorTest, RestoreAnchorFailsForInvalidSelectors) {
SetBodyInnerHTML(
"<style> body { height: 1000px; margin: 0; } div { height: 100px } "
"</style>"
@@ -856,7 +844,7 @@ TEST_P(ScrollAnchorTest, RestoreAnchorFailsForInvalidSelectors) {
// Ensure that when the serialized selector refers to a non-box, non-text
// element(meaning its corresponding LayoutObject can't be the anchor object)
// that restoration will still succeed.
-TEST_P(ScrollAnchorTest, RestoreAnchorSucceedsForNonBoxNonTextElement) {
+TEST_F(ScrollAnchorTest, RestoreAnchorSucceedsForNonBoxNonTextElement) {
SetBodyInnerHTML(
"<style> body { height: 1000px; margin: 0; } div { height: 100px } "
"</style>"
@@ -880,7 +868,7 @@ TEST_P(ScrollAnchorTest, RestoreAnchorSucceedsForNonBoxNonTextElement) {
ValidateSerializedAnchor("html>body>code", LayoutPoint(0, 0));
}
-TEST_P(ScrollAnchorTest, RestoreAnchorSucceedsWhenScriptForbidden) {
+TEST_F(ScrollAnchorTest, RestoreAnchorSucceedsWhenScriptForbidden) {
SetBodyInnerHTML(
"<style> body { height: 1000px; margin: 0; } div { height: 100px } "
"</style>"
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 56be7a43e97..4765f26297c 100644
--- a/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/scrollbars_test.cc
@@ -18,11 +18,12 @@
#include "third_party/blink/renderer/core/layout/layout_scrollbar_part.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/page.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/testing/sim/sim_request.h"
#include "third_party/blink/renderer/core/testing/sim/sim_test.h"
+#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/scroll/scrollbar_theme_overlay_mock.h"
-#include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h"
#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"
@@ -31,12 +32,8 @@ namespace blink {
namespace {
-class ScrollbarsTest : public testing::WithParamInterface<bool>,
- private ScopedRootLayerScrollingForTest,
- public SimTest {
+class ScrollbarsTest : public SimTest {
public:
- ScrollbarsTest() : ScopedRootLayerScrollingForTest(GetParam()) {}
-
HitTestResult HitTest(int x, int y) {
return WebView().CoreHitTestResultAt(WebPoint(x, y));
}
@@ -46,10 +43,10 @@ class ScrollbarsTest : public testing::WithParamInterface<bool>,
}
void HandleMouseMoveEvent(int x, int y) {
- WebMouseEvent event(
- WebInputEvent::kMouseMove, WebFloatPoint(x, y), WebFloatPoint(x, y),
- WebPointerProperties::Button::kNoButton, 0, WebInputEvent::kNoModifiers,
- CurrentTimeTicksInSeconds());
+ WebMouseEvent event(WebInputEvent::kMouseMove, WebFloatPoint(x, y),
+ WebFloatPoint(x, y),
+ WebPointerProperties::Button::kNoButton, 0,
+ WebInputEvent::kNoModifiers, CurrentTimeTicks());
event.SetFrameScale(1);
GetEventHandler().HandleMouseMoveEvent(event, Vector<WebMouseEvent>());
}
@@ -58,7 +55,7 @@ class ScrollbarsTest : public testing::WithParamInterface<bool>,
WebMouseEvent event(
WebInputEvent::kMouseDown, WebFloatPoint(x, y), WebFloatPoint(x, y),
WebPointerProperties::Button::kLeft, 0,
- WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicksInSeconds());
+ WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicks());
event.SetFrameScale(1);
GetEventHandler().HandleMousePressEvent(event);
}
@@ -67,7 +64,25 @@ class ScrollbarsTest : public testing::WithParamInterface<bool>,
WebMouseEvent event(
WebInputEvent::kMouseUp, WebFloatPoint(x, y), WebFloatPoint(x, y),
WebPointerProperties::Button::kLeft, 0,
- WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicksInSeconds());
+ WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicks());
+ event.SetFrameScale(1);
+ GetEventHandler().HandleMouseReleaseEvent(event);
+ }
+
+ void HandleMouseMiddlePressEvent(int x, int y) {
+ WebMouseEvent event(
+ WebInputEvent::kMouseDown, WebFloatPoint(x, y), WebFloatPoint(x, y),
+ WebPointerProperties::Button::kMiddle, 0,
+ WebInputEvent::Modifiers::kMiddleButtonDown, CurrentTimeTicks());
+ event.SetFrameScale(1);
+ GetEventHandler().HandleMousePressEvent(event);
+ }
+
+ void HandleMouseMiddleReleaseEvent(int x, int y) {
+ WebMouseEvent event(
+ WebInputEvent::kMouseUp, WebFloatPoint(x, y), WebFloatPoint(x, y),
+ WebPointerProperties::Button::kMiddle, 0,
+ WebInputEvent::Modifiers::kMiddleButtonDown, CurrentTimeTicks());
event.SetFrameScale(1);
GetEventHandler().HandleMouseReleaseEvent(event);
}
@@ -76,7 +91,7 @@ class ScrollbarsTest : public testing::WithParamInterface<bool>,
WebMouseEvent event(
WebInputEvent::kMouseMove, WebFloatPoint(1, 1), WebFloatPoint(1, 1),
WebPointerProperties::Button::kLeft, 0,
- WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicksInSeconds());
+ WebInputEvent::Modifiers::kLeftButtonDown, CurrentTimeTicks());
event.SetFrameScale(1);
GetEventHandler().HandleMouseLeaveEvent(event);
}
@@ -131,10 +146,7 @@ class ScrollbarsTestWithVirtualTimer : public ScrollbarsTest {
}
};
-INSTANTIATE_TEST_CASE_P(All, ScrollbarsTest, testing::Bool());
-INSTANTIATE_TEST_CASE_P(All, ScrollbarsTestWithVirtualTimer, testing::Bool());
-
-TEST_P(ScrollbarsTest, DocumentStyleRecalcPreservesScrollbars) {
+TEST_F(ScrollbarsTest, DocumentStyleRecalcPreservesScrollbars) {
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
WebView().Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
@@ -174,7 +186,7 @@ class ScrollbarsWebViewClient : public FrameTestHelpers::TestWebViewClient {
float device_scale_factor_;
};
-TEST_P(ScrollbarsTest, ScrollbarSizeForUseZoomDSF) {
+TEST_F(ScrollbarsTest, ScrollbarSizeForUseZoomDSF) {
ScrollbarsWebViewClient client;
client.set_device_scale_factor(1.f);
@@ -236,11 +248,7 @@ TEST_P(ScrollbarsTest, ScrollbarSizeForUseZoomDSF) {
// caused by trying to avoid the layout when overlays are enabled but not
// checking whether the scrollbars should be custom - which do take up layout
// space. https://crbug.com/668387.
-TEST_P(ScrollbarsTest, CustomScrollbarsCauseLayoutOnExistenceChange) {
- // The bug reproduces only with RLS off. When RLS ships we can keep the test
- // but remove this setting.
- ScopedRootLayerScrollingForTest turn_off_root_layer_scrolling(false);
-
+TEST_F(ScrollbarsTest, CustomScrollbarsCauseLayoutOnExistenceChange) {
WebView().Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -292,11 +300,7 @@ TEST_P(ScrollbarsTest, CustomScrollbarsCauseLayoutOnExistenceChange) {
ASSERT_FALSE(layout_viewport->HorizontalScrollbar());
}
-TEST_P(ScrollbarsTest, TransparentBackgroundUsesDarkOverlayColorTheme) {
- // The bug reproduces only with RLS off. When RLS ships we can keep the test
- // but remove this setting.
- ScopedRootLayerScrollingForTest turn_off_root_layer_scrolling(false);
-
+TEST_F(ScrollbarsTest, TransparentBackgroundUsesDarkOverlayColorTheme) {
WebView().Resize(WebSize(800, 600));
WebView().SetBaseBackgroundColorOverride(SK_ColorTRANSPARENT);
SimRequest request("https://example.com/test.html", "text/html");
@@ -322,7 +326,7 @@ TEST_P(ScrollbarsTest, TransparentBackgroundUsesDarkOverlayColorTheme) {
layout_viewport->GetScrollbarOverlayColorTheme());
}
-TEST_P(ScrollbarsTest, BodyBackgroundChangesOverlayColorTheme) {
+TEST_F(ScrollbarsTest, BodyBackgroundChangesOverlayColorTheme) {
v8::HandleScope handle_scope(v8::Isolate::GetCurrent());
WebView().Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
@@ -352,7 +356,7 @@ TEST_P(ScrollbarsTest, BodyBackgroundChangesOverlayColorTheme) {
}
// Ensure overlay scrollbar change to display:none correctly.
-TEST_P(ScrollbarsTest, OverlayScrollbarChangeToDisplayNoneDynamically) {
+TEST_F(ScrollbarsTest, OverlayScrollbarChangeToDisplayNoneDynamically) {
WebView().Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -396,11 +400,8 @@ TEST_P(ScrollbarsTest, OverlayScrollbarChangeToDisplayNoneDynamically) {
DCHECK(scrollable_root->VerticalScrollbar()->IsOverlayScrollbar());
// For PaintLayer Overlay Scrollbar we will remove the scrollbar when it is
- // not necessary even with overflow:scroll. Should remove after RLS ships.
- if (GetParam() == 0)
- DCHECK(scrollable_root->HorizontalScrollbar());
- else
- DCHECK(!scrollable_root->HorizontalScrollbar());
+ // not necessary even with overflow:scroll.
+ DCHECK(!scrollable_root->HorizontalScrollbar());
// Set display:none.
div->setAttribute(HTMLNames::classAttr, "noscrollbars");
@@ -424,7 +425,7 @@ TEST_P(ScrollbarsTest, OverlayScrollbarChangeToDisplayNoneDynamically) {
EXPECT_TRUE(scrollable_root->HorizontalScrollbar()->FrameRect().IsEmpty());
}
-TEST_P(ScrollbarsTest, scrollbarIsNotHandlingTouchpadScroll) {
+TEST_F(ScrollbarsTest, scrollbarIsNotHandlingTouchpadScroll) {
WebView().Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
LoadURL("https://example.com/test.html");
@@ -446,9 +447,9 @@ TEST_P(ScrollbarsTest, scrollbarIsNotHandlingTouchpadScroll) {
ScrollableArea* scrollable_area =
ToLayoutBox(scrollable->GetLayoutObject())->GetScrollableArea();
DCHECK(scrollable_area->VerticalScrollbar());
- WebGestureEvent scroll_begin(
- WebInputEvent::kGestureScrollBegin, WebInputEvent::kNoModifiers,
- CurrentTimeTicksInSeconds(), kWebGestureDeviceTouchpad);
+ WebGestureEvent scroll_begin(WebInputEvent::kGestureScrollBegin,
+ WebInputEvent::kNoModifiers, CurrentTimeTicks(),
+ kWebGestureDeviceTouchpad);
scroll_begin.SetPositionInWidget(
WebFloatPoint(scrollable->OffsetLeft() + scrollable->OffsetWidth() - 2,
scrollable->OffsetTop()));
@@ -465,7 +466,7 @@ TEST_P(ScrollbarsTest, scrollbarIsNotHandlingTouchpadScroll) {
scroll_begin, &should_update_capture));
}
-TEST_P(ScrollbarsTest, HidingScrollbarsOnScrollableAreaDisablesScrollbars) {
+TEST_F(ScrollbarsTest, HidingScrollbarsOnScrollableAreaDisablesScrollbars) {
WebView().Resize(WebSize(800, 600));
SimRequest request("https://example.com/test.html", "text/html");
@@ -534,7 +535,7 @@ TEST_P(ScrollbarsTest, HidingScrollbarsOnScrollableAreaDisablesScrollbars) {
}
// Ensure mouse cursor should be pointer when hovering over the scrollbar.
-TEST_P(ScrollbarsTest, MouseOverScrollbarInCustomCursorElement) {
+TEST_F(ScrollbarsTest, MouseOverScrollbarInCustomCursorElement) {
WebView().Resize(WebSize(250, 250));
SimRequest request("https://example.com/test.html", "text/html");
@@ -579,7 +580,7 @@ TEST_P(ScrollbarsTest, MouseOverScrollbarInCustomCursorElement) {
// Makes sure that mouse hover over an overlay scrollbar doesn't activate
// elements below(except the Element that owns the scrollbar) unless the
// scrollbar is faded out.
-TEST_P(ScrollbarsTest, MouseOverLinkAndOverlayScrollbar) {
+TEST_F(ScrollbarsTest, MouseOverLinkAndOverlayScrollbar) {
WebView().Resize(WebSize(20, 20));
SimRequest request("https://example.com/test.html", "text/html");
@@ -661,7 +662,7 @@ TEST_P(ScrollbarsTest, MouseOverLinkAndOverlayScrollbar) {
// Makes sure that mouse hover over an custom scrollbar doesn't change the
// activate elements.
-TEST_P(ScrollbarsTest, MouseOverCustomScrollbar) {
+TEST_F(ScrollbarsTest, MouseOverCustomScrollbar) {
WebView().Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
@@ -728,7 +729,7 @@ TEST_P(ScrollbarsTest, MouseOverCustomScrollbar) {
// Makes sure that mouse hover over an overlay scrollbar doesn't hover iframe
// below.
-TEST_P(ScrollbarsTest, MouseOverScrollbarAndIFrame) {
+TEST_F(ScrollbarsTest, MouseOverScrollbarAndIFrame) {
WebView().Resize(WebSize(200, 200));
SimRequest main_resource("https://example.com/", "text/html");
@@ -811,7 +812,7 @@ TEST_P(ScrollbarsTest, MouseOverScrollbarAndIFrame) {
// Makes sure that mouse hover over a scrollbar also hover the element owns the
// scrollbar.
-TEST_P(ScrollbarsTest, MouseOverScrollbarAndParentElement) {
+TEST_F(ScrollbarsTest, MouseOverScrollbarAndParentElement) {
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
WebView().Resize(WebSize(200, 200));
@@ -898,7 +899,7 @@ TEST_P(ScrollbarsTest, MouseOverScrollbarAndParentElement) {
}
// Makes sure that mouse over a root scrollbar also hover the html element.
-TEST_P(ScrollbarsTest, MouseOverRootScrollbar) {
+TEST_F(ScrollbarsTest, MouseOverRootScrollbar) {
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
WebView().Resize(WebSize(200, 200));
@@ -932,7 +933,7 @@ TEST_P(ScrollbarsTest, MouseOverRootScrollbar) {
EXPECT_EQ(document.HoverElement(), document.documentElement());
}
-TEST_P(ScrollbarsTest, MouseReleaseUpdatesScrollbarHoveredPart) {
+TEST_F(ScrollbarsTest, MouseReleaseUpdatesScrollbarHoveredPart) {
WebView().Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
@@ -997,7 +998,7 @@ TEST_P(ScrollbarsTest, MouseReleaseUpdatesScrollbarHoveredPart) {
EXPECT_EQ(scrollbar->HoveredPart(), ScrollbarPart::kNoPart);
}
-TEST_P(ScrollbarsTest,
+TEST_F(ScrollbarsTest,
CustomScrollbarInOverlayScrollbarThemeWillNotCauseDCHECKFails) {
WebView().Resize(WebSize(200, 200));
@@ -1026,7 +1027,7 @@ TEST_P(ScrollbarsTest,
// Make sure root custom scrollbar can change by Emulator but div custom
// scrollbar not.
-TEST_P(ScrollbarsTest, CustomScrollbarChangeToMobileByEmulator) {
+TEST_F(ScrollbarsTest, CustomScrollbarChangeToMobileByEmulator) {
WebView().Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
@@ -1110,7 +1111,7 @@ TEST_P(ScrollbarsTest, CustomScrollbarChangeToMobileByEmulator) {
}
// Ensure custom scrollbar recreate when style owner change,
-TEST_P(ScrollbarsTest, CustomScrollbarWhenStyleOwnerChange) {
+TEST_F(ScrollbarsTest, CustomScrollbarWhenStyleOwnerChange) {
WebView().Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
@@ -1167,10 +1168,10 @@ TEST_P(ScrollbarsTest, CustomScrollbarWhenStyleOwnerChange) {
// Disable on Android since VirtualTime not work for Android.
// http://crbug.com/633321
#if defined(OS_ANDROID)
-TEST_P(ScrollbarsTestWithVirtualTimer,
+TEST_F(ScrollbarsTestWithVirtualTimer,
DISABLED_TestNonCompositedOverlayScrollbarsFade) {
#else
-TEST_P(ScrollbarsTestWithVirtualTimer, TestNonCompositedOverlayScrollbarsFade) {
+TEST_F(ScrollbarsTestWithVirtualTimer, TestNonCompositedOverlayScrollbarsFade) {
#endif
TimeAdvance();
constexpr double kMockOverlayFadeOutDelayInSeconds = 5.0;
@@ -1482,7 +1483,7 @@ TEST_P(ScrollbarAppearanceTest, HugeScrollingThumbPosition) {
#endif
// A body with width just under the window width should not have scrollbars.
-TEST_P(ScrollbarsTest, WideBodyShouldNotHaveScrollbars) {
+TEST_F(ScrollbarsTest, WideBodyShouldNotHaveScrollbars) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
@@ -1506,7 +1507,7 @@ TEST_P(ScrollbarsTest, WideBodyShouldNotHaveScrollbars) {
}
// A body with height just under the window height should not have scrollbars.
-TEST_P(ScrollbarsTest, TallBodyShouldNotHaveScrollbars) {
+TEST_F(ScrollbarsTest, TallBodyShouldNotHaveScrollbars) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
@@ -1531,7 +1532,7 @@ TEST_P(ScrollbarsTest, TallBodyShouldNotHaveScrollbars) {
// A body with dimensions just barely inside the window dimensions should not
// have scrollbars.
-TEST_P(ScrollbarsTest, TallAndWideBodyShouldNotHaveScrollbars) {
+TEST_F(ScrollbarsTest, TallAndWideBodyShouldNotHaveScrollbars) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
@@ -1556,7 +1557,7 @@ TEST_P(ScrollbarsTest, TallAndWideBodyShouldNotHaveScrollbars) {
// A body with dimensions equal to the window dimensions should not have
// scrollbars.
-TEST_P(ScrollbarsTest, BodySizeEqualWindowSizeShouldNotHaveScrollbars) {
+TEST_F(ScrollbarsTest, BodySizeEqualWindowSizeShouldNotHaveScrollbars) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
@@ -1581,7 +1582,7 @@ TEST_P(ScrollbarsTest, BodySizeEqualWindowSizeShouldNotHaveScrollbars) {
// A body with percentage width extending beyond the window width should cause a
// horizontal scrollbar.
-TEST_P(ScrollbarsTest, WidePercentageBodyShouldHaveScrollbar) {
+TEST_F(ScrollbarsTest, WidePercentageBodyShouldHaveScrollbar) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
@@ -1607,7 +1608,7 @@ TEST_P(ScrollbarsTest, WidePercentageBodyShouldHaveScrollbar) {
// Similar to |WidePercentageBodyShouldHaveScrollbar| but with a body height
// equal to the window height.
-TEST_P(ScrollbarsTest, WidePercentageAndTallBodyShouldHaveScrollbar) {
+TEST_F(ScrollbarsTest, WidePercentageAndTallBodyShouldHaveScrollbar) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
@@ -1633,7 +1634,7 @@ TEST_P(ScrollbarsTest, WidePercentageAndTallBodyShouldHaveScrollbar) {
// A body with percentage height extending beyond the window height should cause
// a vertical scrollbar.
-TEST_P(ScrollbarsTest, TallPercentageBodyShouldHaveScrollbar) {
+TEST_F(ScrollbarsTest, TallPercentageBodyShouldHaveScrollbar) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
@@ -1659,7 +1660,7 @@ TEST_P(ScrollbarsTest, TallPercentageBodyShouldHaveScrollbar) {
// Similar to |TallPercentageBodyShouldHaveScrollbar| but with a body width
// equal to the window width.
-TEST_P(ScrollbarsTest, TallPercentageAndWideBodyShouldHaveScrollbar) {
+TEST_F(ScrollbarsTest, TallPercentageAndWideBodyShouldHaveScrollbar) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
@@ -1685,7 +1686,7 @@ TEST_P(ScrollbarsTest, TallPercentageAndWideBodyShouldHaveScrollbar) {
// A body with percentage dimensions extending beyond the window dimensions
// should cause scrollbars.
-TEST_P(ScrollbarsTest, TallAndWidePercentageBodyShouldHaveScrollbars) {
+TEST_F(ScrollbarsTest, TallAndWidePercentageBodyShouldHaveScrollbars) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
@@ -1709,7 +1710,7 @@ TEST_P(ScrollbarsTest, TallAndWidePercentageBodyShouldHaveScrollbars) {
EXPECT_TRUE(layout_viewport->HorizontalScrollbar());
}
-TEST_P(ScrollbarsTest, MouseOverIFrameScrollbar) {
+TEST_F(ScrollbarsTest, MouseOverIFrameScrollbar) {
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
WebView().Resize(WebSize(800, 600));
@@ -1759,7 +1760,7 @@ TEST_P(ScrollbarsTest, MouseOverIFrameScrollbar) {
EXPECT_EQ(document.HoverElement(), iframe);
}
-TEST_P(ScrollbarsTest, AutosizeTest) {
+TEST_F(ScrollbarsTest, AutosizeTest) {
// This test requires that scrollbars take up space.
ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
@@ -1827,7 +1828,7 @@ TEST_P(ScrollbarsTest, AutosizeTest) {
}
}
-TEST_P(ScrollbarsTest,
+TEST_F(ScrollbarsTest,
HideTheOverlayScrollbarNotCrashAfterPLSADisposedPaintLayer) {
WebView().Resize(WebSize(200, 200));
SimRequest request("https://example.com/test.html", "text/html");
@@ -1869,7 +1870,50 @@ TEST_P(ScrollbarsTest,
EXPECT_FALSE(scrollable_div->ScrollbarsHiddenIfOverlay());
}
-TEST_P(ScrollbarsTest, OverlayScrollbarHitTest) {
+TEST_F(ScrollbarsTest, PLSADisposeShouldClearPointerInLayers) {
+ GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
+ true);
+ WebView().Resize(WebSize(200, 200));
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ /* transform keeps the graphics layer */
+ #div { width: 100px; height: 100px; will-change: transform; }
+ .scroller{ overflow: scroll; }
+ .big{ height: 2000px; }
+ /* positioned so we still keep the PaintLayer */
+ .hide { overflow: visible; position: absolute; }
+ </style>
+ <div id='div' class='scroller' style='z-index:1'>
+ <div class='big'>
+ </div>
+ </div>
+ )HTML");
+ Compositor().BeginFrame();
+
+ Document& document = GetDocument();
+ Element* div = document.getElementById("div");
+ PaintLayerScrollableArea* scrollable_div =
+ ToLayoutBox(div->GetLayoutObject())->GetScrollableArea();
+
+ ASSERT_TRUE(scrollable_div);
+
+ PaintLayer* paint_layer = scrollable_div->Layer();
+ ASSERT_TRUE(paint_layer);
+
+ GraphicsLayer* graphics_layer = scrollable_div->LayerForScrolling();
+ ASSERT_TRUE(graphics_layer);
+
+ div->setAttribute(HTMLNames::classAttr, "hide");
+ document.UpdateStyleAndLayout();
+
+ EXPECT_FALSE(paint_layer->GetScrollableArea());
+ EXPECT_FALSE(graphics_layer->GetScrollableArea());
+}
+
+TEST_F(ScrollbarsTest, OverlayScrollbarHitTest) {
WebView().Resize(WebSize(300, 300));
SimRequest main_resource("https://example.com/", "text/html");
@@ -1923,6 +1967,89 @@ TEST_P(ScrollbarsTest, OverlayScrollbarHitTest) {
EXPECT_FALSE(hit_test_result.GetScrollbar());
}
+TEST_F(ScrollbarsTest, AllowMiddleButtonPressOnScrollbar) {
+ ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
+ WebView().Resize(WebSize(200, 200));
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ #big {
+ height: 800px;
+ }
+ </style>
+ <div id='big'>
+ </div>
+ )HTML");
+ Compositor().BeginFrame();
+
+ ScrollableArea* scrollable_area =
+ WebView().MainFrameImpl()->GetFrameView()->LayoutViewportScrollableArea();
+
+ Scrollbar* scrollbar = scrollable_area->VerticalScrollbar();
+ ASSERT_TRUE(scrollbar);
+ ASSERT_TRUE(scrollbar->Enabled());
+
+ // Not allow press scrollbar with middle button.
+ HandleMouseMoveEvent(195, 5);
+ HandleMouseMiddlePressEvent(195, 5);
+ EXPECT_EQ(scrollbar->PressedPart(), ScrollbarPart::kThumbPart);
+ HandleMouseMiddleReleaseEvent(195, 5);
+}
+
+// Ensure Scrollbar not release press by middle button down.
+TEST_F(ScrollbarsTest, MiddleDownShouldNotAffectScrollbarPress) {
+ ScopedOverlayScrollbarsForTest overlay_scrollbars(false);
+ WebView().Resize(WebSize(200, 200));
+ SimRequest request("https://example.com/test.html", "text/html");
+ LoadURL("https://example.com/test.html");
+ request.Complete(R"HTML(
+ <!DOCTYPE html>
+ <style>
+ #big {
+ height: 800px;
+ }
+ </style>
+ <div id='big'>
+ </div>
+ )HTML");
+ Compositor().BeginFrame();
+
+ ScrollableArea* scrollable_area =
+ WebView().MainFrameImpl()->GetFrameView()->LayoutViewportScrollableArea();
+
+ Scrollbar* scrollbar = scrollable_area->VerticalScrollbar();
+ ASSERT_TRUE(scrollbar);
+ ASSERT_TRUE(scrollbar->Enabled());
+
+ // Press on scrollbar then move mouse out of scrollbar and middle click
+ // should not release the press state. Then relase mouse left button should
+ // release the scrollbar press state.
+
+ // Move mouse to thumb.
+ HandleMouseMoveEvent(195, 5);
+ HandleMousePressEvent(195, 5);
+ 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,
+ CurrentTimeTicks());
+ event.SetFrameScale(1);
+ GetEventHandler().HandleMouseLeaveEvent(event);
+ EXPECT_EQ(scrollbar->PressedPart(), ScrollbarPart::kThumbPart);
+
+ // Middle click should not release scrollbar press state.
+ HandleMouseMiddlePressEvent(5, 5);
+ EXPECT_EQ(scrollbar->PressedPart(), ScrollbarPart::kThumbPart);
+
+ // Middle button release should release scrollbar press state.
+ HandleMouseMiddleReleaseEvent(5, 5);
+ EXPECT_EQ(scrollbar->PressedPart(), ScrollbarPart::kNoPart);
+}
+
class ScrollbarTrackMarginsTest : public ScrollbarsTest {
public:
void PrepareTest(const String& track_style) {
@@ -1976,9 +2103,7 @@ class ScrollbarTrackMarginsTest : public ScrollbarsTest {
LayoutScrollbarPart* vertical_track_ = nullptr;
};
-INSTANTIATE_TEST_CASE_P(All, ScrollbarTrackMarginsTest, testing::Bool());
-
-TEST_P(ScrollbarTrackMarginsTest,
+TEST_F(ScrollbarTrackMarginsTest,
CustomScrollbarFractionalMarginsWillNotCauseDCHECKFailure) {
PrepareTest(R"CSS(
::-webkit-scrollbar-track {
@@ -1994,7 +2119,7 @@ TEST_P(ScrollbarTrackMarginsTest,
EXPECT_EQ(41, vertical_track_->MarginBottom());
}
-TEST_P(ScrollbarTrackMarginsTest,
+TEST_F(ScrollbarTrackMarginsTest,
CustomScrollbarScaledMarginsWillNotCauseDCHECKFailure) {
WebView().SetZoomFactorForDeviceScaleFactor(1.25f);
diff --git a/chromium/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc b/chromium/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc
index dffb0d13788..371d08e0e4b 100644
--- a/chromium/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/shapes/box_shape_test.cc
@@ -143,7 +143,7 @@ TEST_F(BoxShapeTest, getIntervals) {
TEST_EXCLUDED_INTERVAL(shape, LayoutUnit(15), LayoutUnit(6), 0, 100);
TEST_EXCLUDED_INTERVAL(shape, LayoutUnit(20), LayoutUnit(50), 0, 100);
TEST_EXCLUDED_INTERVAL(shape, LayoutUnit(69), LayoutUnit(5), 0, 100);
- TEST_EXCLUDED_INTERVAL(shape, LayoutUnit(85), LayoutUnit(10), 0, 97.320511f);
+ TEST_EXCLUDED_INTERVAL(shape, LayoutUnit(85), LayoutUnit(10), 0, 97.3125f);
}
} // anonymous namespace
diff --git a/chromium/third_party/blink/renderer/core/layout/shapes/polygon_shape.h b/chromium/third_party/blink/renderer/core/layout/shapes/polygon_shape.h
index 7b073cc72be..97f76361219 100644
--- a/chromium/third_party/blink/renderer/core/layout/shapes/polygon_shape.h
+++ b/chromium/third_party/blink/renderer/core/layout/shapes/polygon_shape.h
@@ -65,7 +65,7 @@ class OffsetPolygonEdge final : public VertexPair {
class PolygonShape final : public Shape {
public:
PolygonShape(std::unique_ptr<Vector<FloatPoint>> vertices, WindRule fill_rule)
- : Shape(), polygon_(std::move(vertices), fill_rule) {}
+ : Shape(), polygon_(std::move(vertices)) {}
LayoutRect ShapeMarginLogicalBoundingBox() const override;
bool IsEmpty() const override { return polygon_.IsEmpty(); }
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 778a89ee86f..b940726a77b 100644
--- a/chromium/third_party/blink/renderer/core/layout/shapes/shape.h
+++ b/chromium/third_party/blink/renderer/core/layout/shapes/shape.h
@@ -51,8 +51,8 @@ struct LineSegment {
logical_right(logical_right),
is_valid(true) {}
- float logical_left;
- float logical_right;
+ LayoutUnit logical_left;
+ LayoutUnit logical_right;
bool is_valid;
};
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 d7737d02982..61f6ccb7d1d 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,8 @@
#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/use_counter.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/floating_objects.h"
@@ -37,7 +39,6 @@
#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/length_functions.h"
-#include "third_party/blink/renderer/platform/wtf/auto_reset.h"
namespace blink {
@@ -49,10 +50,22 @@ CSSBoxType ReferenceBox(const ShapeValue& shape_value) {
void ShapeOutsideInfo::SetReferenceBoxLogicalSize(
LayoutSize new_reference_box_logical_size) {
+ const Document& document = layout_box_.GetDocument();
bool is_horizontal_writing_mode =
layout_box_.ContainingBlock()->Style()->IsHorizontalWritingMode();
+
+ LayoutSize margin_box_for_use_counter = new_reference_box_logical_size;
+ if (is_horizontal_writing_mode) {
+ margin_box_for_use_counter.Expand(layout_box_.MarginWidth(),
+ layout_box_.MarginHeight());
+ } else {
+ margin_box_for_use_counter.Expand(layout_box_.MarginHeight(),
+ layout_box_.MarginWidth());
+ }
+
switch (ReferenceBox(*layout_box_.Style()->ShapeOutside())) {
case CSSBoxType::kMargin:
+ UseCounter::Count(document, WebFeature::kShapeOutsideMarginBox);
if (is_horizontal_writing_mode)
new_reference_box_logical_size.Expand(layout_box_.MarginWidth(),
layout_box_.MarginHeight());
@@ -61,16 +74,25 @@ void ShapeOutsideInfo::SetReferenceBoxLogicalSize(
layout_box_.MarginWidth());
break;
case CSSBoxType::kBorder:
+ UseCounter::Count(document, WebFeature::kShapeOutsideBorderBox);
break;
case CSSBoxType::kPadding:
+ UseCounter::Count(document, WebFeature::kShapeOutsidePaddingBox);
if (is_horizontal_writing_mode)
new_reference_box_logical_size.Shrink(layout_box_.BorderWidth(),
layout_box_.BorderHeight());
else
new_reference_box_logical_size.Shrink(layout_box_.BorderHeight(),
layout_box_.BorderWidth());
+
+ if (new_reference_box_logical_size != margin_box_for_use_counter) {
+ UseCounter::Count(
+ document,
+ WebFeature::kShapeOutsidePaddingBoxDifferentFromMarginBox);
+ }
break;
case CSSBoxType::kContent:
+ UseCounter::Count(document, WebFeature::kShapeOutsideContentBox);
if (is_horizontal_writing_mode)
new_reference_box_logical_size.Shrink(
layout_box_.BorderAndPaddingWidth(),
@@ -79,6 +101,12 @@ void ShapeOutsideInfo::SetReferenceBoxLogicalSize(
new_reference_box_logical_size.Shrink(
layout_box_.BorderAndPaddingHeight(),
layout_box_.BorderAndPaddingWidth());
+
+ if (new_reference_box_logical_size != margin_box_for_use_counter) {
+ UseCounter::Count(
+ document,
+ WebFeature::kShapeOutsideContentBoxDifferentFromMarginBox);
+ }
break;
case CSSBoxType::kMissing:
NOTREACHED();
@@ -93,6 +121,17 @@ void ShapeOutsideInfo::SetReferenceBoxLogicalSize(
reference_box_logical_size_ = new_reference_box_logical_size;
}
+void ShapeOutsideInfo::SetPercentageResolutionInlineSize(
+ LayoutUnit percentage_resolution_inline_size) {
+ DCHECK(RuntimeEnabledFeatures::LayoutNGEnabled());
+
+ if (percentage_resolution_inline_size_ == percentage_resolution_inline_size)
+ return;
+
+ MarkShapeAsDirty();
+ percentage_resolution_inline_size_ = percentage_resolution_inline_size;
+}
+
static bool CheckShapeImageOrigin(Document& document,
const StyleImage& style_image) {
if (style_image.IsGeneratedImage())
@@ -160,24 +199,25 @@ const Shape& ShapeOutsideInfo::ComputedShape() const {
if (Shape* shape = shape_.get())
return *shape;
- AutoReset<bool> is_in_computing_shape(&is_computing_shape_, true);
+ base::AutoReset<bool> is_in_computing_shape(&is_computing_shape_, true);
const ComputedStyle& style = *layout_box_.Style();
DCHECK(layout_box_.ContainingBlock());
- const ComputedStyle& containing_block_style =
- *layout_box_.ContainingBlock()->Style();
+ const LayoutBlock& containing_block = *layout_box_.ContainingBlock();
+ const ComputedStyle& containing_block_style = containing_block.StyleRef();
WritingMode writing_mode = containing_block_style.GetWritingMode();
// Make sure contentWidth is not negative. This can happen when containing
// block has a vertical scrollbar and its content is smaller than the
// scrollbar width.
- LayoutUnit maximum_value =
- layout_box_.ContainingBlock()
- ? std::max(LayoutUnit(),
- layout_box_.ContainingBlock()->ContentWidth())
- : LayoutUnit();
- float margin = FloatValueForLength(layout_box_.Style()->ShapeMargin(),
- maximum_value.ToFloat());
+ LayoutUnit percentage_resolution_inline_size =
+ containing_block.IsLayoutNGMixin()
+ ? percentage_resolution_inline_size_
+ : std::max(LayoutUnit(), containing_block.ContentWidth());
+
+ float margin =
+ FloatValueForLength(layout_box_.Style()->ShapeMargin(),
+ percentage_resolution_inline_size.ToFloat());
float shape_image_threshold = style.ShapeImageThreshold();
DCHECK(style.ShapeOutside());
@@ -365,8 +405,8 @@ ShapeOutsideDeltas ShapeOutsideInfo::ComputeDeltasForContainingBlockLine(
containing_block.Style()->IsLeftToRightDirection()
? containing_block.MarginStartForChild(layout_box_)
: containing_block.MarginEndForChild(layout_box_);
- LayoutUnit raw_left_margin_box_delta(
- segment.logical_left + LogicalLeftOffset() + logical_left_margin);
+ LayoutUnit raw_left_margin_box_delta =
+ segment.logical_left + LogicalLeftOffset() + logical_left_margin;
LayoutUnit left_margin_box_delta = clampTo<LayoutUnit>(
raw_left_margin_box_delta, LayoutUnit(), float_margin_box_width);
@@ -374,10 +414,10 @@ ShapeOutsideDeltas ShapeOutsideInfo::ComputeDeltasForContainingBlockLine(
containing_block.Style()->IsLeftToRightDirection()
? containing_block.MarginEndForChild(layout_box_)
: containing_block.MarginStartForChild(layout_box_);
- LayoutUnit raw_right_margin_box_delta(
+ LayoutUnit raw_right_margin_box_delta =
segment.logical_right + LogicalLeftOffset() -
containing_block.LogicalWidthForChild(layout_box_) -
- logical_right_margin);
+ logical_right_margin;
LayoutUnit right_margin_box_delta = clampTo<LayoutUnit>(
raw_right_margin_box_delta, -float_margin_box_width, LayoutUnit());
diff --git a/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.h b/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.h
index c940bff0e94..b2ac9f0f360 100644
--- a/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.h
+++ b/chromium/third_party/blink/renderer/core/layout/shapes/shape_outside_info.h
@@ -95,6 +95,7 @@ class ShapeOutsideInfo final {
public:
void SetReferenceBoxLogicalSize(LayoutSize);
+ void SetPercentageResolutionInlineSize(LayoutUnit);
LayoutUnit ShapeLogicalTop() const {
return ComputedShape().ShapeMarginLogicalBoundingBox().Y() +
@@ -178,6 +179,7 @@ class ShapeOutsideInfo final {
const LayoutBox& layout_box_;
mutable std::unique_ptr<Shape> shape_;
LayoutSize reference_box_logical_size_;
+ LayoutUnit percentage_resolution_inline_size_;
ShapeOutsideDeltas shape_outside_deltas_;
mutable bool is_computing_shape_;
};
diff --git a/chromium/third_party/blink/renderer/core/layout/subtree_layout_scope.h b/chromium/third_party/blink/renderer/core/layout/subtree_layout_scope.h
index d8f32a82870..d5f506c7d16 100644
--- a/chromium/third_party/blink/renderer/core/layout/subtree_layout_scope.h
+++ b/chromium/third_party/blink/renderer/core/layout/subtree_layout_scope.h
@@ -31,7 +31,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SUBTREE_LAYOUT_SCOPE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SUBTREE_LAYOUT_SCOPE_H_
-#include "third_party/blink/renderer/core/inspector/InspectorTraceEvents.h"
+#include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc
index ddbe809a927..df0f405f749 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_block.cc
@@ -25,10 +25,11 @@
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.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/style/shadow_list.h"
#include "third_party/blink/renderer/core/svg/svg_element.h"
-#include "third_party/blink/renderer/platform/geometry/transform_state.h"
+#include "third_party/blink/renderer/platform/transforms/transform_state.h"
namespace blink {
@@ -47,6 +48,7 @@ void LayoutSVGBlock::AbsoluteRects(Vector<IntRect>&, const LayoutPoint&) const {
void LayoutSVGBlock::WillBeDestroyed() {
SVGResourcesCache::ClientDestroyed(*this);
+ SVGResources::ClearClipPathFilterMask(*GetElement(), Style());
LayoutBlockFlow::WillBeDestroyed();
}
@@ -73,6 +75,7 @@ void LayoutSVGBlock::StyleDidChange(StyleDifference diff,
}
LayoutBlock::StyleDidChange(diff, old_style);
+ SVGResources::UpdateClipPathFilterMask(*GetElement(), old_style, StyleRef());
SVGResourcesCache::ClientStyleChanged(*this, diff, StyleRef());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc
index f7a9a9b684e..ad066f7f40e 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_ellipse.cc
@@ -98,14 +98,13 @@ void LayoutSVGEllipse::CalculateRadiiAndCenter() {
}
bool LayoutSVGEllipse::ShapeDependentStrokeContains(const FloatPoint& point) {
- // The optimized check below for circles does not support non-scaling or
- // discontinuous strokes.
- if (use_path_fallback_ || !HasContinuousStroke() ||
- radii_.Width() != radii_.Height()) {
- if (!HasPath())
- CreatePath();
+ if (radii_.Width() < 0 || radii_.Height() < 0)
+ return false;
+
+ // The optimized check below for circles does not support non-circular and
+ // the cases that we set use_path_fallback_ in UpdateShapeFromElement().
+ if (use_path_fallback_ || radii_.Width() != radii_.Height())
return LayoutSVGShape::ShapeDependentStrokeContains(point);
- }
const FloatPoint center =
FloatPoint(center_.X() - point.X(), center_.Y() - point.Y());
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
index eb31ff5f2ae..6736f00c101 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_foreign_object_test.cc
@@ -12,15 +12,6 @@ class LayoutSVGForeignObjectTest : public RenderingTest {
public:
LayoutSVGForeignObjectTest()
: RenderingTest(SingleChildLocalFrameClient::Create()) {}
-
- const Node* HitTest(int x, int y) {
- HitTestResult result(
- HitTestRequest(HitTestRequest::kReadOnly | HitTestRequest::kActive |
- HitTestRequest::kAllowChildFrameContent),
- IntPoint(x, y));
- GetLayoutView().HitTest(result);
- return result.InnerNode();
- }
};
TEST_F(LayoutSVGForeignObjectTest, DivInForeignObject) {
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 8fd4c1384e6..5ab1d05e39f 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
@@ -25,6 +25,7 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
#include "third_party/blink/renderer/core/layout/svg/line/svg_inline_flow_box.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.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/svg/svg_a_element.h"
@@ -119,6 +120,8 @@ void LayoutSVGInline::AbsoluteQuads(Vector<FloatQuad>& quads,
void LayoutSVGInline::WillBeDestroyed() {
SVGResourcesCache::ClientDestroyed(*this);
+ SVGResources::ClearClipPathFilterMask(ToSVGElement(*GetNode()), Style());
+ SVGResources::ClearPaints(ToSVGElement(*GetNode()), Style());
LayoutInline::WillBeDestroyed();
}
@@ -128,6 +131,9 @@ void LayoutSVGInline::StyleDidChange(StyleDifference diff,
SetNeedsBoundariesUpdate();
LayoutInline::StyleDidChange(diff, old_style);
+ SVGResources::UpdateClipPathFilterMask(ToSVGElement(*GetNode()), old_style,
+ StyleRef());
+ SVGResources::UpdatePaints(ToSVGElement(*GetNode()), old_style, StyleRef());
SVGResourcesCache::ClientStyleChanged(*this, diff, StyleRef());
}
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
index a62462cfe7f..c8708e90b56 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_model_object.cc
@@ -34,6 +34,7 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_container.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.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/paint/paint_layer.h"
#include "third_party/blink/renderer/core/svg/svg_graphics_element.h"
@@ -92,6 +93,7 @@ FloatRect LayoutSVGModelObject::LocalBoundingBoxRectForAccessibility() const {
void LayoutSVGModelObject::WillBeDestroyed() {
SVGResourcesCache::ClientDestroyed(*this);
+ SVGResources::ClearClipPathFilterMask(*GetElement(), Style());
LayoutObject::WillBeDestroyed();
}
@@ -134,6 +136,7 @@ void LayoutSVGModelObject::StyleDidChange(StyleDifference diff,
}
LayoutObject::StyleDidChange(diff, old_style);
+ SVGResources::UpdateClipPathFilterMask(*GetElement(), old_style, StyleRef());
SVGResourcesCache::ClientStyleChanged(*this, diff, StyleRef());
}
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 2e95d31b6f9..a3eee4a939e 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
@@ -38,6 +38,17 @@ LayoutSVGPath::LayoutSVGPath(SVGGeometryElement* node) : LayoutSVGShape(node) {}
LayoutSVGPath::~LayoutSVGPath() = default;
+void LayoutSVGPath::StyleDidChange(StyleDifference diff,
+ const ComputedStyle* old_style) {
+ LayoutSVGShape::StyleDidChange(diff, old_style);
+ SVGResources::UpdateMarkers(*GetElement(), old_style, StyleRef());
+}
+
+void LayoutSVGPath::WillBeDestroyed() {
+ SVGResources::ClearMarkers(*GetElement(), Style());
+ LayoutSVGShape::WillBeDestroyed();
+}
+
void LayoutSVGPath::UpdateShapeFromElement() {
LayoutSVGShape::UpdateShapeFromElement();
ProcessMarkerPositions();
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 45949839cc9..b1f6c080e44 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
@@ -42,6 +42,9 @@ class LayoutSVGPath final : public LayoutSVGShape {
const char* GetName() const override { return "LayoutSVGPath"; }
private:
+ void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
+ void WillBeDestroyed() override;
+
void UpdateShapeFromElement() override;
FloatRect HitTestStrokeBoundingBox() const override;
FloatRect CalculateUpdatedStrokeBoundingBox() const;
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc
index 5d9ae41433c..81ab1129b3b 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc
+++ b/chromium/third_party/blink/renderer/core/layout/svg/layout_svg_rect.cc
@@ -85,14 +85,10 @@ void LayoutSVGRect::UpdateShapeFromElement() {
}
bool LayoutSVGRect::ShapeDependentStrokeContains(const FloatPoint& point) {
- // The optimized code below does not support non-simple strokes so we need
- // to fall back to LayoutSVGShape::shapeDependentStrokeContains in these
- // cases.
- if (use_path_fallback_ || !DefinitelyHasSimpleStroke()) {
- if (!HasPath())
- CreatePath();
+ // The optimized code below does not support the cases that we set
+ // use_path_fallback_ in UpdateShapeFromElement().
+ if (use_path_fallback_)
return LayoutSVGShape::ShapeDependentStrokeContains(point);
- }
const float half_stroke_width = StrokeWidth() / 2;
const float half_width = fill_bounding_box_.Width() / 2;
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 9e361f0ccac..5be8e9757a3 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
@@ -120,21 +120,21 @@ void LayoutSVGResourceClipper::RemoveAllClientsFromCache(
: SVGResourceClient::kParentOnlyInvalidation);
}
-Optional<Path> LayoutSVGResourceClipper::AsPath() {
+base::Optional<Path> LayoutSVGResourceClipper::AsPath() {
if (clip_content_path_validity_ == kClipContentPathValid)
- return Optional<Path>(clip_content_path_);
+ return base::Optional<Path>(clip_content_path_);
if (clip_content_path_validity_ == kClipContentPathInvalid)
- return WTF::nullopt;
+ return base::nullopt;
DCHECK_EQ(clip_content_path_validity_, kClipContentPathUnknown);
clip_content_path_validity_ = kClipContentPathInvalid;
// If the current clip-path gets clipped itself, we have to fallback to
// masking.
if (StyleRef().ClipPath())
- return WTF::nullopt;
+ return base::nullopt;
unsigned op_count = 0;
- Optional<SkOpBuilder> clip_path_builder;
+ base::Optional<SkOpBuilder> clip_path_builder;
SkPath resolved_path;
for (const SVGElement& child_element :
Traversal<SVGElement>::ChildrenOf(*GetElement())) {
@@ -142,14 +142,14 @@ Optional<Path> LayoutSVGResourceClipper::AsPath() {
if (strategy == ClipStrategy::kNone)
continue;
if (strategy == ClipStrategy::kMask)
- return WTF::nullopt;
+ return base::nullopt;
// Multiple shapes require PathOps. In some degenerate cases PathOps can
// exhibit quadratic behavior, so we cap the number of ops to a reasonable
// count.
const unsigned kMaxOps = 42;
if (++op_count > kMaxOps)
- return WTF::nullopt;
+ return base::nullopt;
if (clip_path_builder) {
clip_path_builder->add(PathFromElement(child_element).GetSkPath(),
kUnion_SkPathOp);
@@ -167,7 +167,7 @@ Optional<Path> LayoutSVGResourceClipper::AsPath() {
clip_path_builder->resolve(&resolved_path);
clip_content_path_ = std::move(resolved_path);
clip_content_path_validity_ = kClipContentPathValid;
- return Optional<Path>(clip_content_path_);
+ return base::Optional<Path>(clip_content_path_);
}
sk_sp<const PaintRecord> LayoutSVGResourceClipper::CreatePaintRecord() {
@@ -214,6 +214,18 @@ void LayoutSVGResourceClipper::CalculateLocalClipBounds() {
}
}
+AffineTransform LayoutSVGResourceClipper::CalculateClipTransform(
+ const FloatRect& reference_box) const {
+ AffineTransform transform =
+ ToSVGClipPathElement(GetElement())
+ ->CalculateTransform(SVGElement::kIncludeMotionTransform);
+ if (ClipPathUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
+ transform.Translate(reference_box.X(), reference_box.Y());
+ transform.ScaleNonUniform(reference_box.Width(), reference_box.Height());
+ }
+ return transform;
+}
+
bool LayoutSVGResourceClipper::HitTestClipContent(
const FloatRect& object_bounding_box,
const FloatPoint& node_at_point) {
@@ -221,21 +233,12 @@ bool LayoutSVGResourceClipper::HitTestClipContent(
if (!SVGLayoutSupport::PointInClippingArea(*this, point))
return false;
- if (ClipPathUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
- AffineTransform transform;
- transform.Translate(object_bounding_box.X(), object_bounding_box.Y());
- transform.ScaleNonUniform(object_bounding_box.Width(),
- object_bounding_box.Height());
- point = transform.Inverse().MapPoint(point);
- }
-
- AffineTransform animated_local_transform =
- ToSVGClipPathElement(GetElement())
- ->CalculateTransform(SVGElement::kIncludeMotionTransform);
- if (!animated_local_transform.IsInvertible())
+ AffineTransform user_space_transform =
+ CalculateClipTransform(object_bounding_box);
+ if (!user_space_transform.IsInvertible())
return false;
- point = animated_local_transform.Inverse().MapPoint(point);
+ point = user_space_transform.Inverse().MapPoint(point);
for (const SVGElement& child_element :
Traversal<SVGElement>::ChildrenOf(*GetElement())) {
@@ -245,9 +248,8 @@ bool LayoutSVGResourceClipper::HitTestClipContent(
HitTestResult result(HitTestRequest::kSVGClipContent, hit_point);
LayoutObject* layout_object = child_element.GetLayoutObject();
- if (layout_object->IsBoxModelObject() &&
- ToLayoutBoxModelObject(layout_object)->HasSelfPaintingLayer())
- continue;
+ DCHECK(!layout_object->IsBoxModelObject() ||
+ !ToLayoutBoxModelObject(layout_object)->HasSelfPaintingLayer());
if (layout_object->NodeAtFloatPoint(result, point, kHitTestForeground))
return true;
@@ -264,14 +266,7 @@ FloatRect LayoutSVGResourceClipper::ResourceBoundingBox(
if (local_clip_bounds_.IsEmpty())
CalculateLocalClipBounds();
- AffineTransform transform =
- ToSVGClipPathElement(GetElement())
- ->CalculateTransform(SVGElement::kIncludeMotionTransform);
- if (ClipPathUnits() == SVGUnitTypes::kSvgUnitTypeObjectboundingbox) {
- transform.Translate(reference_box.X(), reference_box.Y());
- transform.ScaleNonUniform(reference_box.Width(), reference_box.Height());
- }
- return transform.MapRect(local_clip_bounds_);
+ return CalculateClipTransform(reference_box).MapRect(local_clip_bounds_);
}
void LayoutSVGResourceClipper::WillBeDestroyed() {
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 e979d7cc562..dd32bc669ff 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
@@ -48,8 +48,9 @@ class LayoutSVGResourceClipper final : public LayoutSVGResourceContainer {
->CurrentValue()
->EnumValue();
}
+ AffineTransform CalculateClipTransform(const FloatRect& reference_box) const;
- Optional<Path> AsPath();
+ base::Optional<Path> AsPath();
sk_sp<const PaintRecord> CreatePaintRecord();
bool HasCycle() { return in_clip_expansion_; }
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 3fee1a35841..c1d14a5c912 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
@@ -19,11 +19,11 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
+#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/svg/svg_resource.h"
#include "third_party/blink/renderer/core/svg/svg_tree_scope_resources.h"
-#include "third_party/blink/renderer/platform/wtf/auto_reset.h"
namespace blink {
@@ -55,7 +55,7 @@ void LayoutSVGResourceContainer::UpdateLayout() {
if (is_in_layout_)
return;
- AutoReset<bool> in_layout_change(&is_in_layout_, true);
+ base::AutoReset<bool> in_layout_change(&is_in_layout_, true);
LayoutSVGHiddenContainer::UpdateLayout();
@@ -64,40 +64,23 @@ void LayoutSVGResourceContainer::UpdateLayout() {
void LayoutSVGResourceContainer::WillBeDestroyed() {
LayoutSVGHiddenContainer::WillBeDestroyed();
- // The resource is being torn down. If we have any clients, move those to be
- // pending on the resource (if one exists.)
+ // The resource is being torn down.
+ // TODO(fs): Remove this when SVGResources is gone.
if (LocalSVGResource* resource = ResourceForContainer(*this))
- MakeClientsPending(*resource);
+ resource->NotifyResourceDestroyed(*this);
}
void LayoutSVGResourceContainer::StyleDidChange(
StyleDifference diff,
const ComputedStyle* old_style) {
LayoutSVGHiddenContainer::StyleDidChange(diff, old_style);
- // The resource has (read: may have) been attached. Notify any pending
- // clients that they can now try to add themselves as clients to the
- // resource.
- if (LocalSVGResource* resource = ResourceForContainer(*this)) {
- if (resource->Target() == GetElement())
- resource->NotifyPendingClients();
- }
-}
-
-void LayoutSVGResourceContainer::MakeClientsPending(
- LocalSVGResource& resource) {
- RemoveAllClientsFromCache();
-
- for (auto* client : clients_) {
- // Unlink the resource from the client's SVGResources.
- SVGResources* resources =
- SVGResourcesCache::CachedResourcesForLayoutObject(*client);
- // Or else the client wouldn't be in the list in the first place.
- DCHECK(resources);
- resources->ResourceDestroyed(this);
-
- resource.AddWatch(ToSVGElement(*client->GetNode()));
- }
- clients_.clear();
+ // The resource has been attached. Notify any pending clients that
+ // they can now try to add themselves as clients to the resource.
+ // TODO(fs): Remove this when SVGResources is gone.
+ if (old_style)
+ return;
+ if (LocalSVGResource* resource = ResourceForContainer(*this))
+ resource->NotifyResourceAttached(*this);
}
void LayoutSVGResourceContainer::MarkAllClientsForInvalidation(
@@ -105,7 +88,7 @@ void LayoutSVGResourceContainer::MarkAllClientsForInvalidation(
if (is_invalidating_)
return;
LocalSVGResource* resource = ResourceForContainer(*this);
- if (clients_.IsEmpty() && (!resource || !resource->HasClients()))
+ if (!resource || !resource->HasClients())
return;
// Remove modes for which invalidations have already been
// performed. If no modes remain we are done.
@@ -115,25 +98,6 @@ void LayoutSVGResourceContainer::MarkAllClientsForInvalidation(
completed_invalidations_mask_ |= invalidation_mask;
is_invalidating_ = true;
- bool needs_layout =
- invalidation_mask & SVGResourceClient::kLayoutInvalidation;
- bool mark_for_invalidation =
- invalidation_mask & ~SVGResourceClient::kParentOnlyInvalidation;
-
- // Invalidate clients registered on the this object (via SVGResources).
- for (auto* client : clients_) {
- DCHECK(client->IsSVG());
- if (client->IsSVGResourceContainer()) {
- ToLayoutSVGResourceContainer(client)->RemoveAllClientsFromCache(
- mark_for_invalidation);
- continue;
- }
-
- if (mark_for_invalidation)
- MarkClientForInvalidation(*client, invalidation_mask);
-
- MarkForLayoutAndParentResourceInvalidation(*client, needs_layout);
- }
// Invalidate clients registered via an SVGResource.
if (resource)
@@ -162,17 +126,6 @@ void LayoutSVGResourceContainer::MarkClientForInvalidation(
client.SetNeedsBoundariesUpdate();
}
-void LayoutSVGResourceContainer::AddClient(LayoutObject& client) {
- clients_.insert(&client);
- ClearInvalidationMask();
-}
-
-bool LayoutSVGResourceContainer::RemoveClient(LayoutObject& client) {
- RemoveClientFromCache(client);
- clients_.erase(&client);
- return clients_.IsEmpty();
-}
-
void LayoutSVGResourceContainer::InvalidateCacheAndMarkForLayout(
LayoutInvalidationReasonForTracing reason,
SubtreeLayoutScope* layout_scope) {
@@ -195,24 +148,25 @@ void LayoutSVGResourceContainer::InvalidateCacheAndMarkForLayout(
static inline void RemoveFromCacheAndInvalidateDependencies(
LayoutObject& object,
bool needs_layout) {
+ if (!object.GetNode() || !object.GetNode()->IsSVGElement())
+ return;
+ SVGElement& element = ToSVGElement(*object.GetNode());
+
if (SVGResources* resources =
SVGResourcesCache::CachedResourcesForLayoutObject(object)) {
+ SVGResourceClient* client = element.GetSVGResourceClient();
if (InvalidationModeMask invalidation_mask =
- resources->RemoveClientFromCacheAffectingObjectBounds(object)) {
+ resources->RemoveClientFromCacheAffectingObjectBounds(*client)) {
LayoutSVGResourceContainer::MarkClientForInvalidation(object,
invalidation_mask);
}
}
- if (!object.GetNode() || !object.GetNode()->IsSVGElement())
- return;
-
- ToSVGElement(object.GetNode())
- ->NotifyIncomingReferences([needs_layout](SVGElement& element) {
- DCHECK(element.GetLayoutObject());
- LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
- *element.GetLayoutObject(), needs_layout);
- });
+ element.NotifyIncomingReferences([needs_layout](SVGElement& element) {
+ DCHECK(element.GetLayoutObject());
+ LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
+ *element.GetLayoutObject(), needs_layout);
+ });
}
void LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
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 815e18917fa..4f9c61ee06e 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
@@ -25,8 +25,6 @@
namespace blink {
-class LocalSVGResource;
-
enum LayoutSVGResourceType {
kMaskerResourceType,
kMarkerResourceType,
@@ -45,10 +43,9 @@ class LayoutSVGResourceContainer : public LayoutSVGHiddenContainer {
virtual void RemoveAllClientsFromCache(bool mark_for_invalidation = true) = 0;
// Remove any cached data for the |client|, and return true if so.
- virtual bool RemoveClientFromCache(LayoutObject& client) { return false; }
+ virtual bool RemoveClientFromCache(SVGResourceClient&) { return false; }
void UpdateLayout() override;
- void StyleDidChange(StyleDifference, const ComputedStyle* old_style) final;
bool IsOfType(LayoutObjectType type) const override {
return type == kLayoutObjectSVGResourceContainer ||
LayoutSVGHiddenContainer::IsOfType(type);
@@ -63,11 +60,6 @@ class LayoutSVGResourceContainer : public LayoutSVGHiddenContainer {
resource_type == kRadialGradientResourceType;
}
- // Detach all clients from this resource, and add them as watches to the tree
- // scope's resource entry (the argument.)
- void MakeClientsPending(LocalSVGResource&);
- bool HasClients() const { return !clients_.IsEmpty(); }
-
void InvalidateCacheAndMarkForLayout(LayoutInvalidationReasonForTracing,
SubtreeLayoutScope* = nullptr);
void InvalidateCacheAndMarkForLayout(SubtreeLayoutScope* = nullptr);
@@ -83,23 +75,18 @@ class LayoutSVGResourceContainer : public LayoutSVGHiddenContainer {
// Used from RemoveAllClientsFromCache methods.
void MarkAllClientsForInvalidation(InvalidationModeMask);
+ void StyleDidChange(StyleDifference, const ComputedStyle* old_style) final;
void WillBeDestroyed() override;
bool is_in_layout_;
private:
- friend class SVGResourcesCache;
- void AddClient(LayoutObject&);
- bool RemoveClient(LayoutObject&);
-
// Track global (markAllClientsForInvalidation) invalidations to avoid
// redundant crawls.
unsigned completed_invalidations_mask_ : 8;
unsigned is_invalidating_ : 1;
// 23 padding bits available
-
- HashSet<LayoutObject*> clients_;
};
DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutSVGResourceContainer,
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 31e1ab4c897..a9559a578de 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
@@ -75,7 +75,7 @@ void LayoutSVGResourceFilter::RemoveAllClientsFromCache(
: SVGResourceClient::kParentOnlyInvalidation);
}
-bool LayoutSVGResourceFilter::RemoveClientFromCache(LayoutObject& client) {
+bool LayoutSVGResourceFilter::RemoveClientFromCache(SVGResourceClient& client) {
auto entry = filter_.find(&client);
if (entry == filter_.end())
return false;
@@ -127,14 +127,13 @@ void LayoutSVGResourceFilter::PrimitiveAttributeChanged(
if (!primitive.SetFilterEffectAttribute(effect, attribute))
return;
node_map->InvalidateDependentEffects(effect);
-
- // Issue paint invalidations for the image on the screen.
- MarkClientForInvalidation(*filter.key,
- SVGResourceClient::kPaintInvalidation);
}
if (LocalSVGResource* resource =
- ToSVGFilterElement(GetElement())->AssociatedResource())
- resource->NotifyContentChanged(SVGResourceClient::kPaintInvalidation);
+ ToSVGFilterElement(GetElement())->AssociatedResource()) {
+ resource->NotifyContentChanged(
+ SVGResourceClient::kPaintInvalidation |
+ SVGResourceClient::kSkipAncestorInvalidation);
+ }
}
} // 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 a9169846171..23372b07167 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
@@ -80,7 +80,7 @@ class LayoutSVGResourceFilter final : public LayoutSVGResourceContainer {
}
void RemoveAllClientsFromCache(bool mark_for_invalidation = true) override;
- bool RemoveClientFromCache(LayoutObject&) override;
+ bool RemoveClientFromCache(SVGResourceClient&) override;
FloatRect ResourceBoundingBox(const LayoutObject*);
@@ -93,12 +93,12 @@ class LayoutSVGResourceFilter final : public LayoutSVGResourceContainer {
static const LayoutSVGResourceType kResourceType = kFilterResourceType;
LayoutSVGResourceType ResourceType() const override { return kResourceType; }
- FilterData* GetFilterDataForLayoutObject(const LayoutObject* object) {
- return filter_.at(const_cast<LayoutObject*>(object));
+ FilterData* GetFilterDataForClient(const SVGResourceClient* client) {
+ return filter_.at(const_cast<SVGResourceClient*>(client));
}
- void SetFilterDataForLayoutObject(LayoutObject* object,
- FilterData* filter_data) {
- filter_.Set(object, filter_data);
+ void SetFilterDataForClient(const SVGResourceClient* client,
+ FilterData* filter_data) {
+ filter_.Set(const_cast<SVGResourceClient*>(client), filter_data);
}
protected:
@@ -107,7 +107,8 @@ class LayoutSVGResourceFilter final : public LayoutSVGResourceContainer {
private:
void DisposeFilterMap();
- using FilterMap = PersistentHeapHashMap<LayoutObject*, Member<FilterData>>;
+ using FilterMap =
+ PersistentHeapHashMap<Member<SVGResourceClient>, Member<FilterData>>;
FilterMap filter_;
};
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 ef2795a5292..db3bf84ce05 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
@@ -40,7 +40,8 @@ void LayoutSVGResourceGradient::RemoveAllClientsFromCache(
: SVGResourceClient::kParentOnlyInvalidation);
}
-bool LayoutSVGResourceGradient::RemoveClientFromCache(LayoutObject& client) {
+bool LayoutSVGResourceGradient::RemoveClientFromCache(
+ SVGResourceClient& client) {
auto entry = gradient_map_.find(&client);
if (entry == gradient_map_.end())
return false;
@@ -49,7 +50,7 @@ bool LayoutSVGResourceGradient::RemoveClientFromCache(LayoutObject& client) {
}
SVGPaintServer LayoutSVGResourceGradient::PreparePaintServer(
- const LayoutObject& object,
+ const SVGResourceClient& client,
const FloatRect& object_bounding_box) {
ClearInvalidationMask();
@@ -71,7 +72,7 @@ SVGPaintServer LayoutSVGResourceGradient::PreparePaintServer(
return SVGPaintServer::Invalid();
std::unique_ptr<GradientData>& gradient_data =
- gradient_map_.insert(&object, nullptr).stored_value->value;
+ gradient_map_.insert(&client, nullptr).stored_value->value;
if (!gradient_data)
gradient_data = std::make_unique<GradientData>();
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 3dfbe11d4f5..896308a0796 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
@@ -44,9 +44,9 @@ class LayoutSVGResourceGradient : public LayoutSVGResourcePaintServer {
explicit LayoutSVGResourceGradient(SVGGradientElement*);
void RemoveAllClientsFromCache(bool mark_for_invalidation = true) final;
- bool RemoveClientFromCache(LayoutObject&) final;
+ bool RemoveClientFromCache(SVGResourceClient&) final;
- SVGPaintServer PreparePaintServer(const LayoutObject&,
+ SVGPaintServer PreparePaintServer(const SVGResourceClient&,
const FloatRect& object_bounding_box) final;
bool IsChildAllowed(LayoutObject* child, const ComputedStyle&) const final;
@@ -62,7 +62,9 @@ class LayoutSVGResourceGradient : public LayoutSVGResourcePaintServer {
private:
bool should_collect_gradient_attributes_ : 1;
- HashMap<const LayoutObject*, std::unique_ptr<GradientData>> gradient_map_;
+ using GradientMap = PersistentHeapHashMap<Member<const SVGResourceClient>,
+ std::unique_ptr<GradientData>>;
+ GradientMap gradient_map_;
};
} // namespace blink
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 09f27694cdd..9e256694a52 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
@@ -21,8 +21,8 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_marker.h"
+#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.h"
-#include "third_party/blink/renderer/platform/wtf/auto_reset.h"
namespace blink {
@@ -36,7 +36,7 @@ void LayoutSVGResourceMarker::UpdateLayout() {
if (is_in_layout_)
return;
- AutoReset<bool> in_layout_change(&is_in_layout_, true);
+ base::AutoReset<bool> in_layout_change(&is_in_layout_, true);
// LayoutSVGHiddenContainer overwrites layout(). We need the
// layouting of LayoutSVGContainer for calculating local
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 6c6adbd5e6e..7dead57bf3a 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
@@ -146,7 +146,8 @@ SVGPaintServer SVGPaintServer::RequestForLayoutObject(
if (!paint_description.resource)
return SVGPaintServer(paint_description.color);
SVGPaintServer paint_server = paint_description.resource->PreparePaintServer(
- layout_object, layout_object.ObjectBoundingBox());
+ *SVGResources::GetClient(layout_object),
+ layout_object.ObjectBoundingBox());
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 60010bc3a8e..9f096f3d2a4 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
@@ -103,7 +103,7 @@ class LayoutSVGResourcePaintServer : public LayoutSVGResourceContainer {
~LayoutSVGResourcePaintServer() override;
virtual SVGPaintServer PreparePaintServer(
- const LayoutObject&,
+ const SVGResourceClient&,
const FloatRect& object_bounding_box) = 0;
// Helper utilities used in to access the underlying resources for DRT.
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 98f6a544ddf..af180fc1017 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
@@ -60,7 +60,8 @@ void LayoutSVGResourcePattern::RemoveAllClientsFromCache(
: SVGResourceClient::kParentOnlyInvalidation);
}
-bool LayoutSVGResourcePattern::RemoveClientFromCache(LayoutObject& client) {
+bool LayoutSVGResourcePattern::RemoveClientFromCache(
+ SVGResourceClient& client) {
auto entry = pattern_map_.find(&client);
if (entry == pattern_map_.end())
return false;
@@ -69,7 +70,7 @@ bool LayoutSVGResourcePattern::RemoveClientFromCache(LayoutObject& client) {
}
PatternData* LayoutSVGResourcePattern::PatternForClient(
- const LayoutObject& object,
+ const SVGResourceClient& client,
const FloatRect& object_bounding_box) {
DCHECK(!should_collect_pattern_attributes_);
@@ -77,10 +78,10 @@ PatternData* LayoutSVGResourcePattern::PatternForClient(
// 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(&object))
+ if (PatternData* current_data = pattern_map_.at(&client))
return current_data;
- return pattern_map_.Set(&object, BuildPatternData(object_bounding_box))
+ return pattern_map_.Set(&client, BuildPatternData(object_bounding_box))
.stored_value->value.get();
}
@@ -133,7 +134,7 @@ std::unique_ptr<PatternData> LayoutSVGResourcePattern::BuildPatternData(
}
SVGPaintServer LayoutSVGResourcePattern::PreparePaintServer(
- const LayoutObject& object,
+ const SVGResourceClient& client,
const FloatRect& object_bounding_box) {
ClearInvalidationMask();
@@ -156,7 +157,7 @@ SVGPaintServer LayoutSVGResourcePattern::PreparePaintServer(
object_bounding_box.IsEmpty())
return SVGPaintServer::Invalid();
- PatternData* pattern_data = PatternForClient(object, object_bounding_box);
+ PatternData* pattern_data = PatternForClient(client, object_bounding_box);
if (!pattern_data || !pattern_data->pattern)
return SVGPaintServer::Invalid();
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 b71cd1d29eb..322b3cef08b 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
@@ -42,10 +42,10 @@ class LayoutSVGResourcePattern final : public LayoutSVGResourcePaintServer {
const char* GetName() const override { return "LayoutSVGResourcePattern"; }
void RemoveAllClientsFromCache(bool mark_for_invalidation = true) override;
- bool RemoveClientFromCache(LayoutObject&) override;
+ bool RemoveClientFromCache(SVGResourceClient&) override;
SVGPaintServer PreparePaintServer(
- const LayoutObject&,
+ const SVGResourceClient&,
const FloatRect& object_bounding_box) override;
static const LayoutSVGResourceType kResourceType = kPatternResourceType;
@@ -56,7 +56,7 @@ class LayoutSVGResourcePattern final : public LayoutSVGResourcePaintServer {
const FloatRect& object_bounding_box);
sk_sp<PaintRecord> AsPaintRecord(const FloatSize&,
const AffineTransform&) const;
- PatternData* PatternForClient(const LayoutObject&,
+ PatternData* PatternForClient(const SVGResourceClient&,
const FloatRect& object_bounding_box);
const LayoutSVGResourceContainer* ResolveContentElement() const;
@@ -78,7 +78,9 @@ class LayoutSVGResourcePattern final : public LayoutSVGResourcePaintServer {
// same => we should be able to cache a single display list per
// LayoutSVGResourcePattern + one Pattern(shader) for each client -- this
// would avoid re-recording when multiple clients share the same pattern.
- HashMap<const LayoutObject*, std::unique_ptr<PatternData>> pattern_map_;
+ using PatternMap = PersistentHeapHashMap<Member<const SVGResourceClient>,
+ std::unique_ptr<PatternData>>;
+ PatternMap pattern_map_;
};
} // namespace blink
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 f35b4a16e36..caa1a0d5809 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
@@ -65,7 +65,7 @@ LayoutSVGRoot::LayoutSVGRoot(SVGElement* node)
LayoutSVGRoot::~LayoutSVGRoot() = default;
-void LayoutSVGRoot::ComputeIntrinsicSizingInfo(
+void LayoutSVGRoot::UnscaledIntrinsicSizingInfo(
IntrinsicSizingInfo& intrinsic_sizing_info) const {
// https://www.w3.org/TR/SVG/coords.html#IntrinsicSizing
@@ -91,6 +91,13 @@ void LayoutSVGRoot::ComputeIntrinsicSizingInfo(
intrinsic_sizing_info.Transpose();
}
+void LayoutSVGRoot::ComputeIntrinsicSizingInfo(
+ IntrinsicSizingInfo& intrinsic_sizing_info) const {
+ UnscaledIntrinsicSizingInfo(intrinsic_sizing_info);
+
+ intrinsic_sizing_info.size.Scale(StyleRef().EffectiveZoom());
+}
+
bool LayoutSVGRoot::IsEmbeddedThroughSVGImage() const {
return SVGImage::IsInSVGImage(ToSVGSVGElement(GetNode()));
}
@@ -251,6 +258,7 @@ void LayoutSVGRoot::PaintReplaced(const PaintInfo& paint_info,
void LayoutSVGRoot::WillBeDestroyed() {
SVGResourcesCache::ClientDestroyed(*this);
+ SVGResources::ClearClipPathFilterMask(ToSVGSVGElement(*GetNode()), Style());
LayoutReplaced::WillBeDestroyed();
}
@@ -300,6 +308,8 @@ void LayoutSVGRoot::StyleDidChange(StyleDifference diff,
IntrinsicSizingInfoChanged();
LayoutReplaced::StyleDidChange(diff, old_style);
+ SVGResources::UpdateClipPathFilterMask(ToSVGSVGElement(*GetNode()), old_style,
+ StyleRef());
SVGResourcesCache::ClientStyleChanged(*this, diff, StyleRef());
}
@@ -502,9 +512,11 @@ bool LayoutSVGRoot::NodeAtPoint(HitTestResult& result,
// don't clip to the viewport, the visual overflow rect.
// FIXME: This should be an intersection when rect-based hit tests are
// supported by nodeAtFloatPoint.
- if (ContentBoxRect().Contains(point_in_border_box) ||
- (!ShouldApplyViewportClip() &&
- VisualOverflowRect().Contains(point_in_border_box))) {
+ bool skip_children = (result.GetHitTestRequest().GetStopNode() == this);
+ if (!skip_children &&
+ (ContentBoxRect().Contains(point_in_border_box) ||
+ (!ShouldApplyViewportClip() &&
+ VisualOverflowRect().Contains(point_in_border_box)))) {
const AffineTransform& local_to_parent_transform =
LocalToSVGParentTransform();
if (local_to_parent_transform.IsInvertible()) {
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 8b4c3a51221..70952638ac7 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
@@ -39,7 +39,7 @@ class CORE_EXPORT LayoutSVGRoot final : public LayoutReplaced {
bool IsEmbeddedThroughFrameContainingSVGDocument() const;
void IntrinsicSizingInfoChanged() const;
- void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
+ void UnscaledIntrinsicSizingInfo(IntrinsicSizingInfo&) const;
// If you have a LayoutSVGRoot, use firstChild or lastChild instead.
void SlowFirstChild() const = delete;
@@ -110,6 +110,7 @@ class CORE_EXPORT LayoutSVGRoot final : public LayoutReplaced {
LayoutReplaced::IsOfType(type);
}
+ void ComputeIntrinsicSizingInfo(IntrinsicSizingInfo&) const override;
LayoutUnit ComputeReplacedLogicalWidth(
ShouldComputePreferred = kComputeActual) const override;
LayoutUnit ComputeReplacedLogicalHeight(
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 0545143fb20..7d84e24d65c 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
@@ -62,12 +62,21 @@ LayoutSVGShape::LayoutSVGShape(SVGGeometryElement* node)
LayoutSVGShape::~LayoutSVGShape() = default;
+void LayoutSVGShape::StyleDidChange(StyleDifference diff,
+ const ComputedStyle* old_style) {
+ LayoutSVGModelObject::StyleDidChange(diff, old_style);
+ SVGResources::UpdatePaints(*GetElement(), old_style, StyleRef());
+}
+
+void LayoutSVGShape::WillBeDestroyed() {
+ SVGResources::ClearPaints(*GetElement(), Style());
+ LayoutSVGModelObject::WillBeDestroyed();
+}
+
void LayoutSVGShape::CreatePath() {
if (!path_)
path_ = std::make_unique<Path>();
*path_ = ToSVGGeometryElement(GetElement())->AsPath();
- if (rare_data_.get())
- rare_data_->cached_non_scaling_stroke_path_.Clear();
}
float LayoutSVGShape::DashScaleFactor() const {
@@ -78,8 +87,15 @@ float LayoutSVGShape::DashScaleFactor() const {
void LayoutSVGShape::UpdateShapeFromElement() {
CreatePath();
-
fill_bounding_box_ = CalculateObjectBoundingBox();
+
+ if (HasNonScalingStroke()) {
+ // NonScalingStrokeTransform may depend on LocalTransform which in turn may
+ // depend on ObjectBoundingBox, thus we need to call them in this order.
+ UpdateLocalTransform();
+ UpdateNonScalingStrokeData();
+ }
+
stroke_bounding_box_ = CalculateStrokeBoundingBox();
}
@@ -139,17 +155,21 @@ FloatRect LayoutSVGShape::HitTestStrokeBoundingBox() const {
}
bool LayoutSVGShape::ShapeDependentStrokeContains(const FloatPoint& point) {
- DCHECK(path_);
+ // In case the subclass didn't create path during UpdateShapeFromElement()
+ // for optimization but still calls this method.
+ if (!HasPath())
+ CreatePath();
+
StrokeData stroke_data;
SVGLayoutSupport::ApplyStrokeStyleToStrokeData(stroke_data, StyleRef(), *this,
DashScaleFactor());
if (HasNonScalingStroke()) {
- AffineTransform non_scaling_transform = NonScalingStrokeTransform();
- Path* use_path = NonScalingStrokePath(path_.get(), non_scaling_transform);
-
- return use_path->StrokeContains(non_scaling_transform.MapPoint(point),
- stroke_data);
+ // The reason is similar to the above code about HasPath().
+ if (!rare_data_)
+ UpdateNonScalingStrokeData();
+ return NonScalingStrokePath().StrokeContains(
+ NonScalingStrokeTransform().MapPoint(point), stroke_data);
}
return path_->StrokeContains(point, stroke_data);
@@ -243,7 +263,10 @@ void LayoutSVGShape::UpdateLayout() {
// UpdateShapeFromElement() also updates the object & stroke bounds - which
// feeds into the visual rect - so we need to call it for both the
// shape-update and the bounds-update flag.
- if (needs_shape_update_ || needs_boundaries_update_) {
+ // We also need to update stroke bounds if HasNonScalingStroke() because the
+ // shape may be affected by ancestor transforms.
+ if (needs_shape_update_ || needs_boundaries_update_ ||
+ HasNonScalingStroke()) {
FloatRect old_object_bounding_box = ObjectBoundingBox();
UpdateShapeFromElement();
if (old_object_bounding_box != ObjectBoundingBox()) {
@@ -292,21 +315,9 @@ void LayoutSVGShape::UpdateLayout() {
ClearNeedsLayout();
}
-Path* LayoutSVGShape::NonScalingStrokePath(
- const Path* path,
- const AffineTransform& stroke_transform) const {
- LayoutSVGShapeRareData& rare_data = EnsureRareData();
- if (!rare_data.cached_non_scaling_stroke_path_.IsEmpty() &&
- stroke_transform == rare_data.cached_non_scaling_stroke_transform_)
- return &rare_data.cached_non_scaling_stroke_path_;
-
- rare_data.cached_non_scaling_stroke_path_ = *path;
- rare_data.cached_non_scaling_stroke_path_.Transform(stroke_transform);
- rare_data.cached_non_scaling_stroke_transform_ = stroke_transform;
- return &rare_data.cached_non_scaling_stroke_path_;
-}
+void LayoutSVGShape::UpdateNonScalingStrokeData() {
+ DCHECK(HasNonScalingStroke());
-AffineTransform LayoutSVGShape::NonScalingStrokeTransform() const {
// Compute the CTM to the SVG root. This should probably be the CTM all the
// way to the "canvas" of the page ("host" coordinate system), but with our
// current approach of applying/painting non-scaling-stroke, that can break in
@@ -320,7 +331,15 @@ AffineTransform LayoutSVGShape::NonScalingStrokeTransform() const {
// here.
t.SetE(0);
t.SetF(0);
- return t;
+
+ auto& rare_data = EnsureRareData();
+ if (rare_data.non_scaling_stroke_transform_ != t) {
+ SetShouldDoFullPaintInvalidation(PaintInvalidationReason::kStyle);
+ rare_data.non_scaling_stroke_transform_ = t;
+ }
+
+ rare_data.non_scaling_stroke_path_ = *path_;
+ rare_data.non_scaling_stroke_path_.Transform(t);
}
void LayoutSVGShape::Paint(const PaintInfo& paint_info,
@@ -400,12 +419,11 @@ FloatRect LayoutSVGShape::CalculateStrokeBoundingBox() const {
SVGLayoutSupport::ApplyStrokeStyleToStrokeData(stroke_data, StyleRef(),
*this, DashScaleFactor());
if (HasNonScalingStroke()) {
- AffineTransform non_scaling_transform = NonScalingStrokeTransform();
+ const auto& non_scaling_transform = NonScalingStrokeTransform();
if (non_scaling_transform.IsInvertible()) {
- Path* use_path =
- NonScalingStrokePath(path_.get(), non_scaling_transform);
+ const auto& non_scaling_stroke = NonScalingStrokePath();
FloatRect stroke_bounding_rect =
- use_path->StrokeBoundingRect(stroke_data);
+ non_scaling_stroke.StrokeBoundingRect(stroke_data);
stroke_bounding_rect =
non_scaling_transform.Inverse().MapRect(stroke_bounding_rect);
stroke_bounding_box.Unite(stroke_bounding_rect);
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 cd1d8279bb5..d2bdfa17f82 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
@@ -51,8 +51,8 @@ struct LayoutSVGShapeRareData {
public:
LayoutSVGShapeRareData() = default;
- Path cached_non_scaling_stroke_path_;
- AffineTransform cached_non_scaling_stroke_transform_;
+ Path non_scaling_stroke_path_;
+ AffineTransform non_scaling_stroke_transform_;
DISALLOW_COPY_AND_ASSIGN(LayoutSVGShapeRareData);
};
@@ -88,8 +88,17 @@ class LayoutSVGShape : public LayoutSVGModelObject {
bool HasNonScalingStroke() const {
return Style()->SvgStyle().VectorEffect() == VE_NON_SCALING_STROKE;
}
- Path* NonScalingStrokePath(const Path*, const AffineTransform&) const;
- AffineTransform NonScalingStrokeTransform() const;
+ const Path& NonScalingStrokePath() const {
+ DCHECK(HasNonScalingStroke());
+ DCHECK(rare_data_);
+ return rare_data_->non_scaling_stroke_path_;
+ }
+ const AffineTransform& NonScalingStrokeTransform() const {
+ DCHECK(HasNonScalingStroke());
+ DCHECK(rare_data_);
+ return rare_data_->non_scaling_stroke_transform_;
+ }
+
AffineTransform LocalSVGTransform() const final { return local_transform_; }
virtual const Vector<MarkerPosition>* MarkerPositions() const {
@@ -107,6 +116,9 @@ class LayoutSVGShape : public LayoutSVGModelObject {
const char* GetName() const override { return "LayoutSVGShape"; }
protected:
+ void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
+ void WillBeDestroyed() override;
+
float VisualRectOutsetForRasterEffects() const override;
void ClearPath() { path_.reset(); }
@@ -155,6 +167,7 @@ class LayoutSVGShape : public LayoutSVGModelObject {
FloatRect StrokeBoundingBox() const final { return stroke_bounding_box_; }
FloatRect CalculateObjectBoundingBox() const;
FloatRect CalculateStrokeBoundingBox() const;
+ void UpdateNonScalingStrokeData();
bool UpdateLocalTransform();
private:
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 c1b5acc44e7..5a85c7afdf3 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
@@ -38,6 +38,7 @@
#include "third_party/blink/renderer/core/layout/svg/layout_svg_root.h"
#include "third_party/blink/renderer/core/layout/svg/line/svg_root_inline_box.h"
#include "third_party/blink/renderer/core/layout/svg/svg_layout_support.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_text_layout_attributes_builder.h"
#include "third_party/blink/renderer/core/paint/svg_text_painter.h"
@@ -71,9 +72,15 @@ LayoutSVGText::~LayoutSVGText() {
DCHECK(descendant_text_nodes_.IsEmpty());
}
+void LayoutSVGText::StyleDidChange(StyleDifference diff,
+ const ComputedStyle* old_style) {
+ LayoutSVGBlock::StyleDidChange(diff, old_style);
+ SVGResources::UpdatePaints(*GetElement(), old_style, StyleRef());
+}
+
void LayoutSVGText::WillBeDestroyed() {
descendant_text_nodes_.clear();
-
+ SVGResources::ClearPaints(*GetElement(), Style());
LayoutSVGBlock::WillBeDestroyed();
}
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 e22ee07774a..1523d8f454c 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
@@ -85,6 +85,8 @@ class LayoutSVGText final : public LayoutSVGBlock {
void AddChild(LayoutObject* child,
LayoutObject* before_child = nullptr) override;
void RemoveChild(LayoutObject*) override;
+
+ void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
void WillBeDestroyed() override;
RootInlineBox* CreateRootInlineBox() override;
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 380077331fa..5319bbbf394 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
@@ -199,7 +199,8 @@ bool SVGRootInlineBox::NodeAtPoint(HitTestResult& result,
const LayoutPoint& accumulated_offset,
LayoutUnit line_top,
LayoutUnit line_bottom) {
- for (InlineBox* leaf = FirstLeafChild(); leaf; leaf = leaf->NextLeafChild()) {
+ // Iterate the text boxes in reverse so that the top-most node will be considered first.
+ for (InlineBox* leaf = LastLeafChild(); leaf; leaf = leaf->PrevLeafChild()) {
if (!leaf->IsSVGInlineTextBox())
continue;
if (leaf->NodeAtPoint(result, location_in_container, accumulated_offset,
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 10e7e46daad..45a7d90fa47 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
@@ -40,8 +40,8 @@
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/svg/svg_element.h"
-#include "third_party/blink/renderer/platform/geometry/transform_state.h"
#include "third_party/blink/renderer/platform/graphics/stroke_data.h"
+#include "third_party/blink/renderer/platform/transforms/transform_state.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
namespace blink {
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 6f0461021d1..8dbf9a61289 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
@@ -86,13 +86,13 @@ class TextStreamSeparator {
: separator_(s), need_to_separate_(false) {}
private:
- friend TextStream& operator<<(TextStream&, TextStreamSeparator&);
+ friend WTF::TextStream& operator<<(WTF::TextStream&, TextStreamSeparator&);
String separator_;
bool need_to_separate_;
};
-TextStream& operator<<(TextStream& ts, TextStreamSeparator& sep) {
+WTF::TextStream& operator<<(WTF::TextStream& ts, TextStreamSeparator& sep) {
if (sep.need_to_separate_)
ts << sep.separator_;
else
@@ -101,28 +101,42 @@ TextStream& operator<<(TextStream& ts, TextStreamSeparator& sep) {
}
template <typename ValueType>
-static void WriteNameValuePair(TextStream& ts,
+static void WriteNameValuePair(WTF::TextStream& ts,
const char* name,
ValueType value) {
ts << " [" << name << "=" << value << "]";
}
+static void WriteSVGResourceIfNotNull(WTF::TextStream& ts,
+ const char* name,
+ const StyleSVGResource* value,
+ TreeScope& tree_scope) {
+ if (!value)
+ return;
+ AtomicString id = SVGURIReference::FragmentIdentifierFromIRIString(
+ value->Url(), tree_scope);
+ WriteNameValuePair(ts, name, id);
+}
+
template <typename ValueType>
-static void WriteNameAndQuotedValue(TextStream& ts,
+static void WriteNameAndQuotedValue(WTF::TextStream& ts,
const char* name,
ValueType value) {
ts << " [" << name << "=\"" << value << "\"]";
}
-static void WriteIfNotEmpty(TextStream& ts,
- const char* name,
- const String& value) {
- if (!value.IsEmpty())
- WriteNameValuePair(ts, name, value);
+static void WriteQuotedSVGResource(WTF::TextStream& ts,
+ const char* name,
+ const StyleSVGResource* value,
+ TreeScope& tree_scope) {
+ DCHECK(value);
+ AtomicString id = SVGURIReference::FragmentIdentifierFromIRIString(
+ value->Url(), tree_scope);
+ WriteNameAndQuotedValue(ts, name, id);
}
template <typename ValueType>
-static void WriteIfNotDefault(TextStream& ts,
+static void WriteIfNotDefault(WTF::TextStream& ts,
const char* name,
ValueType value,
ValueType default_value) {
@@ -130,7 +144,8 @@ static void WriteIfNotDefault(TextStream& ts,
WriteNameValuePair(ts, name, value);
}
-TextStream& operator<<(TextStream& ts, const AffineTransform& transform) {
+WTF::TextStream& operator<<(WTF::TextStream& ts,
+ const AffineTransform& transform) {
if (transform.IsIdentity()) {
ts << "identity";
} else {
@@ -142,7 +157,7 @@ TextStream& operator<<(TextStream& ts, const AffineTransform& transform) {
return ts;
}
-static TextStream& operator<<(TextStream& ts, const WindRule rule) {
+static WTF::TextStream& operator<<(WTF::TextStream& ts, const WindRule rule) {
switch (rule) {
case RULE_NONZERO:
ts << "NON-ZERO";
@@ -174,39 +189,26 @@ String SVGEnumerationToString(Enum value) {
} // namespace
-static TextStream& operator<<(TextStream& ts,
- const SVGUnitTypes::SVGUnitType& unit_type) {
+static WTF::TextStream& operator<<(WTF::TextStream& ts,
+ const SVGUnitTypes::SVGUnitType& unit_type) {
ts << SVGEnumerationToString<SVGUnitTypes::SVGUnitType>(unit_type);
return ts;
}
-static TextStream& operator<<(TextStream& ts,
- const SVGMarkerUnitsType& marker_unit) {
+static WTF::TextStream& operator<<(WTF::TextStream& ts,
+ const SVGMarkerUnitsType& marker_unit) {
ts << SVGEnumerationToString<SVGMarkerUnitsType>(marker_unit);
return ts;
}
-static TextStream& operator<<(TextStream& ts,
- const SVGMarkerOrientType& orient_type) {
+static WTF::TextStream& operator<<(WTF::TextStream& ts,
+ const SVGMarkerOrientType& orient_type) {
ts << SVGEnumerationToString<SVGMarkerOrientType>(orient_type);
return ts;
}
-// FIXME: Maybe this should be in DashArray.cpp
-static TextStream& operator<<(TextStream& ts, const DashArray& a) {
- ts << "{";
- DashArray::const_iterator end = a.end();
- for (DashArray::const_iterator it = a.begin(); it != end; ++it) {
- if (it != a.begin())
- ts << ", ";
- ts << *it;
- }
- ts << "}";
- return ts;
-}
-
// FIXME: Maybe this should be in GraphicsTypes.cpp
-static TextStream& operator<<(TextStream& ts, LineCap style) {
+static WTF::TextStream& operator<<(WTF::TextStream& ts, LineCap style) {
switch (style) {
case kButtCap:
ts << "BUTT";
@@ -222,7 +224,7 @@ static TextStream& operator<<(TextStream& ts, LineCap style) {
}
// FIXME: Maybe this should be in GraphicsTypes.cpp
-static TextStream& operator<<(TextStream& ts, LineJoin style) {
+static WTF::TextStream& operator<<(WTF::TextStream& ts, LineJoin style) {
switch (style) {
case kMiterJoin:
ts << "MITER";
@@ -237,13 +239,14 @@ static TextStream& operator<<(TextStream& ts, LineJoin style) {
return ts;
}
-static TextStream& operator<<(TextStream& ts, const SVGSpreadMethodType& type) {
+static WTF::TextStream& operator<<(WTF::TextStream& ts,
+ const SVGSpreadMethodType& type) {
ts << SVGEnumerationToString<SVGSpreadMethodType>(type).UpperASCII();
return ts;
}
static void WriteSVGPaintingResource(
- TextStream& ts,
+ WTF::TextStream& ts,
const SVGPaintDescription& paint_description) {
DCHECK(paint_description.is_valid);
if (!paint_description.resource) {
@@ -268,7 +271,7 @@ static void WriteSVGPaintingResource(
ts << " [id=\"" << element->GetIdAttribute() << "\"]";
}
-static void WriteStyle(TextStream& ts, const LayoutObject& object) {
+static void WriteStyle(WTF::TextStream& ts, const LayoutObject& object) {
const ComputedStyle& style = object.StyleRef();
const SVGComputedStyle& svg_style = style.SvgStyle();
@@ -326,19 +329,24 @@ static void WriteStyle(TextStream& ts, const LayoutObject& object) {
WriteIfNotDefault(ts, "clip rule", svg_style.ClipRule(), RULE_NONZERO);
}
- WriteIfNotEmpty(ts, "start marker", svg_style.MarkerStartResource());
- WriteIfNotEmpty(ts, "middle marker", svg_style.MarkerMidResource());
- WriteIfNotEmpty(ts, "end marker", svg_style.MarkerEndResource());
+ TreeScope& tree_scope = object.GetDocument();
+ WriteSVGResourceIfNotNull(ts, "start marker", svg_style.MarkerStartResource(),
+ tree_scope);
+ WriteSVGResourceIfNotNull(ts, "middle marker", svg_style.MarkerMidResource(),
+ tree_scope);
+ WriteSVGResourceIfNotNull(ts, "end marker", svg_style.MarkerEndResource(),
+ tree_scope);
}
-static TextStream& WritePositionAndStyle(TextStream& ts,
- const LayoutObject& object) {
+static WTF::TextStream& WritePositionAndStyle(WTF::TextStream& ts,
+ const LayoutObject& object) {
ts << " " << object.ObjectBoundingBox();
WriteStyle(ts, object);
return ts;
}
-static TextStream& operator<<(TextStream& ts, const LayoutSVGShape& shape) {
+static WTF::TextStream& operator<<(WTF::TextStream& ts,
+ const LayoutSVGShape& shape) {
WritePositionAndStyle(ts, shape);
SVGElement* svg_element = shape.GetElement();
@@ -410,13 +418,15 @@ static TextStream& operator<<(TextStream& ts, const LayoutSVGShape& shape) {
return ts;
}
-static TextStream& operator<<(TextStream& ts, const LayoutSVGRoot& root) {
+static WTF::TextStream& operator<<(WTF::TextStream& ts,
+ const LayoutSVGRoot& root) {
ts << " " << root.FrameRect();
WriteStyle(ts, root);
return ts;
}
-static void WriteLayoutSVGTextBox(TextStream& ts, const LayoutSVGText& text) {
+static void WriteLayoutSVGTextBox(WTF::TextStream& ts,
+ const LayoutSVGText& text) {
SVGRootInlineBox* box = ToSVGRootInlineBox(text.FirstRootBox());
if (!box)
return;
@@ -433,7 +443,7 @@ static void WriteLayoutSVGTextBox(TextStream& ts, const LayoutSVGText& text) {
}
}
-static inline void WriteSVGInlineTextBox(TextStream& ts,
+static inline void WriteSVGInlineTextBox(WTF::TextStream& ts,
SVGInlineTextBox* text_box,
int indent) {
Vector<SVGTextFragment>& fragments = text_box->TextFragments();
@@ -498,7 +508,7 @@ static inline void WriteSVGInlineTextBox(TextStream& ts,
}
}
-static inline void WriteSVGInlineTextBoxes(TextStream& ts,
+static inline void WriteSVGInlineTextBoxes(WTF::TextStream& ts,
const LayoutText& text,
int indent) {
for (InlineTextBox* box : text.TextBoxes()) {
@@ -509,7 +519,7 @@ static inline void WriteSVGInlineTextBoxes(TextStream& ts,
}
}
-static void WriteStandardPrefix(TextStream& ts,
+static void WriteStandardPrefix(WTF::TextStream& ts,
const LayoutObject& object,
int indent) {
WriteIndent(ts, indent);
@@ -519,7 +529,7 @@ static void WriteStandardPrefix(TextStream& ts,
ts << " {" << object.GetNode()->nodeName() << "}";
}
-static void WriteChildren(TextStream& ts,
+static void WriteChildren(WTF::TextStream& ts,
const LayoutObject& object,
int indent) {
for (LayoutObject* child = object.SlowFirstChild(); child;
@@ -528,7 +538,7 @@ static void WriteChildren(TextStream& ts,
}
static inline void WriteCommonGradientProperties(
- TextStream& ts,
+ WTF::TextStream& ts,
const GradientAttributes& attrs) {
WriteNameValuePair(ts, "gradientUnits", attrs.GradientUnits());
@@ -546,7 +556,7 @@ static inline void WriteCommonGradientProperties(
}
}
-void WriteSVGResourceContainer(TextStream& ts,
+void WriteSVGResourceContainer(WTF::TextStream& ts,
const LayoutObject& object,
int indent) {
WriteStandardPrefix(ts, object, indent);
@@ -652,7 +662,7 @@ void WriteSVGResourceContainer(TextStream& ts,
WriteChildren(ts, object, indent);
}
-void WriteSVGContainer(TextStream& ts,
+void WriteSVGContainer(WTF::TextStream& ts,
const LayoutObject& container,
int indent) {
// Currently LayoutSVGResourceFilterPrimitive has no meaningful output.
@@ -665,13 +675,13 @@ void WriteSVGContainer(TextStream& ts,
WriteChildren(ts, container, indent);
}
-void Write(TextStream& ts, const LayoutSVGRoot& root, int indent) {
+void Write(WTF::TextStream& ts, const LayoutSVGRoot& root, int indent) {
WriteStandardPrefix(ts, root, indent);
ts << root << "\n";
WriteChildren(ts, root, indent);
}
-void WriteSVGText(TextStream& ts, const LayoutSVGText& text, int indent) {
+void WriteSVGText(WTF::TextStream& ts, const LayoutSVGText& text, int indent) {
WriteStandardPrefix(ts, text, indent);
WritePositionAndStyle(ts, text);
WriteLayoutSVGTextBox(ts, text);
@@ -680,7 +690,9 @@ void WriteSVGText(TextStream& ts, const LayoutSVGText& text, int indent) {
WriteChildren(ts, text, indent);
}
-void WriteSVGInline(TextStream& ts, const LayoutSVGInline& text, int indent) {
+void WriteSVGInline(WTF::TextStream& ts,
+ const LayoutSVGInline& text,
+ int indent) {
WriteStandardPrefix(ts, text, indent);
WritePositionAndStyle(ts, text);
ts << "\n";
@@ -688,7 +700,7 @@ void WriteSVGInline(TextStream& ts, const LayoutSVGInline& text, int indent) {
WriteChildren(ts, text, indent);
}
-void WriteSVGInlineText(TextStream& ts,
+void WriteSVGInlineText(WTF::TextStream& ts,
const LayoutSVGInlineText& text,
int indent) {
WriteStandardPrefix(ts, text, indent);
@@ -698,20 +710,24 @@ void WriteSVGInlineText(TextStream& ts,
WriteSVGInlineTextBoxes(ts, text, indent);
}
-void WriteSVGImage(TextStream& ts, const LayoutSVGImage& image, int indent) {
+void WriteSVGImage(WTF::TextStream& ts,
+ const LayoutSVGImage& image,
+ int indent) {
WriteStandardPrefix(ts, image, indent);
WritePositionAndStyle(ts, image);
ts << "\n";
WriteResources(ts, image, indent);
}
-void Write(TextStream& ts, const LayoutSVGShape& shape, int indent) {
+void Write(WTF::TextStream& ts, const LayoutSVGShape& shape, int indent) {
WriteStandardPrefix(ts, shape, indent);
ts << shape << "\n";
WriteResources(ts, shape, indent);
}
-void WriteResources(TextStream& ts, const LayoutObject& object, int indent) {
+void WriteResources(WTF::TextStream& ts,
+ const LayoutObject& object,
+ int indent) {
SVGResources* resources =
SVGResourcesCache::CachedResourcesForLayoutObject(object);
if (!resources)
@@ -721,7 +737,8 @@ void WriteResources(TextStream& ts, const LayoutObject& object, int indent) {
if (LayoutSVGResourceMasker* masker = resources->Masker()) {
WriteIndent(ts, indent);
ts << " ";
- WriteNameAndQuotedValue(ts, "masker", style.SvgStyle().MaskerResource());
+ WriteQuotedSVGResource(ts, "masker", style.SvgStyle().MaskerResource(),
+ tree_scope);
ts << " ";
WriteStandardPrefix(ts, *masker, 0);
ts << " " << masker->ResourceBoundingBox(&object) << "\n";
diff --git a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.h b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.h
index 25f79408e05..c322a891e29 100644
--- a/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.h
+++ b/chromium/third_party/blink/renderer/core/layout/svg/svg_layout_tree_as_text.h
@@ -26,7 +26,7 @@
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_LAYOUT_TREE_AS_TEXT_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_LAYOUT_SVG_SVG_LAYOUT_TREE_AS_TEXT_H_
-#include "third_party/blink/renderer/platform/text/text_stream.h"
+#include "third_party/blink/renderer/platform/wtf/text/text_stream.h"
namespace blink {
@@ -39,15 +39,19 @@ class LayoutSVGRoot;
class LayoutSVGText;
// functions used by the main LayoutTreeAsText code
-void Write(TextStream&, const LayoutSVGShape&, int indent);
-void Write(TextStream&, const LayoutSVGRoot&, int indent);
-void WriteSVGResourceContainer(TextStream&, const LayoutObject&, int indent);
-void WriteSVGContainer(TextStream&, const LayoutObject&, int indent);
-void WriteSVGImage(TextStream&, const LayoutSVGImage&, int indent);
-void WriteSVGInlineText(TextStream&, const LayoutSVGInlineText&, int indent);
-void WriteSVGText(TextStream&, const LayoutSVGText&, int indent);
-void WriteSVGInline(TextStream&, const LayoutSVGInline&, int indent);
-void WriteResources(TextStream&, const LayoutObject&, int indent);
+void Write(WTF::TextStream&, const LayoutSVGShape&, int indent);
+void Write(WTF::TextStream&, const LayoutSVGRoot&, int indent);
+void WriteSVGResourceContainer(WTF::TextStream&,
+ const LayoutObject&,
+ int indent);
+void WriteSVGContainer(WTF::TextStream&, const LayoutObject&, int indent);
+void WriteSVGImage(WTF::TextStream&, const LayoutSVGImage&, int indent);
+void WriteSVGInlineText(WTF::TextStream&,
+ const LayoutSVGInlineText&,
+ int indent);
+void WriteSVGText(WTF::TextStream&, const LayoutSVGText&, int indent);
+void WriteSVGInline(WTF::TextStream&, const LayoutSVGInline&, int indent);
+void WriteResources(WTF::TextStream&, const LayoutObject&, int indent);
} // namespace blink
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 32789c4aa5c..b0c868405df 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,6 +27,7 @@
#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/svg_resources_cache.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/svg/svg_pattern_element.h"
#include "third_party/blink/renderer/core/svg/svg_resource.h"
@@ -44,6 +45,10 @@ using namespace SVGNames;
SVGResources::SVGResources() : linked_resource_(nullptr) {}
+SVGResourceClient* SVGResources::GetClient(const LayoutObject& object) {
+ return ToSVGElement(object.GetNode())->GetSVGResourceClient();
+}
+
static HashSet<AtomicString>& ClipperFilterMaskerTags() {
DEFINE_STATIC_LOCAL(
HashSet<AtomicString>, tag_list,
@@ -113,28 +118,24 @@ bool IsResourceOfType<LayoutSVGResourcePaintServer>(
return container->IsSVGPaintServer();
}
-template <>
-bool IsResourceOfType<LayoutSVGResourceContainer>(
- LayoutSVGResourceContainer* container) {
- return true;
-}
-
template <typename ContainerType>
-ContainerType* AttachToResource(SVGTreeScopeResources& tree_scope_resources,
- const AtomicString& id,
- SVGElement& element) {
- LocalSVGResource* resource = tree_scope_resources.ResourceForId(id);
+ContainerType* CastResource(SVGResource* resource) {
if (!resource)
return nullptr;
if (LayoutSVGResourceContainer* container = resource->ResourceContainer()) {
if (IsResourceOfType<ContainerType>(container))
return static_cast<ContainerType*>(container);
}
- resource->AddWatch(element);
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_;
@@ -160,10 +161,6 @@ std::unique_ptr<SVGResources> SVGResources::BuildResources(
const AtomicString& tag_name = element.localName();
DCHECK(!tag_name.IsNull());
- TreeScope& tree_scope = element.TreeScopeForIdResolution();
- SVGTreeScopeResources& tree_scope_resources =
- tree_scope.EnsureSVGTreeScopedResources();
-
const SVGComputedStyle& style = computed_style.SvgStyle();
std::unique_ptr<SVGResources> resources;
@@ -173,11 +170,9 @@ std::unique_ptr<SVGResources> SVGResources::BuildResources(
if (clip_path_operation->GetType() == ClipPathOperation::REFERENCE) {
const ReferenceClipPathOperation& clip_path_reference =
ToReferenceClipPathOperation(*clip_path_operation);
- AtomicString id = SVGURIReference::FragmentIdentifierFromIRIString(
- clip_path_reference.Url(), tree_scope);
EnsureResources(resources).SetClipper(
- AttachToResource<LayoutSVGResourceClipper>(tree_scope_resources, id,
- element));
+ CastResource<LayoutSVGResourceClipper>(
+ clip_path_reference.Resource()));
}
}
@@ -188,80 +183,60 @@ std::unique_ptr<SVGResources> SVGResources::BuildResources(
if (filter_operation.GetType() == FilterOperation::REFERENCE) {
const auto& reference_filter_operation =
ToReferenceFilterOperation(filter_operation);
- AtomicString id = SVGURIReference::FragmentIdentifierFromIRIString(
- reference_filter_operation.Url(), tree_scope);
EnsureResources(resources).SetFilter(
- AttachToResource<LayoutSVGResourceFilter>(tree_scope_resources,
- id, element));
+ CastResource<LayoutSVGResourceFilter>(
+ reference_filter_operation.Resource()));
}
}
}
- if (style.HasMasker()) {
+ if (StyleSVGResource* masker_resource = style.MaskerResource()) {
EnsureResources(resources).SetMasker(
- AttachToResource<LayoutSVGResourceMasker>(
- tree_scope_resources, style.MaskerResource(), element));
+ CastResource<LayoutSVGResourceMasker>(*masker_resource));
}
}
if (style.HasMarkers() && SupportsMarkers(element)) {
- EnsureResources(resources).SetMarkerStart(
- AttachToResource<LayoutSVGResourceMarker>(
- tree_scope_resources, style.MarkerStartResource(), element));
- EnsureResources(resources).SetMarkerMid(
- AttachToResource<LayoutSVGResourceMarker>(
- tree_scope_resources, style.MarkerMidResource(), element));
- EnsureResources(resources).SetMarkerEnd(
- AttachToResource<LayoutSVGResourceMarker>(
- tree_scope_resources, style.MarkerEndResource(), element));
+ if (StyleSVGResource* marker_start_resource = style.MarkerStartResource()) {
+ EnsureResources(resources).SetMarkerStart(
+ CastResource<LayoutSVGResourceMarker>(*marker_start_resource));
+ }
+ if (StyleSVGResource* marker_mid_resource = style.MarkerMidResource()) {
+ EnsureResources(resources).SetMarkerMid(
+ CastResource<LayoutSVGResourceMarker>(*marker_mid_resource));
+ }
+ if (StyleSVGResource* marker_end_resource = style.MarkerEndResource()) {
+ EnsureResources(resources).SetMarkerEnd(
+ CastResource<LayoutSVGResourceMarker>(*marker_end_resource));
+ }
}
if (FillAndStrokeTags().Contains(tag_name)) {
- if (style.HasFill() && style.FillPaint().HasUrl()) {
- AtomicString id = SVGURIReference::FragmentIdentifierFromIRIString(
- style.FillPaint().GetUrl(), tree_scope);
+ if (StyleSVGResource* fill_resource = style.FillPaint().Resource()) {
EnsureResources(resources).SetFill(
- AttachToResource<LayoutSVGResourcePaintServer>(tree_scope_resources,
- id, element));
+ CastResource<LayoutSVGResourcePaintServer>(*fill_resource));
}
- if (style.HasStroke() && style.StrokePaint().HasUrl()) {
- AtomicString id = SVGURIReference::FragmentIdentifierFromIRIString(
- style.StrokePaint().GetUrl(), tree_scope);
+ if (StyleSVGResource* stroke_resource = style.StrokePaint().Resource()) {
EnsureResources(resources).SetStroke(
- AttachToResource<LayoutSVGResourcePaintServer>(tree_scope_resources,
- id, element));
+ CastResource<LayoutSVGResourcePaintServer>(*stroke_resource));
}
}
if (auto* pattern = ToSVGPatternElementOrNull(element)) {
- AtomicString id = SVGURIReference::FragmentIdentifierFromIRIString(
- pattern->HrefString(), tree_scope);
- EnsureResources(resources).SetLinkedResource(
- AttachToResource<LayoutSVGResourceContainer>(tree_scope_resources, id,
- element));
+ const SVGPatternElement* directly_referenced_pattern =
+ pattern->ReferencedElement();
+ if (directly_referenced_pattern) {
+ EnsureResources(resources).SetLinkedResource(
+ ToLayoutSVGResourceContainerOrNull(
+ directly_referenced_pattern->GetLayoutObject()));
+ }
}
return (!resources || !resources->HasResourceData()) ? nullptr
: std::move(resources);
}
-void SVGResources::RemoveUnreferencedResources(const LayoutObject& object) {
- SVGTreeScopeResources& tree_scope_resources =
- ToSVGElement(*object.GetNode())
- .TreeScopeForIdResolution()
- .EnsureSVGTreeScopedResources();
- tree_scope_resources.RemoveUnreferencedResources();
-}
-
-void SVGResources::RemoveWatchesForElement(Element& element) {
- SECURITY_DCHECK(element.IsSVGElement());
- SVGElement& svg_element = ToSVGElement(element);
- SVGTreeScopeResources& tree_scope_resources =
- svg_element.TreeScopeForIdResolution().EnsureSVGTreeScopedResources();
- tree_scope_resources.RemoveWatchesForElement(svg_element);
-}
-
void SVGResources::LayoutIfNeeded() {
if (clipper_filter_masker_data_) {
if (LayoutSVGResourceClipper* clipper =
@@ -294,7 +269,7 @@ void SVGResources::LayoutIfNeeded() {
}
InvalidationModeMask SVGResources::RemoveClientFromCacheAffectingObjectBounds(
- LayoutObject& client) const {
+ SVGResourceClient& client) const {
if (!clipper_filter_masker_data_)
return 0;
InvalidationModeMask invalidation_flags = 0;
@@ -310,7 +285,7 @@ InvalidationModeMask SVGResources::RemoveClientFromCacheAffectingObjectBounds(
}
InvalidationModeMask SVGResources::RemoveClientFromCache(
- LayoutObject& client) const {
+ SVGResourceClient& client) const {
if (!HasResourceData())
return 0;
@@ -648,4 +623,145 @@ void SVGResources::Dump(const LayoutObject* object) {
}
#endif
+void SVGResources::UpdateClipPathFilterMask(SVGElement& element,
+ const ComputedStyle* old_style,
+ const ComputedStyle& style) {
+ const bool had_client = element.GetSVGResourceClient();
+ if (auto* reference_clip =
+ ToReferenceClipPathOperationOrNull(style.ClipPath()))
+ reference_clip->AddClient(element.EnsureSVGResourceClient());
+ if (style.HasFilter())
+ style.Filter().AddClient(element.EnsureSVGResourceClient());
+ if (StyleSVGResource* masker_resource = style.SvgStyle().MaskerResource())
+ masker_resource->AddClient(element.EnsureSVGResourceClient());
+ if (had_client)
+ ClearClipPathFilterMask(element, old_style);
+}
+
+void SVGResources::ClearClipPathFilterMask(SVGElement& element,
+ const ComputedStyle* style) {
+ if (!style)
+ return;
+ SVGResourceClient* client = element.GetSVGResourceClient();
+ if (!client)
+ return;
+ if (auto* old_reference_clip =
+ ToReferenceClipPathOperationOrNull(style->ClipPath()))
+ old_reference_clip->RemoveClient(*client);
+ if (style->HasFilter())
+ style->Filter().RemoveClient(*client);
+ if (StyleSVGResource* masker_resource = style->SvgStyle().MaskerResource())
+ masker_resource->RemoveClient(*client);
+}
+
+void SVGResources::UpdatePaints(SVGElement& element,
+ const ComputedStyle* old_style,
+ const ComputedStyle& style) {
+ const bool had_client = element.GetSVGResourceClient();
+ const SVGComputedStyle& svg_style = style.SvgStyle();
+ if (StyleSVGResource* paint_resource = svg_style.FillPaint().Resource())
+ paint_resource->AddClient(element.EnsureSVGResourceClient());
+ if (StyleSVGResource* paint_resource = svg_style.StrokePaint().Resource())
+ paint_resource->AddClient(element.EnsureSVGResourceClient());
+ if (had_client)
+ ClearPaints(element, old_style);
+}
+
+void SVGResources::ClearPaints(SVGElement& element,
+ const ComputedStyle* style) {
+ if (!style)
+ return;
+ SVGResourceClient* client = element.GetSVGResourceClient();
+ if (!client)
+ return;
+ const SVGComputedStyle& old_svg_style = style->SvgStyle();
+ if (StyleSVGResource* paint_resource = old_svg_style.FillPaint().Resource())
+ paint_resource->RemoveClient(*client);
+ if (StyleSVGResource* paint_resource = old_svg_style.StrokePaint().Resource())
+ paint_resource->RemoveClient(*client);
+}
+
+void SVGResources::UpdateMarkers(SVGElement& element,
+ const ComputedStyle* old_style,
+ const ComputedStyle& style) {
+ const bool had_client = element.GetSVGResourceClient();
+ const SVGComputedStyle& svg_style = style.SvgStyle();
+ if (StyleSVGResource* marker_resource = svg_style.MarkerStartResource())
+ marker_resource->AddClient(element.EnsureSVGResourceClient());
+ if (StyleSVGResource* marker_resource = svg_style.MarkerMidResource())
+ marker_resource->AddClient(element.EnsureSVGResourceClient());
+ if (StyleSVGResource* marker_resource = svg_style.MarkerEndResource())
+ marker_resource->AddClient(element.EnsureSVGResourceClient());
+ if (had_client)
+ ClearMarkers(element, old_style);
+}
+
+void SVGResources::ClearMarkers(SVGElement& element,
+ const ComputedStyle* style) {
+ if (!style)
+ return;
+ SVGResourceClient* client = element.GetSVGResourceClient();
+ if (!client)
+ return;
+ const SVGComputedStyle& old_svg_style = style->SvgStyle();
+ if (StyleSVGResource* marker_resource = old_svg_style.MarkerStartResource())
+ marker_resource->RemoveClient(*client);
+ if (StyleSVGResource* marker_resource = old_svg_style.MarkerMidResource())
+ marker_resource->RemoveClient(*client);
+ if (StyleSVGResource* marker_resource = old_svg_style.MarkerEndResource())
+ marker_resource->RemoveClient(*client);
+}
+
+SVGElementResourceClient::SVGElementResourceClient(SVGElement* element)
+ : element_(element) {}
+
+void SVGElementResourceClient::ResourceContentChanged(
+ InvalidationModeMask invalidation_mask) {
+ 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);
+ return;
+ }
+
+ if (mark_for_invalidation) {
+ LayoutSVGResourceContainer::MarkClientForInvalidation(*layout_object,
+ invalidation_mask);
+ }
+
+ // Special case for filter invalidation.
+ if (invalidation_mask & SVGResourceClient::kSkipAncestorInvalidation)
+ return;
+
+ bool needs_layout =
+ invalidation_mask & SVGResourceClient::kLayoutInvalidation;
+ LayoutSVGResourceContainer::MarkForLayoutAndParentResourceInvalidation(
+ *layout_object, needs_layout);
+}
+
+void SVGElementResourceClient::ResourceElementChanged() {
+ if (LayoutObject* layout_object = element_->GetLayoutObject())
+ SVGResourcesCache::ResourceReferenceChanged(*layout_object);
+}
+
+void SVGElementResourceClient::ResourceDestroyed(
+ LayoutSVGResourceContainer* resource) {
+ LayoutObject* layout_object = element_->GetLayoutObject();
+ if (!layout_object)
+ return;
+ SVGResources* resources =
+ SVGResourcesCache::CachedResourcesForLayoutObject(*layout_object);
+ if (resources)
+ resources->ResourceDestroyed(resource);
+}
+
+void SVGElementResourceClient::Trace(Visitor* visitor) {
+ visitor->Trace(element_);
+ SVGResourceClient::Trace(visitor);
+}
+
} // namespace blink
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 8d61dd166fb..a70b4f60af3 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
@@ -25,13 +25,13 @@
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_resource_container.h"
+#include "third_party/blink/renderer/core/svg/svg_resource_client.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/hash_set.h"
namespace blink {
class ComputedStyle;
-class Element;
class LayoutObject;
class LayoutSVGResourceClipper;
class LayoutSVGResourceFilter;
@@ -47,11 +47,23 @@ class SVGResources {
public:
SVGResources();
+ static SVGResourceClient* GetClient(const LayoutObject&);
+
static std::unique_ptr<SVGResources> BuildResources(const LayoutObject&,
const ComputedStyle&);
- static void RemoveWatchesForElement(Element&);
- static void RemoveUnreferencedResources(const LayoutObject&);
+ static void UpdateClipPathFilterMask(SVGElement&,
+ const ComputedStyle* old_style,
+ const ComputedStyle&);
+ static void ClearClipPathFilterMask(SVGElement&, const ComputedStyle*);
+ static void UpdatePaints(SVGElement&,
+ const ComputedStyle* old_style,
+ const ComputedStyle&);
+ static void ClearPaints(SVGElement&, const ComputedStyle*);
+ static void UpdateMarkers(SVGElement&,
+ const ComputedStyle* old_style,
+ const ComputedStyle&);
+ static void ClearMarkers(SVGElement&, const ComputedStyle*);
void LayoutIfNeeded();
@@ -98,9 +110,9 @@ class SVGResources {
void BuildSetOfResources(HashSet<LayoutSVGResourceContainer*>&);
// Methods operating on all cached resources
- InvalidationModeMask RemoveClientFromCache(LayoutObject&) const;
+ InvalidationModeMask RemoveClientFromCache(SVGResourceClient&) const;
InvalidationModeMask RemoveClientFromCacheAffectingObjectBounds(
- LayoutObject&) const;
+ SVGResourceClient&) const;
void ResourceDestroyed(LayoutSVGResourceContainer*);
void ClearReferencesTo(LayoutSVGResourceContainer*);
@@ -188,6 +200,24 @@ class SVGResources {
DISALLOW_COPY_AND_ASSIGN(SVGResources);
};
+class SVGElementResourceClient final
+ : public GarbageCollected<SVGElementResourceClient>,
+ public SVGResourceClient {
+ USING_GARBAGE_COLLECTED_MIXIN(SVGElementResourceClient);
+
+ public:
+ explicit SVGElementResourceClient(SVGElement*);
+
+ void ResourceContentChanged(InvalidationModeMask) override;
+ void ResourceElementChanged() override;
+ void ResourceDestroyed(LayoutSVGResourceContainer*) override;
+
+ void Trace(Visitor*) override;
+
+ private:
+ Member<SVGElement> element_;
+};
+
} // namespace blink
#endif
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 517cc361a62..9cc13bbfbb5 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
@@ -50,24 +50,15 @@ void SVGResourcesCache::AddResourcesFromLayoutObject(
SVGResources* resources =
cache_.Set(&object, std::move(new_resources)).stored_value->value.get();
+ // Run cycle-detection _afterwards_, so self-references can be caught as well.
HashSet<LayoutSVGResourceContainer*> resource_set;
resources->BuildSetOfResources(resource_set);
- // Run cycle-detection _afterwards_, so self-references can be caught as well.
- {
- SVGResourcesCycleSolver solver(object);
- for (auto* resource_container : resource_set) {
- if (solver.FindCycle(resource_container))
- resources->ClearReferencesTo(resource_container);
- }
- resource_set.clear();
+ SVGResourcesCycleSolver solver(object);
+ for (auto* resource_container : resource_set) {
+ if (solver.FindCycle(resource_container))
+ resources->ClearReferencesTo(resource_container);
}
-
- // Walk resources and register the layout object as a client of each resource.
- resources->BuildSetOfResources(resource_set);
-
- for (auto* resource_container : resource_set)
- resource_container->AddClient(object);
}
void SVGResourcesCache::RemoveResourcesFromLayoutObject(LayoutObject& object) {
@@ -77,19 +68,6 @@ void SVGResourcesCache::RemoveResourcesFromLayoutObject(LayoutObject& object) {
// Removal of the resource may cause removal of paint property nodes.
object.SetNeedsPaintPropertyUpdate();
-
- // Walk resources and unregister the layout object as a client of each
- // resource.
- HashSet<LayoutSVGResourceContainer*> resource_set;
- resources->BuildSetOfResources(resource_set);
-
- bool did_empty_client_set = false;
- for (auto* resource_container : resource_set)
- did_empty_client_set |= resource_container->RemoveClient(object);
-
- // Remove any registrations that became empty after the above.
- if (did_empty_client_set)
- SVGResources::RemoveUnreferencedResources(object);
}
static inline SVGResourcesCache& ResourcesCache(Document& document) {
@@ -110,8 +88,9 @@ void SVGResourcesCache::ClientLayoutChanged(LayoutObject& object) {
// 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(object)) {
+ resources->RemoveClientFromCache(*client)) {
LayoutSVGResourceContainer::MarkClientForInvalidation(object,
invalidation_flags);
}
@@ -227,15 +206,27 @@ SVGResourcesCache::TemporaryStyleScope::TemporaryStyleScope(
const ComputedStyle& temporary_style)
: layout_object_(layout_object),
original_style_(style),
+ temporary_style_(temporary_style),
styles_are_equal_(style == temporary_style) {
+ if (styles_are_equal_)
+ return;
+ DCHECK(LayoutObjectCanHaveResources(layout_object_));
+ SVGElement& element = ToSVGElement(*layout_object_.GetNode());
+ SVGResources::UpdatePaints(element, nullptr, temporary_style_);
SwitchTo(temporary_style);
}
-void SVGResourcesCache::TemporaryStyleScope::SwitchTo(
- const ComputedStyle& style) {
- DCHECK(LayoutObjectCanHaveResources(layout_object_));
+SVGResourcesCache::TemporaryStyleScope::~TemporaryStyleScope() {
if (styles_are_equal_)
return;
+ SVGElement& element = ToSVGElement(*layout_object_.GetNode());
+ SVGResources::ClearPaints(element, &temporary_style_);
+ SwitchTo(original_style_);
+}
+
+void SVGResourcesCache::TemporaryStyleScope::SwitchTo(
+ const ComputedStyle& style) {
+ DCHECK(!styles_are_equal_);
SVGResourcesCache& cache = ResourcesCache(layout_object_.GetDocument());
cache.RemoveResourcesFromLayoutObject(layout_object_);
cache.AddResourcesFromLayoutObject(layout_object_, style);
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 ad9bc3a5f11..eec4f65b065 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
@@ -71,13 +71,14 @@ class SVGResourcesCache {
TemporaryStyleScope(LayoutObject&,
const ComputedStyle& original_style,
const ComputedStyle& temporary_style);
- ~TemporaryStyleScope() { SwitchTo(original_style_); }
+ ~TemporaryStyleScope();
private:
void SwitchTo(const ComputedStyle&);
LayoutObject& layout_object_;
const ComputedStyle& original_style_;
+ const ComputedStyle& temporary_style_;
const bool styles_are_equal_;
DISALLOW_COPY_AND_ASSIGN(TemporaryStyleScope);
};
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 690a9d5a35d..83ad1b140c5 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
@@ -19,6 +19,7 @@
#include "third_party/blink/renderer/core/layout/svg/svg_text_layout_engine.h"
+#include "base/auto_reset.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_api_shim.h"
#include "third_party/blink/renderer/core/layout/api/line_layout_svg_text_path.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_inline_text.h"
@@ -30,7 +31,6 @@
#include "third_party/blink/renderer/core/svg/svg_element.h"
#include "third_party/blink/renderer/core/svg/svg_length_context.h"
#include "third_party/blink/renderer/core/svg/svg_text_content_element.h"
-#include "third_party/blink/renderer/platform/wtf/auto_reset.h"
namespace blink {
@@ -258,8 +258,8 @@ static bool DefinesTextLengthWithSpacing(const InlineFlowBox* start) {
void SVGTextLayoutEngine::LayoutCharactersInTextBoxes(InlineFlowBox* start) {
bool text_length_spacing_in_effect =
text_length_spacing_in_effect_ || DefinesTextLengthWithSpacing(start);
- AutoReset<bool> text_length_spacing_scope(&text_length_spacing_in_effect_,
- text_length_spacing_in_effect);
+ base::AutoReset<bool> text_length_spacing_scope(
+ &text_length_spacing_in_effect_, text_length_spacing_in_effect);
for (InlineBox* child = start->FirstChild(); child;
child = child->NextOnLine()) {
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 68a8028c392..6bf81b4f8ef 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
@@ -10,7 +10,6 @@
#include "third_party/blink/renderer/core/loader/empty_clients.h"
#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
-#include "third_party/blink/renderer/platform/platform_frame_view.h"
namespace blink {
class TextAutosizerClient : public EmptyChromeClient {
@@ -20,7 +19,7 @@ class TextAutosizerClient : public EmptyChromeClient {
return value * device_scale_factor_;
}
IntRect ViewportToScreen(const IntRect& rect,
- const PlatformFrameView* view) const override {
+ const LocalFrameView*) const override {
IntRect scaled_rect(rect);
scaled_rect.Scale(1 / device_scale_factor_);
return scaled_rect;
diff --git a/chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_perftest.cc b/chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_perftest.cc
new file mode 100644
index 00000000000..600bc28f23c
--- /dev/null
+++ b/chromium/third_party/blink/renderer/core/layout/visual_rect_mapping_perftest.cc
@@ -0,0 +1,173 @@
+// 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 "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
+#include "third_party/blink/renderer/core/layout/layout_view.h"
+#include "third_party/blink/renderer/core/paint/paint_layer.h"
+#include "third_party/blink/renderer/core/paint/paint_property_tree_printer.h"
+#include "third_party/blink/renderer/core/testing/core_unit_test_helper.h"
+#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
+#include "third_party/blink/renderer/platform/testing/paint_test_configurations.h"
+
+namespace blink {
+
+class VisualRectPerfTest : public RenderingTest {
+ public:
+ void RunPerfTest(unsigned iteration_count,
+ const LayoutBoxModelObject& target,
+ const LayoutBoxModelObject& ancestor,
+ const LayoutRect& rect);
+};
+
+void VisualRectPerfTest::RunPerfTest(unsigned iteration_count,
+ const LayoutBoxModelObject& object,
+ const LayoutBoxModelObject& ancestor,
+ const LayoutRect& rect) {
+ LayoutRect test_rect(rect);
+ base::TimeTicks start = base::TimeTicks::Now();
+ for (unsigned count = 0; count < iteration_count; count++) {
+ object.MapToVisualRectInAncestorSpace(&ancestor, test_rect);
+ }
+ LOG(ERROR) << " Time to run MapToVisualRectInAncestorSpace: "
+ << (base::TimeTicks::Now() - start).InMilliseconds() << "ms";
+
+ start = base::TimeTicks::Now();
+ size_t total_cache_bytes = 0;
+ for (unsigned count = 0; count < iteration_count; count++) {
+ object.MapToVisualRectInAncestorSpace(&ancestor, test_rect,
+ kUseGeometryMapper);
+ if (count == 0) {
+ total_cache_bytes = object.FirstFragment()
+ .LocalBorderBoxProperties()
+ .CacheMemoryUsageInBytes();
+ }
+ GeometryMapper::ClearCache();
+ }
+
+ LOG(ERROR)
+ << " Time to run MapToVisualRectInAncestorSpace w/GeometryMapper: "
+
+ << (base::TimeTicks::Now() - start).InMilliseconds() << "ms";
+ LOG(ERROR) << " GeometryMapper cache storage size: " << total_cache_bytes
+ << " bytes";
+}
+
+TEST_F(VisualRectPerfTest, GeometryMapper) {
+ SetBodyInnerHTML(R"HTML(
+ <style>
+ body {
+ margin:0;
+ }
+ .paintLayer {
+ position: relative;
+ }
+ .transform {
+ transform: translateX(1px);
+ }
+ .target {
+ position: relative;
+ width: 100px;
+ height: 100px;
+ }
+
+ </style>
+ <div id=singleDiv class=target></div>
+ <div>
+ <div>
+ <div>
+ <div>
+ <div>
+ <div>
+ <div>
+ <div>
+ <div>
+ <div>
+ <div id=nestedDiv class=target></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class=paintLayer>
+ <div class=paintLayer>
+ <div class=paintLayer>
+ <div class=paintLayer>
+ <div class=paintLayer>
+ <div class=paintLayer>
+ <div class=paintLayer>
+ <div class=paintLayer
+ <div class=paintLayer>
+ <div class=paintLayer>
+ <div id=nestedPaintLayers class=target></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div class=transform>
+ <div class=transform>
+ <div class=transform>
+ <div class=transform>
+ <div class=transform>
+ <div class=transform>
+ <div class=transform>
+ <div class=transform
+ <div class=transform>
+ <div class=transform>
+ <div id=nestedTransform class=target></div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ )HTML");
+ LayoutView* view = GetDocument().View()->GetLayoutView();
+ LayoutRect rect(0, 0, 100, 100);
+
+ unsigned kIterationCount = 1000000;
+ LOG(ERROR) << "Test with single div:";
+ RunPerfTest(kIterationCount,
+ *ToLayoutBox(
+ GetDocument().getElementById("singleDiv")->GetLayoutObject()),
+ *view, rect);
+
+ LOG(ERROR) << "Test with nested div:";
+ RunPerfTest(kIterationCount,
+ *ToLayoutBox(
+ GetDocument().getElementById("nestedDiv")->GetLayoutObject()),
+ *view, rect);
+
+ LOG(ERROR) << "Test with div nested under PaintLayers:";
+ RunPerfTest(
+ kIterationCount,
+ *ToLayoutBox(
+ GetDocument().getElementById("nestedPaintLayers")->GetLayoutObject()),
+ *view, rect);
+
+ LOG(ERROR) << "Test with div nested under transforms:";
+ RunPerfTest(
+ kIterationCount,
+ *ToLayoutBox(
+ GetDocument().getElementById("nestedTransform")->GetLayoutObject()),
+ *view, rect);
+}
+
+} // namespace blink
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 eb8578dc98e..f890185dda6 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
@@ -104,24 +104,26 @@ class VisualRectMappingTest : public PaintTestConfigurations,
// Checks the result of MapToVisualRectInAncestorSpace with and without
// geometry mapper.
- void CheckMapToVisualRectInAncestorSpace(
- LayoutRect rect,
- LayoutRect expected,
- const LayoutObject* object,
- const LayoutBoxModelObject* ancestor) {
+ void CheckMapToVisualRectInAncestorSpace(LayoutRect rect,
+ LayoutRect expected,
+ const LayoutObject* object,
+ const LayoutBoxModelObject* ancestor,
+ VisualRectFlags flags,
+ bool expected_retval) {
LayoutRect result(rect);
- EXPECT_TRUE(object->MapToVisualRectInAncestorSpace(ancestor, result));
+ EXPECT_EQ(expected_retval,
+ object->MapToVisualRectInAncestorSpace(ancestor, result, flags));
EXPECT_EQ(result, expected);
result = rect;
- EXPECT_TRUE(object->MapToVisualRectInAncestorSpace(ancestor, result,
- kUseGeometryMapper));
+ EXPECT_EQ(expected_retval,
+ object->MapToVisualRectInAncestorSpace(
+ ancestor, result,
+ static_cast<VisualRectFlags>(flags | kUseGeometryMapper)));
EXPECT_EQ(result, expected);
}
};
-INSTANTIATE_TEST_CASE_P(All,
- VisualRectMappingTest,
- testing::ValuesIn(kAllSlimmingPaintTestConfigurations));
+INSTANTIATE_PAINT_TEST_CASE_P(VisualRectMappingTest);
TEST_P(VisualRectMappingTest, LayoutText) {
SetBodyInnerHTML(R"HTML(
@@ -972,8 +974,9 @@ TEST_P(VisualRectMappingTest, FixedContentsInIframe) {
while (root_view->GetFrame()->OwnerLayoutObject())
root_view = root_view->GetFrame()->OwnerLayoutObject()->View();
- CheckMapToVisualRectInAncestorSpace(
- LayoutRect(0, 0, 400, 300), LayoutRect(0, 0, 400, 300), fixed, root_view);
+ CheckMapToVisualRectInAncestorSpace(LayoutRect(0, 0, 400, 300),
+ LayoutRect(0, 0, 400, 300), fixed,
+ root_view, kDefaultVisualRectFlags, true);
ChildDocument().View()->LayoutViewportScrollableArea()->SetScrollOffset(
ScrollOffset(0, 50), kProgrammaticScroll);
@@ -981,8 +984,9 @@ TEST_P(VisualRectMappingTest, FixedContentsInIframe) {
// The fixed element should not scroll so the mapped visual rect should not
// have changed.
- CheckMapToVisualRectInAncestorSpace(
- LayoutRect(0, 0, 400, 300), LayoutRect(0, 0, 400, 300), fixed, root_view);
+ CheckMapToVisualRectInAncestorSpace(LayoutRect(0, 0, 400, 300),
+ LayoutRect(0, 0, 400, 300), fixed,
+ root_view, kDefaultVisualRectFlags, true);
}
TEST_P(VisualRectMappingTest, FixedContentsWithScrollOffset) {
@@ -1000,18 +1004,83 @@ TEST_P(VisualRectMappingTest, FixedContentsWithScrollOffset) {
<div id='forcescroll' style='height:1000px;'></div>
)HTML");
- GetDocument().View()->UpdateAllLifecyclePhases();
auto* ancestor =
ToLayoutBox(GetDocument().getElementById("ancestor")->GetLayoutObject());
auto* fixed = GetDocument().getElementById("fixed")->GetLayoutObject();
CheckMapToVisualRectInAncestorSpace(LayoutRect(0, 0, 400, 300),
LayoutRect(0, -10, 400, 300), fixed,
- ancestor);
+ ancestor, kDefaultVisualRectFlags, true);
+
+ GetDocument().View()->LayoutViewportScrollableArea()->SetScrollOffset(
+ ScrollOffset(0, 50), kProgrammaticScroll);
+ GetDocument().View()->UpdateAllLifecyclePhases();
+
+ // The fixed element does not scroll but the ancestor does which changes the
+ // visual rect.
+ CheckMapToVisualRectInAncestorSpace(LayoutRect(0, 0, 400, 300),
+ LayoutRect(0, 40, 400, 300), fixed,
+ ancestor, kDefaultVisualRectFlags, true);
+}
+
+TEST_P(VisualRectMappingTest, FixedContentsUnderViewWithScrollOffset) {
+ GetDocument().GetFrame()->GetSettings()->SetPreferCompositingToLCDTextEnabled(
+ true);
+ SetBodyInnerHTML(R"HTML(
+ <style>body { margin:0; } ::-webkit-scrollbar { display:none; }</style>
+ <div id='fixed' style='
+ position:fixed; top:0; left:0; width:400px; height:300px;'>
+ </div>
+ <div id='forcescroll' style='height:1000px;'></div>
+ )HTML");
+
+ auto* fixed = GetDocument().getElementById("fixed")->GetLayoutObject();
+
+ CheckMapToVisualRectInAncestorSpace(
+ LayoutRect(0, 0, 400, 300), LayoutRect(0, 0, 400, 300), fixed,
+ fixed->View(), kDefaultVisualRectFlags, true);
GetDocument().View()->LayoutViewportScrollableArea()->SetScrollOffset(
ScrollOffset(0, 50), kProgrammaticScroll);
GetDocument().View()->UpdateAllLifecyclePhases();
+
+ // Results of mapping to ancestor are in absolute coordinates of the
+ // ancestor. Therefore a fixed-position element is (reverse) offset by scroll.
+ CheckMapToVisualRectInAncestorSpace(
+ LayoutRect(0, 0, 400, 300), LayoutRect(0, 50, 400, 300), fixed,
+ fixed->View(), kDefaultVisualRectFlags, true);
+}
+
+TEST_P(VisualRectMappingTest, InclusiveIntersect) {
+ GetDocument().SetBaseURLOverride(KURL("http://test.com"));
+ SetBodyInnerHTML(R"HTML(
+ <style>body { margin:0; }</style>
+ <div id='ancestor' style='position: relative'>
+ <div style='width: 50px; height: 50px; overflow: hidden'>
+ <div id='child' style='width: 10px; height: 10px; position: relative; left: 50px'></div>
+ </div>
+ </div>
+ )HTML");
+
+ auto* ancestor =
+ ToLayoutBox(GetDocument().getElementById("ancestor")->GetLayoutObject());
+ auto* child =
+ ToLayoutBox(GetDocument().getElementById("child")->GetLayoutObject());
+
+ CheckMapToVisualRectInAncestorSpace(LayoutRect(0, 0, 10, 10),
+ LayoutRect(50, 0, 0, 10), child, ancestor,
+ kEdgeInclusive, true);
+
+ CheckMapToVisualRectInAncestorSpace(LayoutRect(1, 1, 10, 10), LayoutRect(),
+ child, ancestor, kEdgeInclusive, false);
+
+ CheckMapToVisualRectInAncestorSpace(LayoutRect(1, 1, 10, 10),
+ LayoutRect(1, 1, 10, 10), child, child,
+ kEdgeInclusive, true);
+
+ CheckMapToVisualRectInAncestorSpace(LayoutRect(0, 0, 10, 10), LayoutRect(),
+ child, ancestor, kDefaultVisualRectFlags,
+ false);
}
} // namespace blink