1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * (C) 2006 Alexey Proskuryakov (ap@webkit.org)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2011, 2012 Apple Inc. All
7 * rights reserved.
8 * Copyright (C) 2008, 2009 Torch Mobile Inc. All rights reserved.
9 * (http://www.torchmobile.com/)
10 * Copyright (C) 2008, 2009, 2011, 2012 Google Inc. All rights reserved.
11 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
12 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved.
13 *
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Library General Public
16 * License as published by the Free Software Foundation; either
17 * version 2 of the License, or (at your option) any later version.
18 *
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public License
25 * along with this library; see the file COPYING.LIB. If not, write to
26 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 * Boston, MA 02110-1301, USA.
28 */
29
30 #include "third_party/blink/renderer/core/dom/document.h"
31
32 #include <memory>
33 #include <utility>
34
35 #include "base/auto_reset.h"
36 #include "base/macros.h"
37 #include "base/optional.h"
38 #include "base/time/time.h"
39 #include "cc/input/overscroll_behavior.h"
40 #include "cc/input/scroll_snap_data.h"
41 #include "components/performance_manager/public/mojom/coordination_unit.mojom-blink.h"
42 #include "mojo/public/cpp/bindings/pending_remote.h"
43 #include "mojo/public/cpp/bindings/remote.h"
44 #include "mojo/public/mojom/base/text_direction.mojom-blink.h"
45 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
46 #include "services/metrics/public/cpp/mojo_ukm_recorder.h"
47 #include "services/metrics/public/cpp/ukm_builders.h"
48 #include "services/metrics/public/cpp/ukm_source_id.h"
49 #include "services/metrics/public/mojom/ukm_interface.mojom-blink.h"
50 #include "services/network/public/mojom/ip_address_space.mojom-blink.h"
51 #include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
52 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
53 #include "third_party/blink/public/common/feature_policy/document_policy_features.h"
54 #include "third_party/blink/public/common/features.h"
55 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
56 #include "third_party/blink/public/mojom/feature_policy/policy_disposition.mojom-blink.h"
57 #include "third_party/blink/public/mojom/input/focus_type.mojom-blink.h"
58 #include "third_party/blink/public/mojom/insecure_input/insecure_input_service.mojom-blink.h"
59 #include "third_party/blink/public/mojom/ukm/ukm.mojom-blink.h"
60 #include "third_party/blink/public/platform/platform.h"
61 #include "third_party/blink/public/platform/task_type.h"
62 #include "third_party/blink/public/platform/web_content_settings_client.h"
63 #include "third_party/blink/public/platform/web_theme_engine.h"
64 #include "third_party/blink/renderer/bindings/core/v8/html_script_element_or_svg_script_element.h"
65 #include "third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h"
66 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
67 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
68 #include "third_party/blink/renderer/bindings/core/v8/script_value.h"
69 #include "third_party/blink/renderer/bindings/core/v8/source_location.h"
70 #include "third_party/blink/renderer/bindings/core/v8/string_or_element_creation_options.h"
71 #include "third_party/blink/renderer/bindings/core/v8/v0_custom_element_constructor_builder.h"
72 #include "third_party/blink/renderer/bindings/core/v8/v8_element_creation_options.h"
73 #include "third_party/blink/renderer/bindings/core/v8/v8_element_registration_options.h"
74 #include "third_party/blink/renderer/bindings/core/v8/window_proxy.h"
75 #include "third_party/blink/renderer/core/accessibility/ax_context.h"
76 #include "third_party/blink/renderer/core/accessibility/ax_object_cache.h"
77 #include "third_party/blink/renderer/core/animation/document_animations.h"
78 #include "third_party/blink/renderer/core/animation/document_timeline.h"
79 #include "third_party/blink/renderer/core/animation/pending_animations.h"
80 #include "third_party/blink/renderer/core/animation/worklet_animation_controller.h"
81 #include "third_party/blink/renderer/core/aom/computed_accessible_node.h"
82 #include "third_party/blink/renderer/core/css/css_font_selector.h"
83 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
84 #include "third_party/blink/renderer/core/css/css_style_declaration.h"
85 #include "third_party/blink/renderer/core/css/css_style_sheet.h"
86 #include "third_party/blink/renderer/core/css/cssom/computed_style_property_map.h"
87 #include "third_party/blink/renderer/core/css/font_face_set_document.h"
88 #include "third_party/blink/renderer/core/css/invalidation/style_invalidator.h"
89 #include "third_party/blink/renderer/core/css/media_query_matcher.h"
90 #include "third_party/blink/renderer/core/css/parser/css_parser.h"
91 #include "third_party/blink/renderer/core/css/properties/css_property.h"
92 #include "third_party/blink/renderer/core/css/property_registry.h"
93 #include "third_party/blink/renderer/core/css/resolver/font_builder.h"
94 #include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
95 #include "third_party/blink/renderer/core/css/resolver/style_resolver_stats.h"
96 #include "third_party/blink/renderer/core/css/selector_query.h"
97 #include "third_party/blink/renderer/core/css/style_change_reason.h"
98 #include "third_party/blink/renderer/core/css/style_engine.h"
99 #include "third_party/blink/renderer/core/css/style_sheet_contents.h"
100 #include "third_party/blink/renderer/core/css/style_sheet_list.h"
101 #include "third_party/blink/renderer/core/display_lock/display_lock_context.h"
102 #include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
103 #include "third_party/blink/renderer/core/dom/attr.h"
104 #include "third_party/blink/renderer/core/dom/beforeunload_event_listener.h"
105 #include "third_party/blink/renderer/core/dom/cdata_section.h"
106 #include "third_party/blink/renderer/core/dom/comment.h"
107 #include "third_party/blink/renderer/core/dom/context_features.h"
108 #include "third_party/blink/renderer/core/dom/document_fragment.h"
109 #include "third_party/blink/renderer/core/dom/document_init.h"
110 #include "third_party/blink/renderer/core/dom/document_parser_timing.h"
111 #include "third_party/blink/renderer/core/dom/document_type.h"
112 #include "third_party/blink/renderer/core/dom/dom_implementation.h"
113 #include "third_party/blink/renderer/core/dom/element.h"
114 #include "third_party/blink/renderer/core/dom/element_data_cache.h"
115 #include "third_party/blink/renderer/core/dom/element_traversal.h"
116 #include "third_party/blink/renderer/core/dom/events/event.h"
117 #include "third_party/blink/renderer/core/dom/events/event_dispatch_forbidden_scope.h"
118 #include "third_party/blink/renderer/core/dom/events/event_listener.h"
119 #include "third_party/blink/renderer/core/dom/events/native_event_listener.h"
120 #include "third_party/blink/renderer/core/dom/events/scoped_event_queue.h"
121 #include "third_party/blink/renderer/core/dom/flat_tree_traversal.h"
122 #include "third_party/blink/renderer/core/dom/layout_tree_builder_traversal.h"
123 #include "third_party/blink/renderer/core/dom/live_node_list.h"
124 #include "third_party/blink/renderer/core/dom/mutation_observer.h"
125 #include "third_party/blink/renderer/core/dom/node_child_removal_tracker.h"
126 #include "third_party/blink/renderer/core/dom/node_computed_style.h"
127 #include "third_party/blink/renderer/core/dom/node_iterator.h"
128 #include "third_party/blink/renderer/core/dom/node_lists_node_data.h"
129 #include "third_party/blink/renderer/core/dom/node_rare_data.h"
130 #include "third_party/blink/renderer/core/dom/node_traversal.h"
131 #include "third_party/blink/renderer/core/dom/node_with_index.h"
132 #include "third_party/blink/renderer/core/dom/processing_instruction.h"
133 #include "third_party/blink/renderer/core/dom/scripted_animation_controller.h"
134 #include "third_party/blink/renderer/core/dom/shadow_root.h"
135 #include "third_party/blink/renderer/core/dom/slot_assignment.h"
136 #include "third_party/blink/renderer/core/dom/slot_assignment_engine.h"
137 #include "third_party/blink/renderer/core/dom/slot_assignment_recalc_forbidden_scope.h"
138 #include "third_party/blink/renderer/core/dom/static_node_list.h"
139 #include "third_party/blink/renderer/core/dom/transform_source.h"
140 #include "third_party/blink/renderer/core/dom/tree_walker.h"
141 #include "third_party/blink/renderer/core/dom/visited_link_state.h"
142 #include "third_party/blink/renderer/core/dom/whitespace_attacher.h"
143 #include "third_party/blink/renderer/core/dom/xml_document.h"
144 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
145 #include "third_party/blink/renderer/core/editing/frame_selection.h"
146 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
147 #include "third_party/blink/renderer/core/editing/serializers/serialization.h"
148 #include "third_party/blink/renderer/core/events/before_unload_event.h"
149 #include "third_party/blink/renderer/core/events/event_factory.h"
150 #include "third_party/blink/renderer/core/events/hash_change_event.h"
151 #include "third_party/blink/renderer/core/events/overscroll_event.h"
152 #include "third_party/blink/renderer/core/events/page_transition_event.h"
153 #include "third_party/blink/renderer/core/events/visual_viewport_resize_event.h"
154 #include "third_party/blink/renderer/core/events/visual_viewport_scroll_event.h"
155 #include "third_party/blink/renderer/core/execution_context/agent_metrics_collector.h"
156 #include "third_party/blink/renderer/core/execution_context/security_context_init.h"
157 #include "third_party/blink/renderer/core/execution_context/window_agent.h"
158 #include "third_party/blink/renderer/core/execution_context/window_agent_factory.h"
159 #include "third_party/blink/renderer/core/feature_policy/dom_document_policy.h"
160 #include "third_party/blink/renderer/core/feature_policy/feature_policy_parser.h"
161 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
162 #include "third_party/blink/renderer/core/frame/csp/navigation_initiator_impl.h"
163 #include "third_party/blink/renderer/core/frame/document_policy_violation_report_body.h"
164 #include "third_party/blink/renderer/core/frame/dom_timer.h"
165 #include "third_party/blink/renderer/core/frame/dom_visual_viewport.h"
166 #include "third_party/blink/renderer/core/frame/event_handler_registry.h"
167 #include "third_party/blink/renderer/core/frame/feature_policy_violation_report_body.h"
168 #include "third_party/blink/renderer/core/frame/frame_console.h"
169 #include "third_party/blink/renderer/core/frame/history.h"
170 #include "third_party/blink/renderer/core/frame/intervention.h"
171 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
172 #include "third_party/blink/renderer/core/frame/local_frame.h"
173 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
174 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
175 #include "third_party/blink/renderer/core/frame/performance_monitor.h"
176 #include "third_party/blink/renderer/core/frame/report.h"
177 #include "third_party/blink/renderer/core/frame/reporting_context.h"
178 #include "third_party/blink/renderer/core/frame/settings.h"
179 #include "third_party/blink/renderer/core/frame/viewport_data.h"
180 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
181 #include "third_party/blink/renderer/core/html/anchor_element_metrics.h"
182 #include "third_party/blink/renderer/core/html/canvas/canvas_font_cache.h"
183 #include "third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h"
184 #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
185 #include "third_party/blink/renderer/core/html/custom/custom_element.h"
186 #include "third_party/blink/renderer/core/html/custom/custom_element_definition.h"
187 #include "third_party/blink/renderer/core/html/custom/custom_element_descriptor.h"
188 #include "third_party/blink/renderer/core/html/custom/custom_element_registry.h"
189 #include "third_party/blink/renderer/core/html/custom/v0_custom_element_microtask_run_queue.h"
190 #include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
191 #include "third_party/blink/renderer/core/html/document_all_name_collection.h"
192 #include "third_party/blink/renderer/core/html/document_name_collection.h"
193 #include "third_party/blink/renderer/core/html/forms/form_controller.h"
194 #include "third_party/blink/renderer/core/html/forms/html_form_element.h"
195 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
196 #include "third_party/blink/renderer/core/html/html_all_collection.h"
197 #include "third_party/blink/renderer/core/html/html_anchor_element.h"
198 #include "third_party/blink/renderer/core/html/html_base_element.h"
199 #include "third_party/blink/renderer/core/html/html_body_element.h"
200 #include "third_party/blink/renderer/core/html/html_collection.h"
201 #include "third_party/blink/renderer/core/html/html_dialog_element.h"
202 #include "third_party/blink/renderer/core/html/html_document.h"
203 #include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
204 #include "third_party/blink/renderer/core/html/html_head_element.h"
205 #include "third_party/blink/renderer/core/html/html_html_element.h"
206 #include "third_party/blink/renderer/core/html/html_link_element.h"
207 #include "third_party/blink/renderer/core/html/html_meta_element.h"
208 #include "third_party/blink/renderer/core/html/html_object_element.h"
209 #include "third_party/blink/renderer/core/html/html_plugin_element.h"
210 #include "third_party/blink/renderer/core/html/html_script_element.h"
211 #include "third_party/blink/renderer/core/html/html_title_element.h"
212 #include "third_party/blink/renderer/core/html/html_unknown_element.h"
213 #include "third_party/blink/renderer/core/html/imports/html_import_loader.h"
214 #include "third_party/blink/renderer/core/html/imports/html_imports_controller.h"
215 #include "third_party/blink/renderer/core/html/lazy_load_image_observer.h"
216 #include "third_party/blink/renderer/core/html/parser/html_document_parser.h"
217 #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
218 #include "third_party/blink/renderer/core/html/parser/nesting_level_incrementer.h"
219 #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
220 #include "third_party/blink/renderer/core/html/plugin_document.h"
221 #include "third_party/blink/renderer/core/html/portal/document_portals.h"
222 #include "third_party/blink/renderer/core/html/portal/portal_contents.h"
223 #include "third_party/blink/renderer/core/html/window_name_collection.h"
224 #include "third_party/blink/renderer/core/html_element_factory.h"
225 #include "third_party/blink/renderer/core/html_element_type_helpers.h"
226 #include "third_party/blink/renderer/core/html_names.h"
227 #include "third_party/blink/renderer/core/input/event_handler.h"
228 #include "third_party/blink/renderer/core/input/touch_list.h"
229 #include "third_party/blink/renderer/core/inspector/console_message.h"
230 #include "third_party/blink/renderer/core/inspector/inspector_issue.h"
231 #include "third_party/blink/renderer/core/inspector/inspector_issue_storage.h"
232 #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
233 #include "third_party/blink/renderer/core/intersection_observer/element_intersection_observer_data.h"
234 #include "third_party/blink/renderer/core/intersection_observer/intersection_observer_controller.h"
235 #include "third_party/blink/renderer/core/intersection_observer/intersection_observer_entry.h"
236 #include "third_party/blink/renderer/core/layout/adjust_for_absolute_zoom.h"
237 #include "third_party/blink/renderer/core/layout/hit_test_canvas_result.h"
238 #include "third_party/blink/renderer/core/layout/hit_test_result.h"
239 #include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
240 #include "third_party/blink/renderer/core/layout/layout_view.h"
241 #include "third_party/blink/renderer/core/layout/text_autosizer.h"
242 #include "third_party/blink/renderer/core/loader/appcache/application_cache_host_for_frame.h"
243 #include "third_party/blink/renderer/core/loader/cookie_jar.h"
244 #include "third_party/blink/renderer/core/loader/document_loader.h"
245 #include "third_party/blink/renderer/core/loader/frame_fetch_context.h"
246 #include "third_party/blink/renderer/core/loader/frame_loader.h"
247 #include "third_party/blink/renderer/core/loader/http_refresh_scheduler.h"
248 #include "third_party/blink/renderer/core/loader/idleness_detector.h"
249 #include "third_party/blink/renderer/core/loader/interactive_detector.h"
250 #include "third_party/blink/renderer/core/loader/prerenderer_client.h"
251 #include "third_party/blink/renderer/core/loader/progress_tracker.h"
252 #include "third_party/blink/renderer/core/loader/text_resource_decoder_builder.h"
253 #include "third_party/blink/renderer/core/mathml/mathml_element.h"
254 #include "third_party/blink/renderer/core/mathml/mathml_row_element.h"
255 #include "third_party/blink/renderer/core/mathml_element_factory.h"
256 #include "third_party/blink/renderer/core/mathml_names.h"
257 #include "third_party/blink/renderer/core/origin_trials/origin_trial_context.h"
258 #include "third_party/blink/renderer/core/page/chrome_client.h"
259 #include "third_party/blink/renderer/core/page/event_with_hit_test_results.h"
260 #include "third_party/blink/renderer/core/page/focus_controller.h"
261 #include "third_party/blink/renderer/core/page/frame_tree.h"
262 #include "third_party/blink/renderer/core/page/page.h"
263 #include "third_party/blink/renderer/core/page/plugin_script_forbidden_scope.h"
264 #include "third_party/blink/renderer/core/page/pointer_lock_controller.h"
265 #include "third_party/blink/renderer/core/page/scrolling/overscroll_controller.h"
266 #include "third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h"
267 #include "third_party/blink/renderer/core/page/scrolling/scroll_state_callback.h"
268 #include "third_party/blink/renderer/core/page/scrolling/scrolling_coordinator.h"
269 #include "third_party/blink/renderer/core/page/scrolling/snap_coordinator.h"
270 #include "third_party/blink/renderer/core/page/scrolling/text_fragment_anchor.h"
271 #include "third_party/blink/renderer/core/page/scrolling/top_document_root_scroller_controller.h"
272 #include "third_party/blink/renderer/core/page/spatial_navigation_controller.h"
273 #include "third_party/blink/renderer/core/page/validation_message_client.h"
274 #include "third_party/blink/renderer/core/paint/compositing/paint_layer_compositor.h"
275 #include "third_party/blink/renderer/core/paint/first_meaningful_paint_detector.h"
276 #include "third_party/blink/renderer/core/paint/paint_layer.h"
277 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
278 #include "third_party/blink/renderer/core/probe/core_probes.h"
279 #include "third_party/blink/renderer/core/resize_observer/resize_observer_controller.h"
280 #include "third_party/blink/renderer/core/script/script_runner.h"
281 #include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
282 #include "third_party/blink/renderer/core/svg/svg_document_extensions.h"
283 #include "third_party/blink/renderer/core/svg/svg_script_element.h"
284 #include "third_party/blink/renderer/core/svg/svg_title_element.h"
285 #include "third_party/blink/renderer/core/svg/svg_unknown_element.h"
286 #include "third_party/blink/renderer/core/svg/svg_use_element.h"
287 #include "third_party/blink/renderer/core/svg_element_factory.h"
288 #include "third_party/blink/renderer/core/svg_names.h"
289 #include "third_party/blink/renderer/core/trustedtypes/trusted_html.h"
290 #include "third_party/blink/renderer/core/xml/parser/xml_document_parser.h"
291 #include "third_party/blink/renderer/core/xml_names.h"
292 #include "third_party/blink/renderer/core/xmlhttprequest/main_thread_disallow_synchronous_xhr_scope.h"
293 #include "third_party/blink/renderer/core/xmlns_names.h"
294 #include "third_party/blink/renderer/platform/bindings/dom_data_store.h"
295 #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
296 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
297 #include "third_party/blink/renderer/platform/bindings/microtask.h"
298 #include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
299 #include "third_party/blink/renderer/platform/bindings/v8_dom_wrapper.h"
300 #include "third_party/blink/renderer/platform/bindings/v8_per_isolate_data.h"
301 #include "third_party/blink/renderer/platform/fonts/font_matching_metrics.h"
302 #include "third_party/blink/renderer/platform/geometry/length_functions.h"
303 #include "third_party/blink/renderer/platform/heap/heap.h"
304 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
305 #include "third_party/blink/renderer/platform/instrumentation/instance_counters.h"
306 #include "third_party/blink/renderer/platform/instrumentation/resource_coordinator/document_resource_coordinator.h"
307 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
308 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
309 #include "third_party/blink/renderer/platform/language.h"
310 #include "third_party/blink/renderer/platform/loader/fetch/null_resource_fetcher_properties.h"
311 #include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
312 #include "third_party/blink/renderer/platform/network/content_security_policy_parsers.h"
313 #include "third_party/blink/renderer/platform/network/http_parsers.h"
314 #include "third_party/blink/renderer/platform/network/network_state_notifier.h"
315 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
316 #include "third_party/blink/renderer/platform/scheduler/public/event_loop.h"
317 #include "third_party/blink/renderer/platform/scheduler/public/frame_or_worker_scheduler.h"
318 #include "third_party/blink/renderer/platform/scheduler/public/post_cross_thread_task.h"
319 #include "third_party/blink/renderer/platform/scheduler/public/thread_scheduler.h"
320 #include "third_party/blink/renderer/platform/text/platform_locale.h"
321 #include "third_party/blink/renderer/platform/web_test_support.h"
322 #include "third_party/blink/renderer/platform/weborigin/origin_access_entry.h"
323 #include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
324 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
325 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
326 #include "third_party/blink/renderer/platform/wtf/functional.h"
327 #include "third_party/blink/renderer/platform/wtf/hash_functions.h"
328 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
329 #include "third_party/blink/renderer/platform/wtf/text/character_names.h"
330 #include "third_party/blink/renderer/platform/wtf/text/string_buffer.h"
331 #include "third_party/blink/renderer/platform/wtf/text/text_encoding_registry.h"
332
333 #ifndef NDEBUG
334 using WeakDocumentSet = blink::HeapHashSet<blink::WeakMember<blink::Document>>;
335 static WeakDocumentSet& liveDocumentSet();
336 #endif
337
338 namespace blink {
339
340 namespace {
341
342 // Returns true if any of <object> ancestors don't start loading or are loading
343 // plugins/frames/images. If there are no <object> ancestors, this function
344 // returns false.
IsInIndeterminateObjectAncestor(const Element * element)345 bool IsInIndeterminateObjectAncestor(const Element* element) {
346 if (!element->isConnected())
347 return false;
348 for (; element; element = element->ParentOrShadowHostElement()) {
349 if (const auto* object = DynamicTo<HTMLObjectElement>(element)) {
350 if (!object->DidFinishLoading())
351 return true;
352 }
353 }
354 return false;
355 }
356
357 } // namespace
358
359 class DocumentOutliveTimeReporter : public BlinkGCObserver {
360 public:
DocumentOutliveTimeReporter(Document * document)361 explicit DocumentOutliveTimeReporter(Document* document)
362 : BlinkGCObserver(ThreadState::Current()), document_(document) {}
363
~DocumentOutliveTimeReporter()364 ~DocumentOutliveTimeReporter() override {
365 // As not all documents are destroyed before the process dies, this might
366 // miss some long-lived documents or leaked documents.
367 UMA_HISTOGRAM_EXACT_LINEAR(
368 "Document.OutliveTimeAfterShutdown.DestroyedBeforeProcessDies",
369 GetOutliveTimeCount() + 1, 101);
370 }
371
OnCompleteSweepDone()372 void OnCompleteSweepDone() override {
373 enum GCCount {
374 kGCCount5,
375 kGCCount10,
376 kGCCountMax,
377 };
378
379 // There are some cases that a document can live after shutting down because
380 // the document can still be referenced (e.g. a document opened via
381 // window.open can be referenced by the opener even after shutting down). To
382 // avoid such cases as much as possible, outlive time count is started after
383 // all DomWrapper of the document have disappeared.
384 if (!gc_age_when_document_detached_) {
385 if (document_->domWindow() &&
386 DOMWrapperWorld::HasWrapperInAnyWorldInMainThread(
387 document_->domWindow())) {
388 return;
389 }
390 gc_age_when_document_detached_ = ThreadState::Current()->GcAge();
391 }
392
393 int outlive_time_count = GetOutliveTimeCount();
394 if (outlive_time_count == 5 || outlive_time_count == 10) {
395 const char* kUMAString = "Document.OutliveTimeAfterShutdown.GCCount";
396
397 if (outlive_time_count == 5)
398 UMA_HISTOGRAM_ENUMERATION(kUMAString, kGCCount5, kGCCountMax);
399 else if (outlive_time_count == 10)
400 UMA_HISTOGRAM_ENUMERATION(kUMAString, kGCCount10, kGCCountMax);
401 else
402 NOTREACHED();
403 }
404
405 if (outlive_time_count == 5 || outlive_time_count == 10 ||
406 outlive_time_count == 20 || outlive_time_count == 50) {
407 document_->RecordUkmOutliveTimeAfterShutdown(outlive_time_count);
408 }
409 }
410
411 private:
GetOutliveTimeCount() const412 int GetOutliveTimeCount() const {
413 if (!gc_age_when_document_detached_)
414 return 0;
415 return ThreadState::Current()->GcAge() - gc_age_when_document_detached_;
416 }
417
418 WeakPersistent<Document> document_;
419 int gc_age_when_document_detached_ = 0;
420 };
421
422 static const unsigned kCMaxWriteRecursionDepth = 21;
423
424 // This amount of time must have elapsed before we will even consider scheduling
425 // a layout without a delay.
426 // FIXME: For faster machines this value can really be lowered to 200. 250 is
427 // adequate, but a little high for dual G5s. :)
428 static const base::TimeDelta kCLayoutScheduleThreshold =
429 base::TimeDelta::FromMilliseconds(250);
430
431 // DOM Level 2 says (letters added):
432 //
433 // a) Name start characters must have one of the categories Ll, Lu, Lo, Lt, Nl.
434 // b) Name characters other than Name-start characters must have one of the
435 // categories Mc, Me, Mn, Lm, or Nd.
436 // c) Characters in the compatibility area (i.e. with character code greater
437 // than #xF900 and less than #xFFFE) are not allowed in XML names.
438 // d) Characters which have a font or compatibility decomposition (i.e. those
439 // with a "compatibility formatting tag" in field 5 of the database -- marked
440 // by field 5 beginning with a "<") are not allowed.
441 // e) The following characters are treated as name-start characters rather than
442 // name characters, because the property file classifies them as Alphabetic:
443 // [#x02BB-#x02C1], #x0559, #x06E5, #x06E6.
444 // f) Characters #x20DD-#x20E0 are excluded (in accordance with Unicode, section
445 // 5.14).
446 // g) Character #x00B7 is classified as an extender, because the property list
447 // so identifies it.
448 // h) Character #x0387 is added as a name character, because #x00B7 is its
449 // canonical equivalent.
450 // i) Characters ':' and '_' are allowed as name-start characters.
451 // j) Characters '-' and '.' are allowed as name characters.
452 //
453 // It also contains complete tables. If we decide it's better, we could include
454 // those instead of the following code.
455
IsValidNameStart(UChar32 c)456 static inline bool IsValidNameStart(UChar32 c) {
457 // rule (e) above
458 if ((c >= 0x02BB && c <= 0x02C1) || c == 0x559 || c == 0x6E5 || c == 0x6E6)
459 return true;
460
461 // rule (i) above
462 if (c == ':' || c == '_')
463 return true;
464
465 // rules (a) and (f) above
466 const uint32_t kNameStartMask =
467 WTF::unicode::kLetter_Lowercase | WTF::unicode::kLetter_Uppercase |
468 WTF::unicode::kLetter_Other | WTF::unicode::kLetter_Titlecase |
469 WTF::unicode::kNumber_Letter;
470 if (!(WTF::unicode::Category(c) & kNameStartMask))
471 return false;
472
473 // rule (c) above
474 if (c >= 0xF900 && c < 0xFFFE)
475 return false;
476
477 // rule (d) above
478 WTF::unicode::CharDecompositionType decomp_type =
479 WTF::unicode::DecompositionType(c);
480 if (decomp_type == WTF::unicode::kDecompositionFont ||
481 decomp_type == WTF::unicode::kDecompositionCompat)
482 return false;
483
484 return true;
485 }
486
IsValidNamePart(UChar32 c)487 static inline bool IsValidNamePart(UChar32 c) {
488 // rules (a), (e), and (i) above
489 if (IsValidNameStart(c))
490 return true;
491
492 // rules (g) and (h) above
493 if (c == 0x00B7 || c == 0x0387)
494 return true;
495
496 // rule (j) above
497 if (c == '-' || c == '.')
498 return true;
499
500 // rules (b) and (f) above
501 const uint32_t kOtherNamePartMask =
502 WTF::unicode::kMark_NonSpacing | WTF::unicode::kMark_Enclosing |
503 WTF::unicode::kMark_SpacingCombining | WTF::unicode::kLetter_Modifier |
504 WTF::unicode::kNumber_DecimalDigit;
505 if (!(WTF::unicode::Category(c) & kOtherNamePartMask))
506 return false;
507
508 // rule (c) above
509 if (c >= 0xF900 && c < 0xFFFE)
510 return false;
511
512 // rule (d) above
513 WTF::unicode::CharDecompositionType decomp_type =
514 WTF::unicode::DecompositionType(c);
515 if (decomp_type == WTF::unicode::kDecompositionFont ||
516 decomp_type == WTF::unicode::kDecompositionCompat)
517 return false;
518
519 return true;
520 }
521
522 // Tests whether |name| is something the HTML parser would accept as a
523 // tag name.
524 template <typename CharType>
IsValidElementNamePerHTMLParser(const CharType * characters,unsigned length)525 static inline bool IsValidElementNamePerHTMLParser(const CharType* characters,
526 unsigned length) {
527 CharType c = characters[0] | 0x20;
528 if (!('a' <= c && c <= 'z'))
529 return false;
530
531 for (unsigned i = 1; i < length; ++i) {
532 c = characters[i];
533 if (c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == ' ' ||
534 c == '/' || c == '>')
535 return false;
536 }
537
538 return true;
539 }
540
IsValidElementNamePerHTMLParser(const String & name)541 static bool IsValidElementNamePerHTMLParser(const String& name) {
542 unsigned length = name.length();
543 if (!length)
544 return false;
545
546 if (name.Is8Bit()) {
547 const LChar* characters = name.Characters8();
548 return IsValidElementNamePerHTMLParser(characters, length);
549 }
550 const UChar* characters = name.Characters16();
551 return IsValidElementNamePerHTMLParser(characters, length);
552 }
553
554 // Tests whether |name| is a valid name per DOM spec. Also checks
555 // whether the HTML parser would accept this element name and counts
556 // cases of mismatches.
IsValidElementName(Document * document,const String & name)557 static bool IsValidElementName(Document* document, const String& name) {
558 bool is_valid_dom_name = Document::IsValidName(name);
559 bool is_valid_html_name = IsValidElementNamePerHTMLParser(name);
560 if (UNLIKELY(is_valid_html_name != is_valid_dom_name)) {
561 // This is inaccurate because it will not report activity in
562 // detached documents. However retrieving the frame from the
563 // bindings is too slow.
564 UseCounter::Count(document,
565 is_valid_dom_name
566 ? WebFeature::kElementNameDOMValidHTMLParserInvalid
567 : WebFeature::kElementNameDOMInvalidHTMLParserValid);
568 }
569 return is_valid_dom_name;
570 }
571
AcceptsEditingFocus(const Element & element)572 static bool AcceptsEditingFocus(const Element& element) {
573 DCHECK(HasEditableStyle(element));
574
575 return element.GetDocument().GetFrame() && RootEditableElement(element);
576 }
577
578 uint64_t Document::global_tree_version_ = 0;
579
580 static bool g_threaded_parsing_enabled_for_testing = true;
581
582 class Document::NetworkStateObserver final
583 : public GarbageCollected<Document::NetworkStateObserver>,
584 public NetworkStateNotifier::NetworkStateObserver,
585 public ExecutionContextLifecycleObserver {
586 USING_GARBAGE_COLLECTED_MIXIN(Document::NetworkStateObserver);
587
588 public:
NetworkStateObserver(ExecutionContext * context)589 explicit NetworkStateObserver(ExecutionContext* context)
590 : ExecutionContextLifecycleObserver(context) {
591 online_observer_handle_ = GetNetworkStateNotifier().AddOnLineObserver(
592 this, GetExecutionContext()->GetTaskRunner(TaskType::kNetworking));
593 }
594
OnLineStateChange(bool on_line)595 void OnLineStateChange(bool on_line) override {
596 AtomicString event_name =
597 on_line ? event_type_names::kOnline : event_type_names::kOffline;
598 auto* window = To<LocalDOMWindow>(GetExecutionContext());
599 window->DispatchEvent(*Event::Create(event_name));
600 probe::NetworkStateChanged(window->GetFrame(), on_line);
601 }
602
ContextDestroyed()603 void ContextDestroyed() override {
604 UnregisterAsObserver(GetExecutionContext());
605 }
606
UnregisterAsObserver(ExecutionContext * context)607 void UnregisterAsObserver(ExecutionContext* context) {
608 DCHECK(context);
609 online_observer_handle_ = nullptr;
610 }
611
Trace(Visitor * visitor)612 void Trace(Visitor* visitor) override {
613 ExecutionContextLifecycleObserver::Trace(visitor);
614 }
615
616 private:
617 std::unique_ptr<NetworkStateNotifier::NetworkStateObserverHandle>
618 online_observer_handle_;
619 };
620
GetExplicitlySetAttrElementsMap(Element * element)621 ExplicitlySetAttrElementsMap* Document::GetExplicitlySetAttrElementsMap(
622 Element* element) {
623 DCHECK(element);
624 DCHECK(element->GetDocument() == this);
625 auto add_result =
626 element_explicitly_set_attr_elements_map_.insert(element, nullptr);
627 if (add_result.is_new_entry) {
628 add_result.stored_value->value =
629 MakeGarbageCollected<ExplicitlySetAttrElementsMap>();
630 }
631 return add_result.stored_value->value;
632 }
633
Create(Document & document)634 Document* Document::Create(Document& document) {
635 Document* new_document =
636 MakeGarbageCollected<Document>(DocumentInit::Create()
637 .WithContextDocument(&document)
638 .WithURL(BlankURL())
639 .WithOwnerDocument(&document));
640 new_document->SetContextFeatures(document.GetContextFeatures());
641 return new_document;
642 }
643
Document()644 Document::Document() : Document(DocumentInit::Create()) {}
645
Document(const DocumentInit & initializer,DocumentClassFlags document_classes)646 Document::Document(const DocumentInit& initializer,
647 DocumentClassFlags document_classes)
648 : Document(initializer,
649 SecurityContextInit(initializer),
650 document_classes) {}
651
Document(const DocumentInit & initializer,const SecurityContextInit & security_initializer,DocumentClassFlags document_classes)652 Document::Document(const DocumentInit& initializer,
653 const SecurityContextInit& security_initializer,
654 DocumentClassFlags document_classes)
655 : ContainerNode(nullptr, kCreateDocument),
656 TreeScope(*this),
657 evaluate_media_queries_on_style_recalc_(false),
658 pending_sheet_layout_(kNoLayoutWithPendingSheets),
659 window_agent_factory_(initializer.GetWindowAgentFactory()),
660 frame_(initializer.GetFrame()),
661 // TODO(dcheng): Why does this need both a LocalFrame and LocalDOMWindow
662 // pointer?
663 dom_window_(frame_ ? frame_->DomWindow() : nullptr),
664 imports_controller_(initializer.ImportsController()),
665 security_context_(security_initializer, SecurityContext::kLocal),
666 use_counter_during_construction_(initializer.GetUseCounter()),
667 context_document_(initializer.ContextDocument()),
668 context_features_(ContextFeatures::DefaultSwitch()),
669 http_refresh_scheduler_(MakeGarbageCollected<HttpRefreshScheduler>(this)),
670 well_formed_(false),
671 printing_(kNotPrinting),
672 is_painting_preview_(false),
673 compatibility_mode_(kNoQuirksMode),
674 compatibility_mode_locked_(false),
675 last_focus_type_(mojom::blink::FocusType::kNone),
676 had_keyboard_event_(false),
677 clear_focused_element_timer_(
678 GetTaskRunner(TaskType::kInternalUserInteraction),
679 this,
680 &Document::ClearFocusedElementTimerFired),
681 dom_tree_version_(++global_tree_version_),
682 style_version_(0),
683 listener_types_(0),
684 mutation_observer_types_(0),
685 visited_link_state_(MakeGarbageCollected<VisitedLinkState>(*this)),
686 visually_ordered_(false),
687 // https://html.spec.whatwg.org/multipage/dom.html#current-document-readiness
688 // says the ready state starts as 'loading' if there's an associated
689 // parser and 'complete' otherwise. We don't know whether there's an
690 // associated parser here (we create the parser in ImplicitOpen). But
691 // waiting to set the ready state to 'loading' in ImplicitOpen fires a
692 // readystatechange event, which can be observed in the case where we
693 // reuse a window. If there's a window being reused, then there must be
694 // a frame, and if there's a frame, there must be an associated parser, so
695 // setting based on frame_ here is sufficient to ensure that the quirk of
696 // when we set the ready state is not web-observable.
697 ready_state_(frame_ ? kLoading : kComplete),
698 parsing_state_(kFinishedParsing),
699 contains_plugins_(false),
700 ignore_destructive_write_count_(0),
701 throw_on_dynamic_markup_insertion_count_(0),
702 ignore_opens_during_unload_count_(0),
703 markers_(MakeGarbageCollected<DocumentMarkerController>(*this)),
704 css_target_(nullptr),
705 was_discarded_(false),
706 load_event_progress_(kLoadEventCompleted),
707 is_freezing_in_progress_(false),
708 script_runner_(MakeGarbageCollected<ScriptRunner>(this)),
709 xml_version_("1.0"),
710 xml_standalone_(kStandaloneUnspecified),
711 has_xml_declaration_(0),
712 design_mode_(false),
713 is_running_exec_command_(false),
714 has_annotated_regions_(false),
715 annotated_regions_dirty_(false),
716 document_classes_(document_classes),
717 is_view_source_(false),
718 saw_elements_in_known_namespaces_(false),
719 is_srcdoc_document_(initializer.IsSrcdocDocument()),
720 is_mobile_document_(false),
721 layout_view_(nullptr),
722 has_fullscreen_supplement_(false),
723 load_event_delay_count_(0),
724 // We already intentionally fire load event asynchronously and here we use
725 // kDOMManipulation to ensure that we run onload() in order with other
726 // callbacks (e.g. onloadstart()) per the spec.
727 // See: https://html.spec.whatwg.org/#delay-the-load-event
728 load_event_delay_timer_(GetTaskRunner(TaskType::kDOMManipulation),
729 this,
730 &Document::LoadEventDelayTimerFired),
731 plugin_loading_timer_(GetTaskRunner(TaskType::kInternalLoading),
732 this,
733 &Document::PluginLoadingTimerFired),
734 document_timing_(*this),
735 write_recursion_is_too_deep_(false),
736 write_recursion_depth_(0),
737 scripted_animation_controller_(
738 MakeGarbageCollected<ScriptedAnimationController>(domWindow())),
739 current_frame_is_throttled_(false),
740 registration_context_(initializer.RegistrationContext(this)),
741 element_data_cache_clear_timer_(
742 GetTaskRunner(TaskType::kInternalUserInteraction),
743 this,
744 &Document::ElementDataCacheClearTimerFired),
745 document_animations_(MakeGarbageCollected<DocumentAnimations>(this)),
746 timeline_(MakeGarbageCollected<DocumentTimeline>(this)),
747 pending_animations_(MakeGarbageCollected<PendingAnimations>(*this)),
748 worklet_animation_controller_(
749 MakeGarbageCollected<WorkletAnimationController>(this)),
750 template_document_host_(nullptr),
751 did_associate_form_controls_timer_(
752 GetTaskRunner(TaskType::kInternalLoading),
753 this,
754 &Document::DidAssociateFormControlsTimerFired),
755 has_viewport_units_(false),
756 parser_sync_policy_(kAllowAsynchronousParsing),
757 node_count_(0),
758 logged_field_edit_(false),
759 ukm_source_id_(ukm::UkmRecorder::GetNewSourceID()),
760 needs_to_record_ukm_outlive_time_(false),
761 viewport_data_(MakeGarbageCollected<ViewportData>(*this)),
762 is_for_external_handler_(initializer.IsForExternalHandler()),
763 isolated_world_csp_map_(
764 MakeGarbageCollected<
765 HeapHashMap<int, Member<ContentSecurityPolicy>>>()),
766 permission_service_(GetExecutionContext()),
767 font_preload_manager_(*this) {
768 security_initializer.ApplyPendingDataToDocument(*this);
769 GetOriginTrialContext()->BindExecutionContext(GetExecutionContext());
770
771 if (frame_) {
772 pending_fp_headers_ = security_initializer.FeaturePolicyHeader();
773 pending_dp_headers_ = initializer.GetDocumentPolicy().feature_state;
774 }
775
776 if (frame_) {
777 DCHECK(frame_->GetPage());
778 ProvideContextFeaturesToDocumentFrom(*this, *frame_->GetPage());
779 fetcher_ = FrameFetchContext::CreateFetcherForCommittedDocument(
780 *frame_->Loader().GetDocumentLoader(), *this);
781 // TODO(dcheng): Why does this need to check that DOMWindow is non-null?
782 CustomElementRegistry* registry =
783 frame_->DomWindow() ? frame_->DomWindow()->MaybeCustomElements()
784 : nullptr;
785 if (registry && registration_context_)
786 registry->Entangle(registration_context_);
787 cookie_jar_ = MakeGarbageCollected<CookieJar>(this);
788 } else {
789 // We disable fetches for frame-less Documents, including HTML-imported
790 // Documents (if kHtmlImportsRequestInitiatorLock is enabled). Subresources
791 // of HTML-imported Documents are fetched via the context document's
792 // ResourceFetcher. See https://crbug.com/961614 for details.
793 auto& properties =
794 *MakeGarbageCollected<DetachableResourceFetcherProperties>(
795 *MakeGarbageCollected<NullResourceFetcherProperties>());
796 fetcher_ = MakeGarbageCollected<ResourceFetcher>(ResourceFetcherInit(
797 properties, &FetchContext::NullInstance(),
798 GetTaskRunner(TaskType::kNetworking), nullptr /* loader_factory */));
799
800 if (imports_controller_) {
801 // We don't expect the fetcher to be used, so count such unexpected use.
802 fetcher_->SetShouldLogRequestAsInvalidInImportedDocument();
803 }
804 }
805 DCHECK(fetcher_);
806
807 root_scroller_controller_ =
808 MakeGarbageCollected<RootScrollerController>(*this);
809
810 // We depend on the url getting immediately set in subframes, but we
811 // also depend on the url NOT getting immediately set in opened windows.
812 // See fast/dom/early-frame-url.html
813 // and fast/dom/location-new-window-no-crash.html, respectively.
814 // FIXME: Can/should we unify this behavior?
815 if (initializer.ShouldSetURL()) {
816 SetURL(initializer.Url());
817 } else {
818 // Even if this document has no URL, we need to initialize base URL with
819 // fallback base URL.
820 UpdateBaseURL();
821 }
822
823 if (initializer.GetWebBundleClaimedUrl().IsValid()) {
824 web_bundle_claimed_url_ = initializer.GetWebBundleClaimedUrl();
825 SetBaseURLOverride(initializer.GetWebBundleClaimedUrl());
826 }
827
828 InitSecurityContext(initializer);
829 PoliciesInitialized(initializer);
830 InitDNSPrefetch();
831
832 InstanceCounters::IncrementCounter(InstanceCounters::kDocumentCounter);
833
834 lifecycle_.AdvanceTo(DocumentLifecycle::kInactive);
835
836 UpdateForcedColors();
837
838 // Since CSSFontSelector requires Document::fetcher_ and StyleEngine owns
839 // CSSFontSelector, need to initialize |style_engine_| after initializing
840 // |fetcher_|.
841 style_engine_ = MakeGarbageCollected<StyleEngine>(*this);
842
843 // The parent's parser should be suspended together with all the other
844 // objects, else this new Document would have a new ExecutionContext which
845 // suspended state would not match the one from the parent, and could start
846 // loading resources ignoring the defersLoading flag.
847 DCHECK(!ParentDocument() || !ParentDocument()->IsContextPaused());
848
849 #ifndef NDEBUG
850 liveDocumentSet().insert(this);
851 #endif
852
853 if (frame_ && frame_->GetPage()->GetAgentMetricsCollector())
854 frame_->GetPage()->GetAgentMetricsCollector()->DidAttachDocument(*this);
855
856 // We will use Loader() as UseCounter after initialization.
857 use_counter_during_construction_ = nullptr;
858 }
859
~Document()860 Document::~Document() {
861 DCHECK(!GetLayoutView());
862 DCHECK(!ParentTreeScope());
863 // If a top document with a cache, verify that it was comprehensively
864 // cleared during detach.
865 DCHECK(!ax_object_cache_);
866
867 InstanceCounters::DecrementCounter(InstanceCounters::kDocumentCounter);
868 }
869
CreateRangeAdjustedToTreeScope(const TreeScope & tree_scope,const Position & position)870 Range* Document::CreateRangeAdjustedToTreeScope(const TreeScope& tree_scope,
871 const Position& position) {
872 DCHECK(position.IsNotNull());
873 // Note: Since |Position::ComputeContainerNode()| returns |nullptr| if
874 // |position| is |BeforeAnchor| or |AfterAnchor|.
875 Node* const anchor_node = position.AnchorNode();
876 if (anchor_node->GetTreeScope() == tree_scope) {
877 return MakeGarbageCollected<Range>(tree_scope.GetDocument(), position,
878 position);
879 }
880 Node* const shadow_host = tree_scope.AncestorInThisScope(anchor_node);
881 return MakeGarbageCollected<Range>(tree_scope.GetDocument(),
882 Position::BeforeNode(*shadow_host),
883 Position::BeforeNode(*shadow_host));
884 }
885
GetSelectorQueryCache()886 SelectorQueryCache& Document::GetSelectorQueryCache() {
887 if (!selector_query_cache_)
888 selector_query_cache_ = std::make_unique<SelectorQueryCache>();
889 return *selector_query_cache_;
890 }
891
GetMediaQueryMatcher()892 MediaQueryMatcher& Document::GetMediaQueryMatcher() {
893 if (!media_query_matcher_)
894 media_query_matcher_ = MakeGarbageCollected<MediaQueryMatcher>(*this);
895 return *media_query_matcher_;
896 }
897
MediaQueryAffectingValueChanged(MediaValueChange change)898 void Document::MediaQueryAffectingValueChanged(MediaValueChange change) {
899 GetStyleEngine().MediaQueryAffectingValueChanged(change);
900 if (NeedsLayoutTreeUpdate())
901 evaluate_media_queries_on_style_recalc_ = true;
902 else
903 EvaluateMediaQueryList();
904 probe::MediaQueryResultChanged(this);
905 }
906
SetCompatibilityMode(CompatibilityMode mode)907 void Document::SetCompatibilityMode(CompatibilityMode mode) {
908 if (compatibility_mode_locked_ || mode == compatibility_mode_)
909 return;
910
911 if (compatibility_mode_ == kQuirksMode)
912 UseCounter::Count(*this, WebFeature::kQuirksModeDocument);
913 else if (compatibility_mode_ == kLimitedQuirksMode)
914 UseCounter::Count(*this, WebFeature::kLimitedQuirksModeDocument);
915
916 compatibility_mode_ = mode;
917 GetSelectorQueryCache().Invalidate();
918 }
919
compatMode() const920 String Document::compatMode() const {
921 return InQuirksMode() ? "BackCompat" : "CSS1Compat";
922 }
923
SetDoctype(DocumentType * doc_type)924 void Document::SetDoctype(DocumentType* doc_type) {
925 // This should never be called more than once.
926 DCHECK(!doc_type_ || !doc_type);
927 doc_type_ = doc_type;
928 if (doc_type_) {
929 AdoptIfNeeded(*doc_type_);
930 if (doc_type_->publicId().StartsWithIgnoringASCIICase(
931 "-//wapforum//dtd xhtml mobile 1.")) {
932 is_mobile_document_ = true;
933 style_engine_->ViewportRulesChanged();
934 }
935 }
936 }
937
implementation()938 DOMImplementation& Document::implementation() {
939 if (!implementation_)
940 implementation_ = MakeGarbageCollected<DOMImplementation>(*this);
941 return *implementation_;
942 }
943
location() const944 Location* Document::location() const {
945 if (!GetFrame())
946 return nullptr;
947
948 return domWindow()->location();
949 }
950
GetContentSecurityPolicyForWorld()951 ContentSecurityPolicy* Document::GetContentSecurityPolicyForWorld() {
952 v8::Isolate* isolate = GetIsolate();
953 if (!isolate)
954 return GetContentSecurityPolicy();
955 v8::HandleScope handle_scope(isolate);
956 v8::Local<v8::Context> v8_context = isolate->GetCurrentContext();
957
958 // This can be called before we enter v8, hence the context might be empty,
959 // which implies we are not in an isolated world.
960 if (v8_context.IsEmpty())
961 return GetContentSecurityPolicy();
962
963 DOMWrapperWorld& world = DOMWrapperWorld::Current(isolate);
964 if (!world.IsIsolatedWorld())
965 return GetContentSecurityPolicy();
966
967 int32_t world_id = world.GetWorldId();
968 auto it = isolated_world_csp_map_->find(world_id);
969 if (it != isolated_world_csp_map_->end())
970 return it->value;
971
972 ContentSecurityPolicy* policy =
973 IsolatedWorldCSP::Get().CreateIsolatedWorldCSP(*this, world_id);
974 if (!policy)
975 return GetContentSecurityPolicy();
976
977 isolated_world_csp_map_->insert(world_id, policy);
978 return policy;
979 }
980
981 // static
From(ExecutionContext & context)982 Document& Document::From(ExecutionContext& context) {
983 SECURITY_DCHECK(context.IsDocument());
984 return *static_cast<LocalDOMWindow&>(context).document();
985 }
986
987 // static
From(const ExecutionContext & context)988 const Document& Document::From(const ExecutionContext& context) {
989 SECURITY_DCHECK(context.IsDocument());
990 return *static_cast<const LocalDOMWindow&>(context).document();
991 }
992
ToExecutionContext()993 ExecutionContext* Document::ToExecutionContext() {
994 return GetExecutionContext();
995 }
996
ToExecutionContext() const997 const ExecutionContext* Document::ToExecutionContext() const {
998 return GetExecutionContext();
999 }
1000
FeatureEnabled(OriginTrialFeature feature) const1001 bool Document::FeatureEnabled(OriginTrialFeature feature) const {
1002 return GetOriginTrialContext()->IsFeatureEnabled(feature);
1003 }
1004
CountFeaturePolicyUsage(mojom::WebFeature feature)1005 void Document::CountFeaturePolicyUsage(mojom::WebFeature feature) {
1006 UseCounter::Count(*this, feature);
1007 }
1008
FeaturePolicyFeatureObserved(mojom::blink::FeaturePolicyFeature feature)1009 bool Document::FeaturePolicyFeatureObserved(
1010 mojom::blink::FeaturePolicyFeature feature) {
1011 wtf_size_t feature_index = static_cast<wtf_size_t>(feature);
1012 if (parsed_feature_policies_.size() == 0) {
1013 parsed_feature_policies_.resize(
1014 static_cast<wtf_size_t>(mojom::blink::FeaturePolicyFeature::kMaxValue) +
1015 1);
1016 } else if (parsed_feature_policies_[feature_index]) {
1017 return true;
1018 }
1019 parsed_feature_policies_[feature_index] = true;
1020 return false;
1021 }
1022
GetSecurityOrigin() const1023 const SecurityOrigin* Document::GetSecurityOrigin() const {
1024 return GetSecurityContext().GetSecurityOrigin();
1025 }
1026
GetMutableSecurityOrigin()1027 SecurityOrigin* Document::GetMutableSecurityOrigin() {
1028 return GetSecurityContext().GetMutableSecurityOrigin();
1029 }
1030
GetContentSecurityPolicy() const1031 ContentSecurityPolicy* Document::GetContentSecurityPolicy() const {
1032 return GetSecurityContext().GetContentSecurityPolicy();
1033 }
1034
GetSandboxFlags() const1035 mojom::blink::WebSandboxFlags Document::GetSandboxFlags() const {
1036 return GetSecurityContext().GetSandboxFlags();
1037 }
1038
IsSandboxed(mojom::blink::WebSandboxFlags mask) const1039 bool Document::IsSandboxed(mojom::blink::WebSandboxFlags mask) const {
1040 return GetSecurityContext().IsSandboxed(mask);
1041 }
1042
GetPublicURLManager()1043 PublicURLManager& Document::GetPublicURLManager() {
1044 DCHECK(GetExecutionContext());
1045 return GetExecutionContext()->GetPublicURLManager();
1046 }
1047
IsContextPaused() const1048 bool Document::IsContextPaused() const {
1049 return GetExecutionContext() ? GetExecutionContext()->IsContextPaused()
1050 : false;
1051 }
1052
IsContextDestroyed() const1053 bool Document::IsContextDestroyed() const {
1054 return GetExecutionContext() ? GetExecutionContext()->IsContextDestroyed()
1055 : true;
1056 }
1057
GetContentSecurityPolicyDelegate()1058 ContentSecurityPolicyDelegate& Document::GetContentSecurityPolicyDelegate() {
1059 return GetExecutionContext()->GetContentSecurityPolicyDelegate();
1060 }
1061
GetSecureContextMode() const1062 SecureContextMode Document::GetSecureContextMode() const {
1063 return GetSecurityContext().GetSecureContextMode();
1064 }
1065
IsSecureContext() const1066 bool Document::IsSecureContext() const {
1067 return GetExecutionContext()->IsSecureContext();
1068 }
1069
IsSecureContext(String & error_message) const1070 bool Document::IsSecureContext(String& error_message) const {
1071 return GetExecutionContext()->IsSecureContext(error_message);
1072 }
1073
SetReferrerPolicy(network::mojom::ReferrerPolicy policy)1074 void Document::SetReferrerPolicy(network::mojom::ReferrerPolicy policy) {
1075 GetExecutionContext()->SetReferrerPolicy(policy);
1076 }
1077
GetIsolate() const1078 v8::Isolate* Document::GetIsolate() const {
1079 return GetExecutionContext() ? GetExecutionContext()->GetIsolate() : nullptr;
1080 }
1081
GetAgent() const1082 Agent* Document::GetAgent() const {
1083 return GetSecurityContext().GetAgent();
1084 }
1085
GetOriginTrialContext() const1086 OriginTrialContext* Document::GetOriginTrialContext() const {
1087 return MasterDocument().GetSecurityContext().GetOriginTrialContext();
1088 }
1089
SetSecureContextModeForTesting(SecureContextMode mode)1090 void Document::SetSecureContextModeForTesting(SecureContextMode mode) {
1091 GetSecurityContext().SetSecureContextModeForTesting(mode);
1092 }
1093
IsFeatureEnabled(mojom::blink::FeaturePolicyFeature feature,ReportOptions report_on_failure,const String & message,const String & source_file) const1094 bool Document::IsFeatureEnabled(mojom::blink::FeaturePolicyFeature feature,
1095 ReportOptions report_on_failure,
1096 const String& message,
1097 const String& source_file) const {
1098 return GetExecutionContext() &&
1099 GetExecutionContext()->IsFeatureEnabled(feature, report_on_failure,
1100 message, source_file);
1101 }
1102
IsFeatureEnabled(mojom::blink::FeaturePolicyFeature feature,PolicyValue threshold_value,ReportOptions report_on_failure,const String & message,const String & source_file) const1103 bool Document::IsFeatureEnabled(mojom::blink::FeaturePolicyFeature feature,
1104 PolicyValue threshold_value,
1105 ReportOptions report_on_failure,
1106 const String& message,
1107 const String& source_file) const {
1108 return GetExecutionContext() &&
1109 GetExecutionContext()->IsFeatureEnabled(
1110 feature, threshold_value, report_on_failure, message, source_file);
1111 }
1112
IsFeatureEnabled(mojom::blink::DocumentPolicyFeature feature,ReportOptions report_option,const String & message,const String & source_file) const1113 bool Document::IsFeatureEnabled(mojom::blink::DocumentPolicyFeature feature,
1114 ReportOptions report_option,
1115 const String& message,
1116 const String& source_file) const {
1117 return GetExecutionContext() &&
1118 GetExecutionContext()->IsFeatureEnabled(feature, report_option,
1119 message, source_file);
1120 }
1121
IsFeatureEnabled(mojom::blink::DocumentPolicyFeature feature,PolicyValue threshold_value,ReportOptions report_option,const String & message,const String & source_file) const1122 bool Document::IsFeatureEnabled(mojom::blink::DocumentPolicyFeature feature,
1123 PolicyValue threshold_value,
1124 ReportOptions report_option,
1125 const String& message,
1126 const String& source_file) const {
1127 return GetExecutionContext() &&
1128 GetExecutionContext()->IsFeatureEnabled(
1129 feature, threshold_value, report_option, message, source_file);
1130 }
1131
addressSpaceForBindings() const1132 String Document::addressSpaceForBindings() const {
1133 return GetExecutionContext()->addressSpaceForBindings();
1134 }
1135
ChildrenChanged(const ChildrenChange & change)1136 void Document::ChildrenChanged(const ChildrenChange& change) {
1137 ContainerNode::ChildrenChanged(change);
1138 document_element_ = ElementTraversal::FirstWithin(*this);
1139
1140 // For non-HTML documents the willInsertBody notification won't happen
1141 // so we resume as soon as we have a document element. Even for XHTML
1142 // documents there may never be a <body> (since the parser won't always
1143 // insert one), so we resume here too. That does mean XHTML documents make
1144 // frames when there's only a <head>, but such documents are pretty rare.
1145 if (document_element_ && !IsA<HTMLDocument>(this))
1146 BeginLifecycleUpdatesIfRenderingReady();
1147 }
1148
setRootScroller(Element * new_scroller,ExceptionState &)1149 void Document::setRootScroller(Element* new_scroller, ExceptionState&) {
1150 root_scroller_controller_->Set(new_scroller);
1151 }
1152
rootScroller() const1153 Element* Document::rootScroller() const {
1154 return root_scroller_controller_->Get();
1155 }
1156
IsInMainFrame() const1157 bool Document::IsInMainFrame() const {
1158 return GetFrame() && GetFrame()->IsMainFrame();
1159 }
1160
ConvertLocalName(const AtomicString & name)1161 AtomicString Document::ConvertLocalName(const AtomicString& name) {
1162 return IsA<HTMLDocument>(this) ? name.LowerASCII() : name;
1163 }
1164
1165 // Just creates an element with specified qualified name without any
1166 // custom element processing.
1167 // This is a common code for step 5.2 and 7.2 of "create an element"
1168 // <https://dom.spec.whatwg.org/#concept-create-element>
1169 // Functions other than this one should not use HTMLElementFactory and
1170 // SVGElementFactory because they don't support prefixes correctly.
CreateRawElement(const QualifiedName & qname,CreateElementFlags flags)1171 Element* Document::CreateRawElement(const QualifiedName& qname,
1172 CreateElementFlags flags) {
1173 Element* element = nullptr;
1174 if (qname.NamespaceURI() == html_names::xhtmlNamespaceURI) {
1175 // https://html.spec.whatwg.org/C/#elements-in-the-dom:element-interface
1176 element = HTMLElementFactory::Create(qname.LocalName(), *this, flags);
1177 if (!element) {
1178 // 6. If name is a valid custom element name, then return
1179 // HTMLElement.
1180 // 7. Return HTMLUnknownElement.
1181 if (CustomElement::IsValidName(qname.LocalName()))
1182 element = MakeGarbageCollected<HTMLElement>(qname, *this);
1183 else
1184 element = MakeGarbageCollected<HTMLUnknownElement>(qname, *this);
1185 }
1186 saw_elements_in_known_namespaces_ = true;
1187 } else if (qname.NamespaceURI() == svg_names::kNamespaceURI) {
1188 element = SVGElementFactory::Create(qname.LocalName(), *this, flags);
1189 if (!element)
1190 element = MakeGarbageCollected<SVGUnknownElement>(qname, *this);
1191 saw_elements_in_known_namespaces_ = true;
1192 } else if (RuntimeEnabledFeatures::MathMLCoreEnabled() &&
1193 qname.NamespaceURI() == mathml_names::kNamespaceURI) {
1194 element = MathMLElementFactory::Create(qname.LocalName(), *this, flags);
1195 // An unknown MathML element is treated like an <mrow> element.
1196 // TODO(crbug.com/1021837): Determine if we need to introduce a
1197 // MathMLUnknownElement IDL.
1198 if (!element)
1199 element = MakeGarbageCollected<MathMLRowElement>(qname, *this);
1200 saw_elements_in_known_namespaces_ = true;
1201 } else {
1202 element = MakeGarbageCollected<Element>(qname, this);
1203 }
1204
1205 if (element->prefix() != qname.Prefix())
1206 element->SetTagNameForCreateElementNS(qname);
1207 DCHECK(qname == element->TagQName());
1208
1209 return element;
1210 }
1211
1212 // https://dom.spec.whatwg.org/#dom-document-createelement
CreateElementForBinding(const AtomicString & name,ExceptionState & exception_state)1213 Element* Document::CreateElementForBinding(const AtomicString& name,
1214 ExceptionState& exception_state) {
1215 if (!IsValidElementName(this, name)) {
1216 exception_state.ThrowDOMException(
1217 DOMExceptionCode::kInvalidCharacterError,
1218 "The tag name provided ('" + name + "') is not a valid name.");
1219 return nullptr;
1220 }
1221
1222 if (IsXHTMLDocument() || IsA<HTMLDocument>(this)) {
1223 // 2. If the context object is an HTML document, let localName be
1224 // converted to ASCII lowercase.
1225 AtomicString local_name = ConvertLocalName(name);
1226 if (CustomElement::ShouldCreateCustomElement(local_name)) {
1227 return CustomElement::CreateCustomElement(
1228 *this,
1229 QualifiedName(g_null_atom, local_name, html_names::xhtmlNamespaceURI),
1230 CreateElementFlags::ByCreateElement());
1231 }
1232 if (auto* element = HTMLElementFactory::Create(
1233 local_name, *this, CreateElementFlags::ByCreateElement()))
1234 return element;
1235 QualifiedName q_name(g_null_atom, local_name,
1236 html_names::xhtmlNamespaceURI);
1237 if (RegistrationContext() && V0CustomElement::IsValidName(local_name))
1238 return RegistrationContext()->CreateCustomTagElement(*this, q_name);
1239 return MakeGarbageCollected<HTMLUnknownElement>(q_name, *this);
1240 }
1241 return MakeGarbageCollected<Element>(
1242 QualifiedName(g_null_atom, name, g_null_atom), this);
1243 }
1244
GetTypeExtension(Document * document,const StringOrElementCreationOptions & string_or_options)1245 AtomicString GetTypeExtension(
1246 Document* document,
1247 const StringOrElementCreationOptions& string_or_options) {
1248 if (string_or_options.IsNull())
1249 return AtomicString();
1250
1251 if (string_or_options.IsString()) {
1252 UseCounter::Count(document,
1253 WebFeature::kDocumentCreateElement2ndArgStringHandling);
1254 return AtomicString(string_or_options.GetAsString());
1255 }
1256
1257 if (string_or_options.IsElementCreationOptions()) {
1258 const ElementCreationOptions& options =
1259 *string_or_options.GetAsElementCreationOptions();
1260 if (options.hasIs())
1261 return AtomicString(options.is());
1262 }
1263
1264 return AtomicString();
1265 }
1266
1267 // https://dom.spec.whatwg.org/#dom-document-createelement
CreateElementForBinding(const AtomicString & local_name,const StringOrElementCreationOptions & string_or_options,ExceptionState & exception_state)1268 Element* Document::CreateElementForBinding(
1269 const AtomicString& local_name,
1270 const StringOrElementCreationOptions& string_or_options,
1271 ExceptionState& exception_state) {
1272 if (string_or_options.IsNull()) {
1273 return CreateElementForBinding(local_name, exception_state);
1274 }
1275
1276 // 1. If localName does not match Name production, throw InvalidCharacterError
1277 if (!IsValidElementName(this, local_name)) {
1278 exception_state.ThrowDOMException(
1279 DOMExceptionCode::kInvalidCharacterError,
1280 "The tag name provided ('" + local_name + "') is not a valid name.");
1281 return nullptr;
1282 }
1283
1284 // 2. localName converted to ASCII lowercase
1285 const AtomicString& converted_local_name = ConvertLocalName(local_name);
1286 QualifiedName q_name(g_null_atom, converted_local_name,
1287 IsXHTMLDocument() || IsA<HTMLDocument>(this)
1288 ? html_names::xhtmlNamespaceURI
1289 : g_null_atom);
1290
1291 bool is_v1 =
1292 string_or_options.IsElementCreationOptions() || !RegistrationContext();
1293 // V0 is only allowed with the flag.
1294 DCHECK(is_v1 || RuntimeEnabledFeatures::CustomElementsV0Enabled(this));
1295 bool create_v1_builtin = string_or_options.IsElementCreationOptions();
1296 bool should_create_builtin =
1297 create_v1_builtin || string_or_options.IsString();
1298
1299 // 3.
1300 const AtomicString& is = GetTypeExtension(this, string_or_options);
1301
1302 // 5. Let element be the result of creating an element given ...
1303 Element* element =
1304 CreateElement(q_name,
1305 is_v1 ? CreateElementFlags::ByCreateElementV1()
1306 : CreateElementFlags::ByCreateElementV0(),
1307 should_create_builtin ? is : g_null_atom);
1308
1309 // 8. If 'is' is non-null, set 'is' attribute
1310 if (!is_v1 && !is.IsEmpty())
1311 element->setAttribute(html_names::kIsAttr, is);
1312
1313 return element;
1314 }
1315
CreateQualifiedName(const AtomicString & namespace_uri,const AtomicString & qualified_name,ExceptionState & exception_state)1316 static inline QualifiedName CreateQualifiedName(
1317 const AtomicString& namespace_uri,
1318 const AtomicString& qualified_name,
1319 ExceptionState& exception_state) {
1320 AtomicString prefix, local_name;
1321 if (!Document::ParseQualifiedName(qualified_name, prefix, local_name,
1322 exception_state))
1323 return QualifiedName::Null();
1324
1325 QualifiedName q_name(prefix, local_name, namespace_uri);
1326 if (!Document::HasValidNamespaceForElements(q_name)) {
1327 exception_state.ThrowDOMException(
1328 DOMExceptionCode::kNamespaceError,
1329 "The namespace URI provided ('" + namespace_uri +
1330 "') is not valid for the qualified name provided ('" +
1331 qualified_name + "').");
1332 return QualifiedName::Null();
1333 }
1334
1335 return q_name;
1336 }
1337
createElementNS(const AtomicString & namespace_uri,const AtomicString & qualified_name,ExceptionState & exception_state)1338 Element* Document::createElementNS(const AtomicString& namespace_uri,
1339 const AtomicString& qualified_name,
1340 ExceptionState& exception_state) {
1341 QualifiedName q_name(
1342 CreateQualifiedName(namespace_uri, qualified_name, exception_state));
1343 if (q_name == QualifiedName::Null())
1344 return nullptr;
1345
1346 CreateElementFlags flags = CreateElementFlags::ByCreateElement();
1347 if (CustomElement::ShouldCreateCustomElement(q_name))
1348 return CustomElement::CreateCustomElement(*this, q_name, flags);
1349 if (RegistrationContext() && V0CustomElement::IsValidName(q_name.LocalName()))
1350 return RegistrationContext()->CreateCustomTagElement(*this, q_name);
1351 return CreateRawElement(q_name, flags);
1352 }
1353
1354 // https://dom.spec.whatwg.org/#internal-createelementns-steps
createElementNS(const AtomicString & namespace_uri,const AtomicString & qualified_name,const StringOrElementCreationOptions & string_or_options,ExceptionState & exception_state)1355 Element* Document::createElementNS(
1356 const AtomicString& namespace_uri,
1357 const AtomicString& qualified_name,
1358 const StringOrElementCreationOptions& string_or_options,
1359 ExceptionState& exception_state) {
1360 if (string_or_options.IsNull())
1361 return createElementNS(namespace_uri, qualified_name, exception_state);
1362
1363 // 1. Validate and extract
1364 QualifiedName q_name(
1365 CreateQualifiedName(namespace_uri, qualified_name, exception_state));
1366 if (q_name == QualifiedName::Null())
1367 return nullptr;
1368
1369 bool is_v1 =
1370 string_or_options.IsElementCreationOptions() || !RegistrationContext();
1371 // V0 is only allowed with the flag.
1372 DCHECK(is_v1 || RuntimeEnabledFeatures::CustomElementsV0Enabled(this));
1373 bool create_v1_builtin = string_or_options.IsElementCreationOptions();
1374 bool should_create_builtin =
1375 create_v1_builtin || string_or_options.IsString();
1376
1377 // 2.
1378 const AtomicString& is = GetTypeExtension(this, string_or_options);
1379
1380 if (!IsValidElementName(this, qualified_name)) {
1381 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidCharacterError,
1382 "The tag name provided ('" +
1383 qualified_name +
1384 "') is not a valid name.");
1385 return nullptr;
1386 }
1387
1388 // 3. Let element be the result of creating an element
1389 Element* element =
1390 CreateElement(q_name,
1391 is_v1 ? CreateElementFlags::ByCreateElementV1()
1392 : CreateElementFlags::ByCreateElementV0(),
1393 should_create_builtin ? is : g_null_atom);
1394
1395 // 4. If 'is' is non-null, set 'is' attribute
1396 if (!is_v1 && !is.IsEmpty())
1397 element->setAttribute(html_names::kIsAttr, is);
1398
1399 return element;
1400 }
1401
1402 // Entry point of "create an element".
1403 // https://dom.spec.whatwg.org/#concept-create-element
CreateElement(const QualifiedName & q_name,const CreateElementFlags flags,const AtomicString & is)1404 Element* Document::CreateElement(const QualifiedName& q_name,
1405 const CreateElementFlags flags,
1406 const AtomicString& is) {
1407 CustomElementDefinition* definition = nullptr;
1408 if (flags.IsCustomElementsV1() &&
1409 q_name.NamespaceURI() == html_names::xhtmlNamespaceURI) {
1410 const CustomElementDescriptor desc(is.IsNull() ? q_name.LocalName() : is,
1411 q_name.LocalName());
1412 if (CustomElementRegistry* registry = CustomElement::Registry(*this))
1413 definition = registry->DefinitionFor(desc);
1414 }
1415
1416 if (definition)
1417 return definition->CreateElement(*this, q_name, flags);
1418
1419 return CustomElement::CreateUncustomizedOrUndefinedElement(*this, q_name,
1420 flags, is);
1421 }
1422
registerElement(ScriptState * script_state,const AtomicString & name,const ElementRegistrationOptions * options,ExceptionState & exception_state)1423 ScriptValue Document::registerElement(ScriptState* script_state,
1424 const AtomicString& name,
1425 const ElementRegistrationOptions* options,
1426 ExceptionState& exception_state) {
1427 if (!RegistrationContext()) {
1428 exception_state.ThrowDOMException(
1429 DOMExceptionCode::kNotSupportedError,
1430 "No element registration context is available.");
1431 return ScriptValue();
1432 }
1433
1434 // Polymer V1 uses Custom Elements V0. <dom-module> is defined in its base
1435 // library and is a strong signal that this is a Polymer V1.
1436 // This counter is used to research how much users are affected once Custom
1437 // Element V0 is deprecated.
1438 if (name == "dom-module")
1439 UseCounter::Count(*this, WebFeature::kPolymerV1Detected);
1440
1441 V0CustomElementConstructorBuilder constructor_builder(script_state, options);
1442 RegistrationContext()->RegisterElement(this, &constructor_builder, name,
1443 exception_state);
1444 if (exception_state.HadException())
1445 return ScriptValue();
1446 return constructor_builder.BindingsReturnValue();
1447 }
1448
RegistrationContext() const1449 V0CustomElementRegistrationContext* Document::RegistrationContext() const {
1450 if (RuntimeEnabledFeatures::CustomElementsV0Enabled(this))
1451 return registration_context_.Get();
1452 return nullptr;
1453 }
1454
CustomElementMicrotaskRunQueue()1455 V0CustomElementMicrotaskRunQueue* Document::CustomElementMicrotaskRunQueue() {
1456 if (!custom_element_microtask_run_queue_) {
1457 custom_element_microtask_run_queue_ =
1458 MakeGarbageCollected<V0CustomElementMicrotaskRunQueue>();
1459 }
1460 return custom_element_microtask_run_queue_.Get();
1461 }
1462
ClearImportsController()1463 void Document::ClearImportsController() {
1464 fetcher_->ClearContext();
1465 imports_controller_ = nullptr;
1466 }
1467
EnsureImportsController()1468 HTMLImportsController* Document::EnsureImportsController() {
1469 if (!imports_controller_) {
1470 DCHECK(frame_);
1471 imports_controller_ = MakeGarbageCollected<HTMLImportsController>(*this);
1472 }
1473
1474 return imports_controller_;
1475 }
1476
ImportLoader() const1477 HTMLImportLoader* Document::ImportLoader() const {
1478 if (!imports_controller_)
1479 return nullptr;
1480 return imports_controller_->LoaderFor(*this);
1481 }
1482
IsHTMLImport() const1483 bool Document::IsHTMLImport() const {
1484 return imports_controller_ && imports_controller_->Master() != this;
1485 }
1486
MasterDocument() const1487 Document& Document::MasterDocument() const {
1488 if (!imports_controller_)
1489 return *const_cast<Document*>(this);
1490
1491 Document* master = imports_controller_->Master();
1492 DCHECK(master);
1493 return *master;
1494 }
1495
HaveImportsLoaded() const1496 bool Document::HaveImportsLoaded() const {
1497 if (!imports_controller_)
1498 return true;
1499 return !imports_controller_->ShouldBlockScriptExecution(*this);
1500 }
1501
ExecutingWindow() const1502 LocalDOMWindow* Document::ExecutingWindow() const {
1503 if (LocalDOMWindow* owning_window = domWindow())
1504 return owning_window;
1505 if (HTMLImportsController* import = ImportsController())
1506 return import->Master()->domWindow();
1507 return nullptr;
1508 }
1509
ExecutingFrame()1510 LocalFrame* Document::ExecutingFrame() {
1511 LocalDOMWindow* window = ExecutingWindow();
1512 if (!window)
1513 return nullptr;
1514 return window->GetFrame();
1515 }
1516
createDocumentFragment()1517 DocumentFragment* Document::createDocumentFragment() {
1518 return DocumentFragment::Create(*this);
1519 }
1520
createTextNode(const String & data)1521 Text* Document::createTextNode(const String& data) {
1522 return Text::Create(*this, data);
1523 }
1524
createComment(const String & data)1525 Comment* Document::createComment(const String& data) {
1526 return Comment::Create(*this, data);
1527 }
1528
createCDATASection(const String & data,ExceptionState & exception_state)1529 CDATASection* Document::createCDATASection(const String& data,
1530 ExceptionState& exception_state) {
1531 if (IsA<HTMLDocument>(this)) {
1532 exception_state.ThrowDOMException(
1533 DOMExceptionCode::kNotSupportedError,
1534 "This operation is not supported for HTML documents.");
1535 return nullptr;
1536 }
1537 if (data.Contains("]]>")) {
1538 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidCharacterError,
1539 "String cannot contain ']]>' since that "
1540 "is the end delimiter of a CData "
1541 "section.");
1542 return nullptr;
1543 }
1544 return CDATASection::Create(*this, data);
1545 }
1546
createProcessingInstruction(const String & target,const String & data,ExceptionState & exception_state)1547 ProcessingInstruction* Document::createProcessingInstruction(
1548 const String& target,
1549 const String& data,
1550 ExceptionState& exception_state) {
1551 if (!IsValidName(target)) {
1552 exception_state.ThrowDOMException(
1553 DOMExceptionCode::kInvalidCharacterError,
1554 "The target provided ('" + target + "') is not a valid name.");
1555 return nullptr;
1556 }
1557 if (data.Contains("?>")) {
1558 exception_state.ThrowDOMException(
1559 DOMExceptionCode::kInvalidCharacterError,
1560 "The data provided ('" + data + "') contains '?>'.");
1561 return nullptr;
1562 }
1563 if (IsA<HTMLDocument>(this)) {
1564 UseCounter::Count(*this,
1565 WebFeature::kHTMLDocumentCreateProcessingInstruction);
1566 }
1567 return MakeGarbageCollected<ProcessingInstruction>(*this, target, data);
1568 }
1569
CreateEditingTextNode(const String & text)1570 Text* Document::CreateEditingTextNode(const String& text) {
1571 return Text::CreateEditingText(*this, text);
1572 }
1573
importNode(Node * imported_node,bool deep,ExceptionState & exception_state)1574 Node* Document::importNode(Node* imported_node,
1575 bool deep,
1576 ExceptionState& exception_state) {
1577 // https://dom.spec.whatwg.org/#dom-document-importnode
1578
1579 // 1. If node is a document or shadow root, then throw a "NotSupportedError"
1580 // DOMException.
1581 if (imported_node->IsDocumentNode()) {
1582 exception_state.ThrowDOMException(
1583 DOMExceptionCode::kNotSupportedError,
1584 "The node provided is a document, which may not be imported.");
1585 return nullptr;
1586 }
1587 if (imported_node->IsShadowRoot()) {
1588 // ShadowRoot nodes should not be explicitly importable. Either they are
1589 // imported along with their host node, or created implicitly.
1590 exception_state.ThrowDOMException(
1591 DOMExceptionCode::kNotSupportedError,
1592 "The node provided is a shadow root, which may not be imported.");
1593 return nullptr;
1594 }
1595
1596 // 2. Return a clone of node, with context object and the clone children flag
1597 // set if deep is true.
1598 return imported_node->Clone(
1599 *this, deep ? CloneChildrenFlag::kClone : CloneChildrenFlag::kSkip);
1600 }
1601
adoptNode(Node * source,ExceptionState & exception_state)1602 Node* Document::adoptNode(Node* source, ExceptionState& exception_state) {
1603 EventQueueScope scope;
1604
1605 switch (source->getNodeType()) {
1606 case kDocumentNode:
1607 exception_state.ThrowDOMException(DOMExceptionCode::kNotSupportedError,
1608 "The node provided is of type '" +
1609 source->nodeName() +
1610 "', which may not be adopted.");
1611 return nullptr;
1612 case kAttributeNode: {
1613 auto* attr = To<Attr>(source);
1614 if (Element* owner_element = attr->ownerElement())
1615 owner_element->removeAttributeNode(attr, exception_state);
1616 break;
1617 }
1618 default:
1619 if (source->IsShadowRoot()) {
1620 // ShadowRoot cannot disconnect itself from the host node.
1621 exception_state.ThrowDOMException(
1622 DOMExceptionCode::kHierarchyRequestError,
1623 "The node provided is a shadow root, which may not be adopted.");
1624 return nullptr;
1625 }
1626
1627 if (auto* frame_owner_element =
1628 DynamicTo<HTMLFrameOwnerElement>(source)) {
1629 if (GetFrame() && GetFrame()->Tree().IsDescendantOf(
1630 frame_owner_element->ContentFrame())) {
1631 exception_state.ThrowDOMException(
1632 DOMExceptionCode::kHierarchyRequestError,
1633 "The node provided is a frame which contains this document.");
1634 return nullptr;
1635 }
1636 }
1637 if (source->parentNode()) {
1638 source->parentNode()->RemoveChild(source, exception_state);
1639 if (exception_state.HadException())
1640 return nullptr;
1641 // The above removeChild() can execute arbitrary JavaScript code.
1642 if (source->parentNode()) {
1643 AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
1644 mojom::ConsoleMessageSource::kJavaScript,
1645 mojom::ConsoleMessageLevel::kWarning,
1646 ExceptionMessages::FailedToExecute("adoptNode", "Document",
1647 "Unable to remove the "
1648 "specified node from the "
1649 "original parent.")));
1650 return nullptr;
1651 }
1652 }
1653 }
1654
1655 AdoptIfNeeded(*source);
1656
1657 return source;
1658 }
1659
HasValidNamespaceForElements(const QualifiedName & q_name)1660 bool Document::HasValidNamespaceForElements(const QualifiedName& q_name) {
1661 // These checks are from DOM Core Level 2, createElementNS
1662 // http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-DocCrElNS
1663 // createElementNS(null, "html:div")
1664 if (!q_name.Prefix().IsEmpty() && q_name.NamespaceURI().IsNull())
1665 return false;
1666 // createElementNS("http://www.example.com", "xml:lang")
1667 if (q_name.Prefix() == g_xml_atom &&
1668 q_name.NamespaceURI() != xml_names::kNamespaceURI)
1669 return false;
1670
1671 // Required by DOM Level 3 Core and unspecified by DOM Level 2 Core:
1672 // http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS
1673 // createElementNS("http://www.w3.org/2000/xmlns/", "foo:bar"),
1674 // createElementNS(null, "xmlns:bar"), createElementNS(null, "xmlns")
1675 if (q_name.Prefix() == g_xmlns_atom ||
1676 (q_name.Prefix().IsEmpty() && q_name.LocalName() == g_xmlns_atom))
1677 return q_name.NamespaceURI() == xmlns_names::kNamespaceURI;
1678 return q_name.NamespaceURI() != xmlns_names::kNamespaceURI;
1679 }
1680
HasValidNamespaceForAttributes(const QualifiedName & q_name)1681 bool Document::HasValidNamespaceForAttributes(const QualifiedName& q_name) {
1682 return HasValidNamespaceForElements(q_name);
1683 }
1684
readyState() const1685 String Document::readyState() const {
1686 DEFINE_STATIC_LOCAL(const String, loading, ("loading"));
1687 DEFINE_STATIC_LOCAL(const String, interactive, ("interactive"));
1688 DEFINE_STATIC_LOCAL(const String, complete, ("complete"));
1689
1690 switch (ready_state_) {
1691 case kLoading:
1692 return loading;
1693 case kInteractive:
1694 return interactive;
1695 case kComplete:
1696 return complete;
1697 }
1698
1699 NOTREACHED();
1700 return String();
1701 }
1702
SetReadyState(DocumentReadyState ready_state)1703 void Document::SetReadyState(DocumentReadyState ready_state) {
1704 if (ready_state == ready_state_)
1705 return;
1706
1707 switch (ready_state) {
1708 case kLoading:
1709 if (document_timing_.DomLoading().is_null()) {
1710 document_timing_.MarkDomLoading();
1711 }
1712 break;
1713 case kInteractive:
1714 if (document_timing_.DomInteractive().is_null())
1715 document_timing_.MarkDomInteractive();
1716 break;
1717 case kComplete:
1718 if (document_timing_.DomComplete().is_null())
1719 document_timing_.MarkDomComplete();
1720 break;
1721 }
1722
1723 ready_state_ = ready_state;
1724 DispatchEvent(*Event::Create(event_type_names::kReadystatechange));
1725 }
1726
IsLoadCompleted() const1727 bool Document::IsLoadCompleted() const {
1728 return ready_state_ == kComplete;
1729 }
1730
EncodingName() const1731 AtomicString Document::EncodingName() const {
1732 // TextEncoding::name() returns a char*, no need to allocate a new
1733 // String for it each time.
1734 // FIXME: We should fix TextEncoding to speak AtomicString anyway.
1735 return AtomicString(Encoding().GetName());
1736 }
1737
SetContentLanguage(const AtomicString & language)1738 void Document::SetContentLanguage(const AtomicString& language) {
1739 if (content_language_ == language)
1740 return;
1741 content_language_ = language;
1742
1743 // Document's style depends on the content language.
1744 GetStyleEngine().MarkViewportStyleDirty();
1745 GetStyleEngine().MarkAllElementsForStyleRecalc(
1746 StyleChangeReasonForTracing::Create(style_change_reason::kLanguage));
1747 }
1748
setXMLVersion(const String & version,ExceptionState & exception_state)1749 void Document::setXMLVersion(const String& version,
1750 ExceptionState& exception_state) {
1751 if (!XMLDocumentParser::SupportsXMLVersion(version)) {
1752 exception_state.ThrowDOMException(
1753 DOMExceptionCode::kNotSupportedError,
1754 "This document does not support the XML version '" + version + "'.");
1755 return;
1756 }
1757
1758 xml_version_ = version;
1759 }
1760
setXMLStandalone(bool standalone,ExceptionState & exception_state)1761 void Document::setXMLStandalone(bool standalone,
1762 ExceptionState& exception_state) {
1763 xml_standalone_ = standalone ? kStandalone : kNotStandalone;
1764 }
1765
SetContent(const String & content)1766 void Document::SetContent(const String& content) {
1767 // Only set the content of the document if it is ready to be set. This method
1768 // could be called at any time.
1769 if (ScriptableDocumentParser* parser = GetScriptableDocumentParser()) {
1770 if (parser->IsParsing() && parser->IsExecutingScript())
1771 return;
1772 }
1773 if (ignore_opens_during_unload_count_)
1774 return;
1775
1776 open();
1777 parser_->Append(content);
1778 close();
1779 }
1780
SuggestedMIMEType() const1781 String Document::SuggestedMIMEType() const {
1782 if (IsA<XMLDocument>(this)) {
1783 if (IsXHTMLDocument())
1784 return "application/xhtml+xml";
1785 if (IsSVGDocument())
1786 return "image/svg+xml";
1787 return "application/xml";
1788 }
1789 if (xmlStandalone())
1790 return "text/xml";
1791 if (IsA<HTMLDocument>(this))
1792 return "text/html";
1793
1794 if (DocumentLoader* document_loader = Loader())
1795 return document_loader->MimeType();
1796 return String();
1797 }
1798
SetMimeType(const AtomicString & mime_type)1799 void Document::SetMimeType(const AtomicString& mime_type) {
1800 mime_type_ = mime_type;
1801 }
1802
contentType() const1803 AtomicString Document::contentType() const {
1804 if (!mime_type_.IsEmpty())
1805 return mime_type_;
1806
1807 if (DocumentLoader* document_loader = Loader())
1808 return document_loader->MimeType();
1809
1810 String mime_type = SuggestedMIMEType();
1811 if (!mime_type.IsEmpty())
1812 return AtomicString(mime_type);
1813
1814 return AtomicString("application/xml");
1815 }
1816
ElementFromPoint(double x,double y) const1817 Element* Document::ElementFromPoint(double x, double y) const {
1818 if (!GetLayoutView())
1819 return nullptr;
1820
1821 return TreeScope::ElementFromPoint(x, y);
1822 }
1823
ElementsFromPoint(double x,double y) const1824 HeapVector<Member<Element>> Document::ElementsFromPoint(double x,
1825 double y) const {
1826 if (!GetLayoutView())
1827 return HeapVector<Member<Element>>();
1828 return TreeScope::ElementsFromPoint(x, y);
1829 }
1830
caretRangeFromPoint(int x,int y)1831 Range* Document::caretRangeFromPoint(int x, int y) {
1832 if (!GetLayoutView())
1833 return nullptr;
1834
1835 HitTestResult result = HitTestInDocument(this, x, y);
1836 PositionWithAffinity position_with_affinity = result.GetPosition();
1837 if (position_with_affinity.IsNull())
1838 return nullptr;
1839
1840 Position range_compliant_position =
1841 position_with_affinity.GetPosition().ParentAnchoredEquivalent();
1842 return CreateRangeAdjustedToTreeScope(*this, range_compliant_position);
1843 }
1844
scrollingElement()1845 Element* Document::scrollingElement() {
1846 if (RuntimeEnabledFeatures::ScrollTopLeftInteropEnabled() && InQuirksMode())
1847 UpdateStyleAndLayoutTree();
1848 return ScrollingElementNoLayout();
1849 }
1850
ScrollingElementNoLayout()1851 Element* Document::ScrollingElementNoLayout() {
1852 if (RuntimeEnabledFeatures::ScrollTopLeftInteropEnabled()) {
1853 if (InQuirksMode()) {
1854 DCHECK(!IsActive() ||
1855 lifecycle_.GetState() >= DocumentLifecycle::kStyleClean);
1856 HTMLBodyElement* body = FirstBodyElement();
1857 if (body && body->GetLayoutObject() &&
1858 body->GetLayoutObject()->HasOverflowClip())
1859 return nullptr;
1860
1861 return body;
1862 }
1863
1864 return documentElement();
1865 }
1866
1867 return body();
1868 }
1869
1870 /*
1871 * Performs three operations:
1872 * 1. Convert control characters to spaces
1873 * 2. Trim leading and trailing spaces
1874 * 3. Collapse internal whitespace.
1875 */
1876 template <typename CharacterType>
CanonicalizedTitle(Document * document,const String & title)1877 static inline String CanonicalizedTitle(Document* document,
1878 const String& title) {
1879 unsigned length = title.length();
1880 unsigned builder_index = 0;
1881 const CharacterType* characters = title.GetCharacters<CharacterType>();
1882
1883 StringBuffer<CharacterType> buffer(length);
1884
1885 // Replace control characters with spaces and collapse whitespace.
1886 bool pending_whitespace = false;
1887 for (unsigned i = 0; i < length; ++i) {
1888 UChar32 c = characters[i];
1889 if ((c <= WTF::unicode::kSpaceCharacter &&
1890 c != WTF::unicode::kLineTabulationCharacter) ||
1891 c == WTF::unicode::kDeleteCharacter) {
1892 if (builder_index != 0)
1893 pending_whitespace = true;
1894 } else {
1895 if (pending_whitespace) {
1896 buffer[builder_index++] = ' ';
1897 pending_whitespace = false;
1898 }
1899 buffer[builder_index++] = c;
1900 }
1901 }
1902 buffer.Shrink(builder_index);
1903
1904 return String::Adopt(buffer);
1905 }
1906
UpdateTitle(const String & title)1907 void Document::UpdateTitle(const String& title) {
1908 if (raw_title_ == title)
1909 return;
1910
1911 raw_title_ = title;
1912
1913 String old_title = title_;
1914 if (raw_title_.IsEmpty())
1915 title_ = String();
1916 else if (raw_title_.Is8Bit())
1917 title_ = CanonicalizedTitle<LChar>(this, raw_title_);
1918 else
1919 title_ = CanonicalizedTitle<UChar>(this, raw_title_);
1920
1921 if (!frame_ || old_title == title_)
1922 return;
1923 DispatchDidReceiveTitle();
1924
1925 if (AXObjectCache* cache = ExistingAXObjectCache())
1926 cache->DocumentTitleChanged();
1927 }
1928
DispatchDidReceiveTitle()1929 void Document::DispatchDidReceiveTitle() {
1930 if (GetFrame() && !GetFrame()->Tree().Parent()) {
1931 String shortened_title = title_.Substring(0, mojom::blink::kMaxTitleChars);
1932 GetFrame()->GetLocalFrameHostRemote().UpdateTitle(
1933 shortened_title, mojo_base::mojom::blink::TextDirection::LEFT_TO_RIGHT);
1934 }
1935 frame_->Client()->DispatchDidReceiveTitle(title_);
1936 }
1937
setTitle(const String & title)1938 void Document::setTitle(const String& title) {
1939 // Title set by JavaScript -- overrides any title elements.
1940 Element* element = documentElement();
1941 if (IsA<SVGSVGElement>(element)) {
1942 if (!title_element_) {
1943 title_element_ = MakeGarbageCollected<SVGTitleElement>(*this);
1944 element->InsertBefore(title_element_.Get(), element->firstChild());
1945 }
1946 if (auto* svg_title = DynamicTo<SVGTitleElement>(title_element_.Get()))
1947 svg_title->SetText(title);
1948 } else if (element && element->IsHTMLElement()) {
1949 if (!title_element_) {
1950 HTMLElement* head_element = head();
1951 if (!head_element)
1952 return;
1953 title_element_ = MakeGarbageCollected<HTMLTitleElement>(*this);
1954 head_element->AppendChild(title_element_.Get());
1955 }
1956 if (auto* html_title = DynamicTo<HTMLTitleElement>(title_element_.Get()))
1957 html_title->setText(title);
1958 }
1959 }
1960
SetTitleElement(Element * title_element)1961 void Document::SetTitleElement(Element* title_element) {
1962 // If the root element is an svg element in the SVG namespace, then let value
1963 // be the child text content of the first title element in the SVG namespace
1964 // that is a child of the root element.
1965 if (IsA<SVGSVGElement>(documentElement())) {
1966 title_element_ = Traversal<SVGTitleElement>::FirstChild(*documentElement());
1967 } else {
1968 if (title_element_ && title_element_ != title_element)
1969 title_element_ = Traversal<HTMLTitleElement>::FirstWithin(*this);
1970 else
1971 title_element_ = title_element;
1972
1973 // If the root element isn't an svg element in the SVG namespace and the
1974 // title element is in the SVG namespace, it is ignored.
1975 if (IsA<SVGTitleElement>(*title_element_)) {
1976 title_element_ = nullptr;
1977 return;
1978 }
1979 }
1980
1981 if (auto* html_title = DynamicTo<HTMLTitleElement>(title_element_.Get()))
1982 UpdateTitle(html_title->text());
1983 else if (auto* svg_title = DynamicTo<SVGTitleElement>(title_element_.Get()))
1984 UpdateTitle(svg_title->textContent());
1985 }
1986
RemoveTitle(Element * title_element)1987 void Document::RemoveTitle(Element* title_element) {
1988 if (title_element_ != title_element)
1989 return;
1990
1991 title_element_ = nullptr;
1992
1993 // Update title based on first title element in the document, if one exists.
1994 if (IsA<HTMLDocument>(this) || IsXHTMLDocument()) {
1995 if (HTMLTitleElement* title =
1996 Traversal<HTMLTitleElement>::FirstWithin(*this))
1997 SetTitleElement(title);
1998 } else if (IsSVGDocument()) {
1999 if (SVGTitleElement* title = Traversal<SVGTitleElement>::FirstWithin(*this))
2000 SetTitleElement(title);
2001 }
2002
2003 if (!title_element_)
2004 UpdateTitle(String());
2005 }
2006
dir()2007 const AtomicString& Document::dir() {
2008 Element* root_element = documentElement();
2009 if (auto* html = DynamicTo<HTMLHtmlElement>(root_element))
2010 return html->dir();
2011 return g_null_atom;
2012 }
2013
setDir(const AtomicString & value)2014 void Document::setDir(const AtomicString& value) {
2015 Element* root_element = documentElement();
2016 if (auto* html = DynamicTo<HTMLHtmlElement>(root_element))
2017 html->setDir(value);
2018 }
2019
IsPageVisible() const2020 bool Document::IsPageVisible() const {
2021 // The visibility of the document is inherited from the visibility of the
2022 // page. If there is no page associated with the document, we will assume
2023 // that the page is hidden, as specified by the spec:
2024 // https://w3c.github.io/page-visibility/#hidden-attribute
2025 if (!frame_ || !frame_->GetPage())
2026 return false;
2027 // While visibilitychange is being dispatched during unloading it is
2028 // expected that the visibility is hidden regardless of the page's
2029 // visibility.
2030 if (load_event_progress_ >= kUnloadVisibilityChangeInProgress)
2031 return false;
2032 return frame_->GetPage()->IsPageVisible();
2033 }
2034
IsPrefetchOnly() const2035 bool Document::IsPrefetchOnly() const {
2036 if (!frame_ || !frame_->GetPage())
2037 return false;
2038
2039 PrerendererClient* prerenderer_client =
2040 PrerendererClient::From(frame_->GetPage());
2041 return prerenderer_client && prerenderer_client->IsPrefetchOnly();
2042 }
2043
visibilityState() const2044 String Document::visibilityState() const {
2045 return PageHiddenStateString(hidden());
2046 }
2047
hidden() const2048 bool Document::hidden() const {
2049 return !IsPageVisible();
2050 }
2051
wasDiscarded() const2052 bool Document::wasDiscarded() const {
2053 return was_discarded_;
2054 }
2055
SetWasDiscarded(bool was_discarded)2056 void Document::SetWasDiscarded(bool was_discarded) {
2057 was_discarded_ = was_discarded;
2058 }
2059
DidChangeVisibilityState()2060 void Document::DidChangeVisibilityState() {
2061 DispatchEvent(*Event::CreateBubble(event_type_names::kVisibilitychange));
2062 // Also send out the deprecated version until it can be removed.
2063 DispatchEvent(
2064 *Event::CreateBubble(event_type_names::kWebkitvisibilitychange));
2065
2066 if (IsPageVisible())
2067 Timeline().SetAllCompositorPending();
2068
2069 if (hidden() && canvas_font_cache_)
2070 canvas_font_cache_->PruneAll();
2071
2072 InteractiveDetector* interactive_detector = InteractiveDetector::From(*this);
2073 if (interactive_detector) {
2074 interactive_detector->OnPageHiddenChanged(hidden());
2075 }
2076 }
2077
nodeName() const2078 String Document::nodeName() const {
2079 return "#document";
2080 }
2081
getNodeType() const2082 Node::NodeType Document::getNodeType() const {
2083 return kDocumentNode;
2084 }
2085
GetFormController()2086 FormController& Document::GetFormController() {
2087 if (!form_controller_) {
2088 form_controller_ = MakeGarbageCollected<FormController>(*this);
2089 HistoryItem* history_item = Loader() ? Loader()->GetHistoryItem() : nullptr;
2090 if (history_item)
2091 history_item->SetDocumentState(form_controller_->ControlStates());
2092 }
2093 return *form_controller_;
2094 }
2095
GetDocumentState() const2096 DocumentState* Document::GetDocumentState() const {
2097 if (!form_controller_)
2098 return nullptr;
2099 return form_controller_->ControlStates();
2100 }
2101
SetStateForNewControls(const Vector<String> & state_vector)2102 void Document::SetStateForNewControls(const Vector<String>& state_vector) {
2103 if (!state_vector.size() && !form_controller_)
2104 return;
2105 GetFormController().SetStateForNewControls(state_vector);
2106 }
2107
View() const2108 LocalFrameView* Document::View() const {
2109 return frame_ ? frame_->View() : nullptr;
2110 }
2111
GetPage() const2112 Page* Document::GetPage() const {
2113 return frame_ ? frame_->GetPage() : nullptr;
2114 }
2115
GetFrameOfMasterDocument() const2116 LocalFrame* Document::GetFrameOfMasterDocument() const {
2117 if (frame_)
2118 return frame_;
2119 if (imports_controller_)
2120 return imports_controller_->Master()->GetFrame();
2121 return nullptr;
2122 }
2123
GetSettings() const2124 Settings* Document::GetSettings() const {
2125 return frame_ ? frame_->GetSettings() : nullptr;
2126 }
2127
createRange()2128 Range* Document::createRange() {
2129 return Range::Create(*this);
2130 }
2131
createNodeIterator(Node * root,unsigned what_to_show,V8NodeFilter * filter)2132 NodeIterator* Document::createNodeIterator(Node* root,
2133 unsigned what_to_show,
2134 V8NodeFilter* filter) {
2135 DCHECK(root);
2136 return MakeGarbageCollected<NodeIterator>(root, what_to_show, filter);
2137 }
2138
createTreeWalker(Node * root,unsigned what_to_show,V8NodeFilter * filter)2139 TreeWalker* Document::createTreeWalker(Node* root,
2140 unsigned what_to_show,
2141 V8NodeFilter* filter) {
2142 DCHECK(root);
2143 return MakeGarbageCollected<TreeWalker>(root, what_to_show, filter);
2144 }
2145
NeedsLayoutTreeUpdate() const2146 bool Document::NeedsLayoutTreeUpdate() const {
2147 if (!IsActive() || !View())
2148 return false;
2149 if (NeedsFullLayoutTreeUpdate())
2150 return true;
2151 if (style_engine_->NeedsStyleRecalc())
2152 return true;
2153 if (style_engine_->NeedsStyleInvalidation())
2154 return true;
2155 if (GetLayoutView() && GetLayoutView()->WasNotifiedOfSubtreeChange())
2156 return true;
2157 if (style_engine_->NeedsLayoutTreeRebuild()) {
2158 // TODO(futhark): there a couple of places where call back into the top
2159 // frame while recursively doing a lifecycle update. One of them are for the
2160 // RootScrollerController. These should probably be post layout tasks and
2161 // make this test unnecessary since the layout tree rebuild dirtiness is
2162 // internal to StyleEngine::UpdateStyleAndLayoutTree().
2163 DCHECK(InStyleRecalc());
2164 return true;
2165 }
2166 return false;
2167 }
2168
NeedsFullLayoutTreeUpdate() const2169 bool Document::NeedsFullLayoutTreeUpdate() const {
2170 // This method returns true if we cannot decide which specific elements need
2171 // to have its style or layout tree updated on the next lifecycle update. If
2172 // this method returns false, we typically use that to walk up the ancestor
2173 // chain to decide if we can let getComputedStyle() use the current
2174 // ComputedStyle without doing the lifecycle update (implemented in
2175 // Document::NeedsLayoutTreeUpdateForNodeIncludingDisplayLocked()).
2176 if (!IsActive() || !View())
2177 return false;
2178 if (style_engine_->NeedsFullStyleUpdate())
2179 return true;
2180 if (!use_elements_needing_update_.IsEmpty())
2181 return true;
2182 // We have scheduled an invalidation set on the document node which means any
2183 // element may need a style recalc.
2184 if (NeedsStyleInvalidation())
2185 return true;
2186 if (IsSlotAssignmentOrLegacyDistributionDirty())
2187 return true;
2188 if (document_animations_->NeedsAnimationTimingUpdate())
2189 return true;
2190 return false;
2191 }
2192
ShouldScheduleLayoutTreeUpdate() const2193 bool Document::ShouldScheduleLayoutTreeUpdate() const {
2194 if (!IsActive())
2195 return false;
2196 if (InStyleRecalc())
2197 return false;
2198 // InPreLayout will recalc style itself. There's no reason to schedule another
2199 // recalc.
2200 if (lifecycle_.GetState() == DocumentLifecycle::kInPreLayout)
2201 return false;
2202 if (!ShouldScheduleLayout())
2203 return false;
2204 return true;
2205 }
2206
ScheduleLayoutTreeUpdate()2207 void Document::ScheduleLayoutTreeUpdate() {
2208 DCHECK(!HasPendingVisualUpdate());
2209 DCHECK(ShouldScheduleLayoutTreeUpdate());
2210 DCHECK(NeedsLayoutTreeUpdate());
2211
2212 if (!View()->CanThrottleRendering())
2213 GetPage()->Animator().ScheduleVisualUpdate(GetFrame());
2214
2215 // FrameSelection caches visual selection information, which must be
2216 // invalidated on dirty layout tree.
2217 GetFrame()->Selection().MarkCacheDirty();
2218
2219 lifecycle_.EnsureStateAtMost(DocumentLifecycle::kVisualUpdatePending);
2220
2221 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
2222 "ScheduleStyleRecalculation", TRACE_EVENT_SCOPE_THREAD,
2223 "data",
2224 inspector_recalculate_styles_event::Data(GetFrame()));
2225 ++style_version_;
2226 }
2227
HasPendingForcedStyleRecalc() const2228 bool Document::HasPendingForcedStyleRecalc() const {
2229 return HasPendingVisualUpdate() && !InStyleRecalc() &&
2230 GetStyleChangeType() == kSubtreeStyleChange;
2231 }
2232
UpdateStyleInvalidationIfNeeded()2233 void Document::UpdateStyleInvalidationIfNeeded() {
2234 DCHECK(IsActive());
2235 ScriptForbiddenScope forbid_script;
2236
2237 if (!GetStyleEngine().NeedsStyleInvalidation())
2238 return;
2239 TRACE_EVENT0("blink", "Document::updateStyleInvalidationIfNeeded");
2240 SCOPED_BLINK_UMA_HISTOGRAM_TIMER_HIGHRES("Style.InvalidationTime");
2241 GetStyleEngine().InvalidateStyle();
2242 }
2243
SetupFontBuilder(ComputedStyle & document_style)2244 void Document::SetupFontBuilder(ComputedStyle& document_style) {
2245 FontBuilder font_builder(this);
2246 font_builder.CreateFontForDocument(document_style);
2247 }
2248
2249 #define PROPAGATE_FROM(source, getter, setter, initial) \
2250 PROPAGATE_VALUE(source ? source->getter() : initial, getter, setter);
2251
2252 #define PROPAGATE_VALUE(value, getter, setter) \
2253 if ((new_viewport_style->getter()) != (value)) { \
2254 new_viewport_style->setter(value); \
2255 changed = true; \
2256 }
2257
PropagateScrollSnapStyleToViewport(Document & document,const ComputedStyle * document_element_style,scoped_refptr<ComputedStyle> new_viewport_style)2258 bool PropagateScrollSnapStyleToViewport(
2259 Document& document,
2260 const ComputedStyle* document_element_style,
2261 scoped_refptr<ComputedStyle> new_viewport_style) {
2262 bool changed = false;
2263 // We only propagate the properties related to snap container since viewport
2264 // defining element cannot be a snap area.
2265 PROPAGATE_FROM(document_element_style, GetScrollSnapType, SetScrollSnapType,
2266 cc::ScrollSnapType());
2267 PROPAGATE_FROM(document_element_style, ScrollPaddingTop, SetScrollPaddingTop,
2268 Length());
2269 PROPAGATE_FROM(document_element_style, ScrollPaddingRight,
2270 SetScrollPaddingRight, Length());
2271 PROPAGATE_FROM(document_element_style, ScrollPaddingBottom,
2272 SetScrollPaddingBottom, Length());
2273 PROPAGATE_FROM(document_element_style, ScrollPaddingLeft,
2274 SetScrollPaddingLeft, Length());
2275
2276 if (changed) {
2277 document.GetSnapCoordinator().SnapContainerDidChange(
2278 *document.GetLayoutView());
2279 }
2280
2281 return changed;
2282 }
2283
PropagateStyleToViewport()2284 void Document::PropagateStyleToViewport() {
2285 DCHECK(InStyleRecalc());
2286 HTMLElement* body = this->body();
2287 Element* document_element = this->documentElement();
2288
2289 const ComputedStyle* document_element_style =
2290 document_element && documentElement()->GetLayoutObject()
2291 ? documentElement()->GetComputedStyle()
2292 : nullptr;
2293 const ComputedStyle* body_style =
2294 body && body->GetLayoutObject() ? body->GetComputedStyle() : nullptr;
2295
2296 const ComputedStyle& viewport_style = GetLayoutView()->StyleRef();
2297 scoped_refptr<ComputedStyle> new_viewport_style =
2298 ComputedStyle::Clone(viewport_style);
2299 bool changed = false;
2300 bool update_scrollbar_style = false;
2301
2302 // Writing mode and direction
2303 {
2304 const ComputedStyle* direction_style =
2305 body_style ? body_style : document_element_style;
2306 PROPAGATE_FROM(direction_style, GetWritingMode, SetWritingMode,
2307 WritingMode::kHorizontalTb);
2308 PROPAGATE_FROM(direction_style, Direction, SetDirection,
2309 TextDirection::kLtr);
2310 }
2311
2312 // Background
2313 {
2314 const ComputedStyle* background_style = document_element_style;
2315 // http://www.w3.org/TR/css3-background/#body-background
2316 // <html> root element with no background steals background from its first
2317 // <body> child.
2318 // Also see LayoutBoxModelObject::BackgroundTransfersToView()
2319 if (body_style && IsA<HTMLHtmlElement>(documentElement()) &&
2320 IsA<HTMLBodyElement>(body) && !background_style->HasBackground()) {
2321 background_style = body_style;
2322 }
2323
2324 Color background_color = Color::kTransparent;
2325 FillLayer background_layers(EFillLayerType::kBackground, true);
2326 EImageRendering image_rendering = EImageRendering::kAuto;
2327
2328 if (background_style) {
2329 background_color = background_style->VisitedDependentColor(
2330 GetCSSPropertyBackgroundColor());
2331 background_layers = background_style->BackgroundLayers();
2332 for (auto* current_layer = &background_layers; current_layer;
2333 current_layer = current_layer->Next()) {
2334 // http://www.w3.org/TR/css3-background/#root-background
2335 // The root element background always have painting area of the whole
2336 // canvas.
2337 current_layer->SetClip(EFillBox::kBorder);
2338
2339 // The root element doesn't scroll. It always propagates its layout
2340 // overflow to the viewport. Positioning background against either box
2341 // is equivalent to positioning against the scrolled box of the
2342 // viewport.
2343 if (current_layer->Attachment() == EFillAttachment::kScroll)
2344 current_layer->SetAttachment(EFillAttachment::kLocal);
2345 }
2346 image_rendering = background_style->ImageRendering();
2347 }
2348
2349 if (viewport_style.VisitedDependentColor(GetCSSPropertyBackgroundColor()) !=
2350 background_color ||
2351 viewport_style.BackgroundLayers() != background_layers ||
2352 viewport_style.ImageRendering() != image_rendering) {
2353 changed = true;
2354 new_viewport_style->SetBackgroundColor(background_color);
2355 new_viewport_style->AccessBackgroundLayers() = background_layers;
2356 new_viewport_style->SetImageRendering(image_rendering);
2357 }
2358 }
2359
2360 // Overflow
2361 {
2362 const ComputedStyle* overflow_style = nullptr;
2363 if (Element* viewport_element = ViewportDefiningElement()) {
2364 if (viewport_element == body) {
2365 overflow_style = body_style;
2366 } else {
2367 DCHECK_EQ(viewport_element, documentElement());
2368 overflow_style = document_element_style;
2369
2370 // The body element has its own scrolling box, independent from the
2371 // viewport. This is a bit of a weird edge case in the CSS spec that we
2372 // might want to try to eliminate some day (eg. for ScrollTopLeftInterop
2373 // - see http://crbug.com/157855).
2374 if (body_style && !body_style->IsOverflowVisible()) {
2375 UseCounter::Count(*this,
2376 WebFeature::kBodyScrollsInAdditionToViewport);
2377 }
2378 }
2379 }
2380
2381 // TODO(954423, 952711): overscroll-behavior (and most likely
2382 // overflow-anchor) should be propagated from the document element and not
2383 // the viewport defining element.
2384 PROPAGATE_FROM(overflow_style, OverscrollBehaviorX, SetOverscrollBehaviorX,
2385 EOverscrollBehavior::kAuto);
2386 PROPAGATE_FROM(overflow_style, OverscrollBehaviorY, SetOverscrollBehaviorY,
2387 EOverscrollBehavior::kAuto);
2388
2389 // Counts any time scroll snapping and scroll padding break if we change its
2390 // viewport propagation logic. Scroll snapping only breaks if body has
2391 // non-none snap type that is different from the document one.
2392 // TODO(952711): Remove once propagation logic change is complete.
2393 if (document_element_style && body_style) {
2394 bool snap_type_is_different =
2395 !body_style->GetScrollSnapType().is_none &&
2396 (body_style->GetScrollSnapType() !=
2397 document_element_style->GetScrollSnapType());
2398 bool scroll_padding_is_different =
2399 body_style->ScrollPaddingTop() !=
2400 document_element_style->ScrollPaddingTop() ||
2401 body_style->ScrollPaddingBottom() !=
2402 document_element_style->ScrollPaddingBottom() ||
2403 body_style->ScrollPaddingLeft() !=
2404 document_element_style->ScrollPaddingLeft() ||
2405 body_style->ScrollPaddingRight() !=
2406 document_element_style->ScrollPaddingRight();
2407
2408 if (snap_type_is_different) {
2409 UseCounter::Count(*this, WebFeature::kScrollSnapOnViewportBreaks);
2410 }
2411 if (scroll_padding_is_different) {
2412 UseCounter::Count(*this, WebFeature::kScrollPaddingOnViewportBreaks);
2413 }
2414 }
2415
2416 EOverflow overflow_x = EOverflow::kAuto;
2417 EOverflow overflow_y = EOverflow::kAuto;
2418 EOverflowAnchor overflow_anchor = EOverflowAnchor::kAuto;
2419
2420 if (overflow_style) {
2421 overflow_x = overflow_style->OverflowX();
2422 overflow_y = overflow_style->OverflowY();
2423 overflow_anchor = overflow_style->OverflowAnchor();
2424 // Visible overflow on the viewport is meaningless, and the spec says to
2425 // treat it as 'auto':
2426 if (overflow_x == EOverflow::kVisible)
2427 overflow_x = EOverflow::kAuto;
2428 if (overflow_y == EOverflow::kVisible)
2429 overflow_y = EOverflow::kAuto;
2430 if (overflow_anchor == EOverflowAnchor::kVisible)
2431 overflow_anchor = EOverflowAnchor::kAuto;
2432
2433 if (IsInMainFrame()) {
2434 using OverscrollBehaviorType =
2435 cc::OverscrollBehavior::OverscrollBehaviorType;
2436 GetPage()->GetChromeClient().SetOverscrollBehavior(
2437 *GetFrame(),
2438 cc::OverscrollBehavior(static_cast<OverscrollBehaviorType>(
2439 overflow_style->OverscrollBehaviorX()),
2440 static_cast<OverscrollBehaviorType>(
2441 overflow_style->OverscrollBehaviorY())));
2442 }
2443
2444 if (overflow_style->HasPseudoElementStyle(kPseudoIdScrollbar))
2445 update_scrollbar_style = true;
2446 }
2447
2448 PROPAGATE_VALUE(overflow_x, OverflowX, SetOverflowX)
2449 PROPAGATE_VALUE(overflow_y, OverflowY, SetOverflowY)
2450 PROPAGATE_VALUE(overflow_anchor, OverflowAnchor, SetOverflowAnchor);
2451 }
2452
2453 // Misc
2454 {
2455 PROPAGATE_FROM(document_element_style, GetEffectiveTouchAction,
2456 SetEffectiveTouchAction, TouchAction::kAuto);
2457 PROPAGATE_FROM(document_element_style, GetScrollBehavior, SetScrollBehavior,
2458 mojom::blink::ScrollBehavior::kAuto);
2459 PROPAGATE_FROM(document_element_style, DarkColorScheme, SetDarkColorScheme,
2460 false);
2461 }
2462
2463 changed |= PropagateScrollSnapStyleToViewport(*this, document_element_style,
2464 new_viewport_style);
2465
2466 if (changed) {
2467 new_viewport_style->UpdateFontOrientation();
2468 GetLayoutView()->SetStyle(new_viewport_style);
2469 SetupFontBuilder(*new_viewport_style);
2470 }
2471
2472 if (changed || update_scrollbar_style) {
2473 if (PaintLayerScrollableArea* scrollable_area =
2474 GetLayoutView()->GetScrollableArea()) {
2475 if (scrollable_area->HorizontalScrollbar() &&
2476 scrollable_area->HorizontalScrollbar()->IsCustomScrollbar())
2477 scrollable_area->HorizontalScrollbar()->StyleChanged();
2478 if (scrollable_area->VerticalScrollbar() &&
2479 scrollable_area->VerticalScrollbar()->IsCustomScrollbar())
2480 scrollable_area->VerticalScrollbar()->StyleChanged();
2481 }
2482 }
2483 }
2484 #undef PROPAGATE_VALUE
2485 #undef PROPAGATE_FROM
2486
2487 #if DCHECK_IS_ON()
AssertNodeClean(const Node & node)2488 static void AssertNodeClean(const Node& node) {
2489 DCHECK(!node.NeedsStyleRecalc());
2490 DCHECK(!node.ChildNeedsStyleRecalc());
2491 DCHECK(!node.NeedsReattachLayoutTree());
2492 DCHECK(!node.ChildNeedsReattachLayoutTree());
2493 DCHECK(!node.ChildNeedsDistributionRecalc());
2494 DCHECK(!node.NeedsStyleInvalidation());
2495 DCHECK(!node.ChildNeedsStyleInvalidation());
2496 DCHECK(!node.GetForceReattachLayoutTree());
2497 }
2498
AssertLayoutTreeUpdatedForPseudoElements(const Element & element)2499 static void AssertLayoutTreeUpdatedForPseudoElements(const Element& element) {
2500 WTF::Vector<PseudoId> pseudo_ids = {kPseudoIdFirstLetter, kPseudoIdBefore,
2501 kPseudoIdAfter, kPseudoIdMarker,
2502 kPseudoIdBackdrop};
2503 for (auto pseudo_id : pseudo_ids) {
2504 if (auto* pseudo_element = element.GetPseudoElement(pseudo_id))
2505 AssertNodeClean(*pseudo_element);
2506 }
2507 }
2508
AssertLayoutTreeUpdated(Node & root)2509 static void AssertLayoutTreeUpdated(Node& root) {
2510 Node* node = &root;
2511 while (node) {
2512 if (auto* element = DynamicTo<Element>(node)) {
2513 if (RuntimeEnabledFeatures::CSSSubtreeVisibilityEnabled() &&
2514 element->StyleRecalcBlockedByDisplayLock(
2515 DisplayLockLifecycleTarget::kChildren)) {
2516 node = FlatTreeTraversal::NextSkippingChildren(*node);
2517 continue;
2518 }
2519 // Check pseudo elements.
2520 AssertLayoutTreeUpdatedForPseudoElements(*element);
2521 }
2522
2523 AssertNodeClean(*node);
2524
2525 // Make sure there is no node which has a LayoutObject, but doesn't have a
2526 // parent in a flat tree. If there is such a node, we forgot to detach the
2527 // node. DocumentNode is only an exception.
2528 DCHECK((node->IsDocumentNode() || !node->GetLayoutObject() ||
2529 FlatTreeTraversal::Parent(*node)))
2530 << *node;
2531
2532 node = FlatTreeTraversal::Next(*node);
2533 }
2534 }
2535 #endif
2536
UpdateStyleAndLayoutTree()2537 void Document::UpdateStyleAndLayoutTree() {
2538 DCHECK(IsMainThread());
2539 if (Lifecycle().LifecyclePostponed())
2540 return;
2541
2542 HTMLFrameOwnerElement::PluginDisposeSuspendScope suspend_plugin_dispose;
2543 ScriptForbiddenScope forbid_script;
2544
2545 if (HTMLFrameOwnerElement* owner = LocalOwner()) {
2546 owner->GetDocument().UpdateStyleAndLayoutTree();
2547 }
2548
2549 if (!View() || !IsActive())
2550 return;
2551
2552 if (View()->ShouldThrottleRendering())
2553 return;
2554
2555 // RecalcSlotAssignments should be done before checking
2556 // NeedsLayoutTreeUpdate().
2557 GetSlotAssignmentEngine().RecalcSlotAssignments();
2558
2559 // We can call FlatTreeTraversal::AssertFlatTreeNodeDataUpdated just after
2560 // calling RecalcSlotAssignments(), however, it would be better to call it at
2561 // least after InStyleRecalc() check below in order to avoid superfluous
2562 // check, which would be the cause of web tests timeout when dcheck is on.
2563
2564 SlotAssignmentRecalcForbiddenScope forbid_slot_recalc(*this);
2565
2566 if (!NeedsLayoutTreeUpdate()) {
2567 if (Lifecycle().GetState() < DocumentLifecycle::kStyleClean) {
2568 // needsLayoutTreeUpdate may change to false without any actual layout
2569 // tree update. For example, needsAnimationTimingUpdate may change to
2570 // false when time elapses. Advance lifecycle to StyleClean because style
2571 // is actually clean now.
2572 Lifecycle().AdvanceTo(DocumentLifecycle::kInStyleRecalc);
2573 Lifecycle().AdvanceTo(DocumentLifecycle::kStyleClean);
2574 }
2575 return;
2576 }
2577
2578 if (InStyleRecalc())
2579 return;
2580
2581 #if DCHECK_IS_ON()
2582 int assigned_nodes_in_slot_count = 0;
2583 int nodes_which_have_assigned_slot_count = 0;
2584 FlatTreeTraversal::AssertFlatTreeNodeDataUpdated(
2585 *this, assigned_nodes_in_slot_count,
2586 nodes_which_have_assigned_slot_count);
2587 DCHECK_EQ(assigned_nodes_in_slot_count, nodes_which_have_assigned_slot_count);
2588 #endif
2589
2590 // Entering here from inside layout, paint etc. would be catastrophic since
2591 // recalcStyle can tear down the layout tree or (unfortunately) run
2592 // script. Kill the whole layoutObject if someone managed to get into here in
2593 // states not allowing tree mutations.
2594 CHECK(Lifecycle().StateAllowsTreeMutations());
2595
2596 TRACE_EVENT_BEGIN1("blink,devtools.timeline", "UpdateLayoutTree", "beginData",
2597 inspector_recalculate_styles_event::Data(GetFrame()));
2598
2599 unsigned start_element_count = GetStyleEngine().StyleForElementCount();
2600
2601 probe::RecalculateStyle recalculate_style_scope(this);
2602
2603 document_animations_->UpdateAnimationTimingIfNeeded();
2604 EvaluateMediaQueryListIfNeeded();
2605 UpdateUseShadowTreesIfNeeded();
2606
2607 UpdateDistributionForLegacyDistributedNodes();
2608
2609 UpdateActiveStyle();
2610 InvalidateStyleAndLayoutForFontUpdates();
2611 UpdateStyleInvalidationIfNeeded();
2612 UpdateStyle();
2613
2614 NotifyLayoutTreeOfSubtreeChanges();
2615
2616 if (focused_element_ && !focused_element_->IsFocusable())
2617 ClearFocusedElementSoon();
2618 GetLayoutView()->ClearHitTestCache();
2619
2620 DCHECK(!document_animations_->NeedsAnimationTimingUpdate());
2621
2622 unsigned element_count =
2623 GetStyleEngine().StyleForElementCount() - start_element_count;
2624
2625 TRACE_EVENT_END1("blink,devtools.timeline", "UpdateLayoutTree",
2626 "elementCount", element_count);
2627
2628 #if DCHECK_IS_ON()
2629 AssertLayoutTreeUpdated(*this);
2630 #endif
2631 }
2632
UpdateActiveStyle()2633 void Document::UpdateActiveStyle() {
2634 DCHECK(IsActive());
2635 DCHECK(IsMainThread());
2636 TRACE_EVENT0("blink", "Document::updateActiveStyle");
2637 GetStyleEngine().UpdateActiveStyle();
2638 }
2639
InvalidateStyleAndLayoutForFontUpdates()2640 void Document::InvalidateStyleAndLayoutForFontUpdates() {
2641 DCHECK(IsActive());
2642 DCHECK(IsMainThread());
2643 GetStyleEngine().InvalidateStyleAndLayoutForFontUpdates();
2644 }
2645
UpdateStyle()2646 void Document::UpdateStyle() {
2647 DCHECK(!View()->ShouldThrottleRendering());
2648 TRACE_EVENT_BEGIN0("blink,blink_style", "Document::updateStyle");
2649 RUNTIME_CALL_TIMER_SCOPE(V8PerIsolateData::MainThreadIsolate(),
2650 RuntimeCallStats::CounterId::kUpdateStyle);
2651
2652 unsigned initial_element_count = GetStyleEngine().StyleForElementCount();
2653
2654 lifecycle_.AdvanceTo(DocumentLifecycle::kInStyleRecalc);
2655
2656 // SetNeedsStyleRecalc should only happen on Element and Text nodes.
2657 DCHECK(!NeedsStyleRecalc());
2658
2659 StyleResolver& resolver = EnsureStyleResolver();
2660 bool should_record_stats;
2661 TRACE_EVENT_CATEGORY_GROUP_ENABLED("blink,blink_style", &should_record_stats);
2662 GetStyleEngine().SetStatsEnabled(should_record_stats);
2663
2664 GetStyleEngine().UpdateStyleAndLayoutTree();
2665
2666 ClearChildNeedsStyleRecalc();
2667
2668 PropagateStyleToViewport();
2669
2670 View()->UpdateCountersAfterStyleChange();
2671 GetLayoutView()->RecalcLayoutOverflow();
2672
2673 DCHECK(!NeedsStyleRecalc());
2674 DCHECK(!ChildNeedsStyleRecalc());
2675 DCHECK(!NeedsReattachLayoutTree());
2676 DCHECK(!ChildNeedsReattachLayoutTree());
2677 DCHECK(InStyleRecalc());
2678 DCHECK_EQ(GetStyleResolver(), &resolver);
2679 lifecycle_.AdvanceTo(DocumentLifecycle::kStyleClean);
2680 if (should_record_stats) {
2681 TRACE_EVENT_END2(
2682 "blink,blink_style", "Document::updateStyle", "resolverAccessCount",
2683 GetStyleEngine().StyleForElementCount() - initial_element_count,
2684 "counters", GetStyleEngine().Stats()->ToTracedValue());
2685 } else {
2686 TRACE_EVENT_END1(
2687 "blink,blink_style", "Document::updateStyle", "resolverAccessCount",
2688 GetStyleEngine().StyleForElementCount() - initial_element_count);
2689 }
2690 }
2691
NotifyLayoutTreeOfSubtreeChanges()2692 void Document::NotifyLayoutTreeOfSubtreeChanges() {
2693 if (!GetLayoutView()->WasNotifiedOfSubtreeChange())
2694 return;
2695
2696 lifecycle_.AdvanceTo(DocumentLifecycle::kInLayoutSubtreeChange);
2697
2698 GetLayoutView()->HandleSubtreeModifications();
2699 DCHECK(!GetLayoutView()->WasNotifiedOfSubtreeChange());
2700
2701 lifecycle_.AdvanceTo(DocumentLifecycle::kLayoutSubtreeChangeClean);
2702 }
2703
NeedsLayoutTreeUpdateForNode(const Node & node,bool ignore_adjacent_style) const2704 bool Document::NeedsLayoutTreeUpdateForNode(const Node& node,
2705 bool ignore_adjacent_style) const {
2706 // TODO(rakina): Switch some callers that may need to call
2707 // NeedsLayoutTreeUpdateForNodeIncludingDisplayLocked instead of this.
2708 if (DisplayLockUtilities::NearestLockedExclusiveAncestor(node)) {
2709 // |node| is in a locked-subtree, so we don't need to update it.
2710 return false;
2711 }
2712 return NeedsLayoutTreeUpdateForNodeIncludingDisplayLocked(
2713 node, ignore_adjacent_style);
2714 }
2715
NeedsLayoutTreeUpdateForNodeIncludingDisplayLocked(const Node & node,bool ignore_adjacent_style) const2716 bool Document::NeedsLayoutTreeUpdateForNodeIncludingDisplayLocked(
2717 const Node& node,
2718 bool ignore_adjacent_style) const {
2719 if (!node.CanParticipateInFlatTree())
2720 return false;
2721 if (locked_display_lock_count_ == 0 && !NeedsLayoutTreeUpdate())
2722 return false;
2723 if (!node.isConnected())
2724 return false;
2725
2726 if (NeedsFullLayoutTreeUpdate() || node.NeedsStyleRecalc() ||
2727 node.NeedsStyleInvalidation())
2728 return true;
2729 for (const ContainerNode* ancestor = LayoutTreeBuilderTraversal::Parent(node);
2730 ancestor; ancestor = LayoutTreeBuilderTraversal::Parent(*ancestor)) {
2731 if (ShadowRoot* root = ancestor->GetShadowRoot()) {
2732 if (root->NeedsStyleRecalc() || root->NeedsStyleInvalidation() ||
2733 root->NeedsAdjacentStyleRecalc()) {
2734 return true;
2735 }
2736 }
2737 if (ancestor->NeedsStyleRecalc() || ancestor->NeedsStyleInvalidation() ||
2738 (ancestor->NeedsAdjacentStyleRecalc() && !ignore_adjacent_style)) {
2739 return true;
2740 }
2741 auto* element = DynamicTo<Element>(ancestor);
2742 if (!element)
2743 continue;
2744 if (auto* context = element->GetDisplayLockContext()) {
2745 // Even if the ancestor is style-clean, we might've previously
2746 // blocked a style traversal going to the ancestor or its descendants.
2747 if (context->StyleTraversalWasBlocked()) {
2748 DCHECK(context->IsLocked());
2749 return true;
2750 }
2751 }
2752 }
2753 return false;
2754 }
2755
UpdateStyleAndLayoutTreeForNode(const Node * node)2756 void Document::UpdateStyleAndLayoutTreeForNode(const Node* node) {
2757 DCHECK(node);
2758 if (!node->InActiveDocument()) {
2759 // If |node| is not in the active document, we can't update its style or
2760 // layout tree.
2761 DCHECK_EQ(node->ownerDocument(), this);
2762 return;
2763 }
2764 DCHECK(!InStyleRecalc())
2765 << "UpdateStyleAndLayoutTreeForNode called from within style recalc";
2766 if (!NeedsLayoutTreeUpdateForNodeIncludingDisplayLocked(*node))
2767 return;
2768
2769 DisplayLockUtilities::ScopedChainForcedUpdate scoped_update_forced(node);
2770 UpdateStyleAndLayoutTree();
2771 }
2772
UpdateStyleAndLayoutTreeForSubtree(const Node * node)2773 void Document::UpdateStyleAndLayoutTreeForSubtree(const Node* node) {
2774 DCHECK(node);
2775 if (!node->InActiveDocument()) {
2776 DCHECK_EQ(node->ownerDocument(), this);
2777 return;
2778 }
2779 DCHECK(!InStyleRecalc())
2780 << "UpdateStyleAndLayoutTreeForSubtree called from within style recalc";
2781
2782 if (NeedsLayoutTreeUpdateForNodeIncludingDisplayLocked(*node) ||
2783 node->ChildNeedsStyleRecalc() || node->ChildNeedsStyleInvalidation()) {
2784 DisplayLockUtilities::ScopedChainForcedUpdate scoped_update_forced(node);
2785 UpdateStyleAndLayoutTree();
2786 }
2787 }
2788
UpdateStyleAndLayoutForNode(const Node * node,DocumentUpdateReason reason)2789 void Document::UpdateStyleAndLayoutForNode(const Node* node,
2790 DocumentUpdateReason reason) {
2791 DCHECK(node);
2792 if (!node->InActiveDocument())
2793 return;
2794
2795 DisplayLockUtilities::ScopedChainForcedUpdate scoped_update_forced(node);
2796 UpdateStyleAndLayout(reason);
2797 }
2798
ApplyScrollRestorationLogic()2799 void Document::ApplyScrollRestorationLogic() {
2800 // This function in not re-entrant. However, the places that invoke this are
2801 // re-entrant. Specifically, UpdateStyleAndLayout() calls this, which in turn
2802 // can do a find-in-page for the scroll-to-text feature, which can cause
2803 // UpdateStyleAndLayout to happen with subtree-visibility, which gets back here
2804 // and recurses indefinitely. As a result, we ensure to early out from this
2805 // function if are currently in process of restoring scroll.
2806 if (applying_scroll_restoration_logic_)
2807 return;
2808 base::AutoReset<bool> applying_scroll_restoration_logic_scope(
2809 &applying_scroll_restoration_logic_, true);
2810
2811 // If we're restoring a scroll position from history, that takes precedence
2812 // over scrolling to the anchor in the URL.
2813 View()->InvokeFragmentAnchor();
2814
2815 auto& frame_loader = GetFrame()->Loader();
2816 auto* document_loader = frame_loader.GetDocumentLoader();
2817 if (!document_loader)
2818 return;
2819 if (frame_->IsLoading() &&
2820 !FrameLoader::NeedsHistoryItemRestore(document_loader->LoadType()))
2821 return;
2822
2823 auto* history_item = document_loader->GetHistoryItem();
2824
2825 if (!history_item || !history_item->GetViewState())
2826 return;
2827
2828 if (!View()->GetScrollableArea()->HasPendingHistoryRestoreScrollOffset())
2829 return;
2830
2831 bool should_restore_scroll =
2832 history_item->ScrollRestorationType() != kScrollRestorationManual;
2833 auto& scroll_offset = history_item->GetViewState()->scroll_offset_;
2834
2835 // This tries to balance:
2836 // 1. restoring as soon as possible.
2837 // 2. not overriding user scroll (TODO(majidvp): also respect user scale).
2838 // 3. detecting clamping to avoid repeatedly popping the scroll position
2839 // down
2840 // as the page height increases.
2841 // 4. ignoring clamp detection if scroll state is not being restored, if
2842 // load
2843 // is complete, or if the navigation is same-document (as the new page
2844 // may be smaller than the previous page).
2845 bool can_restore_without_clamping =
2846 View()->LayoutViewport()->ClampScrollOffset(scroll_offset) ==
2847 scroll_offset;
2848
2849 bool can_restore_without_annoying_user =
2850 !document_loader->GetInitialScrollState().was_scrolled_by_user &&
2851 (can_restore_without_clamping || !frame_->IsLoading() ||
2852 !should_restore_scroll);
2853 if (!can_restore_without_annoying_user)
2854 return;
2855
2856 // Apply scroll restoration to the LayoutView's scroller. Note that we do
2857 // *not* apply it to the RootFrameViewport's LayoutViewport, because that
2858 // may be for child frame's implicit root scroller, which is not the right
2859 // one to apply to because scroll restoration does not affect implicit root
2860 // scrollers.
2861 auto* layout_scroller = View()->LayoutViewport();
2862 layout_scroller->ApplyPendingHistoryRestoreScrollOffset();
2863
2864 // Also apply restoration to the visual viewport of the root frame, if needed.
2865 auto* root_frame_scroller = View()->GetScrollableArea();
2866 if (root_frame_scroller != layout_scroller)
2867 root_frame_scroller->ApplyPendingHistoryRestoreScrollOffset();
2868
2869 document_loader->GetInitialScrollState().did_restore_from_history = true;
2870 }
2871
MarkHasFindInPageRequest()2872 void Document::MarkHasFindInPageRequest() {
2873 // Note that although find-in-page requests happen in non-main frames, we only
2874 // record the main frame results (per UKM policy). Additionally, we only
2875 // record the event once.
2876 if (had_find_in_page_request_ || !IsInMainFrame())
2877 return;
2878
2879 auto* recorder = UkmRecorder();
2880 DCHECK(recorder);
2881 DCHECK(UkmSourceID() != ukm::kInvalidSourceId);
2882 ukm::builders::Blink_FindInPage(UkmSourceID())
2883 .SetDidSearch(true)
2884 .Record(recorder);
2885 had_find_in_page_request_ = true;
2886 }
2887
MarkHasFindInPageSubtreeVisibilityActiveMatch()2888 void Document::MarkHasFindInPageSubtreeVisibilityActiveMatch() {
2889 // Note that although find-in-page in subtree-visibility requests happen in
2890 // non-main frames, we only record the main frame results (per UKM policy).
2891 // Additionally, we only record the event once.
2892 if (had_find_in_page_render_subtree_active_match_ || !IsInMainFrame())
2893 return;
2894
2895 auto* recorder = UkmRecorder();
2896 DCHECK(recorder);
2897 DCHECK(UkmSourceID() != ukm::kInvalidSourceId);
2898 // TODO(vmpstr): Rename UKM values if possible.
2899 ukm::builders::Blink_FindInPage(UkmSourceID())
2900 .SetDidHaveRenderSubtreeMatch(true)
2901 .Record(recorder);
2902 had_find_in_page_render_subtree_active_match_ = true;
2903 }
2904
UpdateStyleAndLayout(DocumentUpdateReason reason)2905 void Document::UpdateStyleAndLayout(DocumentUpdateReason reason) {
2906 DCHECK(IsMainThread());
2907 LocalFrameView* frame_view = View();
2908
2909 if (reason != DocumentUpdateReason::kBeginMainFrame && frame_view)
2910 frame_view->WillStartForcedLayout();
2911
2912 HTMLFrameOwnerElement::PluginDisposeSuspendScope suspend_plugin_dispose;
2913 ScriptForbiddenScope forbid_script;
2914
2915 DCHECK(!frame_view || !frame_view->IsInPerformLayout())
2916 << "View layout should not be re-entrant";
2917
2918 if (HTMLFrameOwnerElement* owner = LocalOwner())
2919 owner->GetDocument().UpdateStyleAndLayout(reason);
2920
2921 UpdateStyleAndLayoutTree();
2922
2923 if (!IsActive()) {
2924 if (reason != DocumentUpdateReason::kBeginMainFrame && frame_view)
2925 frame_view->DidFinishForcedLayout(reason);
2926 return;
2927 }
2928
2929 if (frame_view && frame_view->NeedsLayout())
2930 frame_view->UpdateLayout();
2931
2932 if (Lifecycle().GetState() < DocumentLifecycle::kLayoutClean)
2933 Lifecycle().AdvanceTo(DocumentLifecycle::kLayoutClean);
2934
2935 ApplyScrollRestorationLogic();
2936
2937 if (LocalFrameView* frame_view_anchored = View())
2938 frame_view_anchored->PerformScrollAnchoringAdjustments();
2939 PerformScrollSnappingTasks();
2940
2941 if (reason != DocumentUpdateReason::kBeginMainFrame && frame_view)
2942 frame_view->DidFinishForcedLayout(reason);
2943
2944 if (update_focus_appearance_after_layout_)
2945 UpdateFocusAppearance();
2946 }
2947
LayoutUpdated()2948 void Document::LayoutUpdated() {
2949 DCHECK(GetFrame());
2950 DCHECK(View());
2951
2952 // Plugins can run script inside layout which can detach the page.
2953 // TODO(dcheng): Does it make sense to do any of this work if detached?
2954 if (GetFrame()) {
2955 if (GetFrame()->IsMainFrame())
2956 GetFrame()->GetPage()->GetChromeClient().MainFrameLayoutUpdated();
2957
2958 // We do attach here, during lifecycle update, because until then we
2959 // don't have a good place that has access to its local root's FrameWidget.
2960 // TODO(dcheng): If we create FrameWidget before Frame then we could move
2961 // this to Document::Initialize().
2962 AttachCompositorTimeline(Timeline().CompositorTimeline());
2963 }
2964
2965 Markers().InvalidateRectsForAllTextMatchMarkers();
2966 }
2967
AttachCompositorTimeline(CompositorAnimationTimeline * timeline) const2968 void Document::AttachCompositorTimeline(
2969 CompositorAnimationTimeline* timeline) const {
2970 if (!Platform::Current()->IsThreadedAnimationEnabled() ||
2971 !GetSettings()->GetAcceleratedCompositingEnabled())
2972 return;
2973
2974 if (timeline->GetAnimationTimeline()->IsScrollTimeline() &&
2975 timeline->GetAnimationTimeline()->animation_host())
2976 return;
2977
2978 GetPage()->GetChromeClient().AttachCompositorAnimationTimeline(timeline,
2979 GetFrame());
2980 }
2981
DetachCompositorTimeline(CompositorAnimationTimeline * timeline) const2982 void Document::DetachCompositorTimeline(
2983 CompositorAnimationTimeline* timeline) const {
2984 if (!Platform::Current()->IsThreadedAnimationEnabled() ||
2985 !GetSettings()->GetAcceleratedCompositingEnabled())
2986 return;
2987
2988 // This requires detaching all animations from timeline first before detaching
2989 // timeline.
2990 if (timeline->GetAnimationTimeline()->IsScrollTimeline() &&
2991 timeline->GetAnimationTimeline()->HasAnimation())
2992 return;
2993
2994 GetPage()->GetChromeClient().DetachCompositorAnimationTimeline(timeline,
2995 GetFrame());
2996 }
2997
ClearFocusedElementSoon()2998 void Document::ClearFocusedElementSoon() {
2999 if (!clear_focused_element_timer_.IsActive())
3000 clear_focused_element_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
3001 }
3002
ClearFocusedElementTimerFired(TimerBase *)3003 void Document::ClearFocusedElementTimerFired(TimerBase*) {
3004 UpdateStyleAndLayoutTree();
3005
3006 if (focused_element_ && !focused_element_->IsFocusable())
3007 focused_element_->blur();
3008 }
3009
StyleForPage(int page_index)3010 scoped_refptr<const ComputedStyle> Document::StyleForPage(int page_index) {
3011 UpdateDistributionForUnknownReasons();
3012 return EnsureStyleResolver().StyleForPage(page_index);
3013 }
3014
EnsurePaintLocationDataValidForNode(const Node * node,DocumentUpdateReason reason)3015 void Document::EnsurePaintLocationDataValidForNode(
3016 const Node* node,
3017 DocumentUpdateReason reason) {
3018 DCHECK(node);
3019 if (!node->InActiveDocument())
3020 return;
3021
3022 DisplayLockUtilities::ScopedChainForcedUpdate scoped_update_forced(node);
3023
3024 // For all nodes we must have up-to-date style and have performed layout to do
3025 // any location-based calculation.
3026 UpdateStyleAndLayout(reason);
3027
3028 // The location of elements that are position: sticky is not known until
3029 // compositing inputs are cleaned. Therefore, for any elements that are either
3030 // sticky or are in a sticky sub-tree (e.g. are affected by a sticky element),
3031 // we need to also clean compositing inputs.
3032 if (View() && node->GetLayoutObject() &&
3033 node->GetLayoutObject()->StyleRef().SubtreeIsSticky()) {
3034 bool success = false;
3035 if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
3036 // In CAP, compositing inputs are cleaned as part of PrePaint.
3037 success = View()->UpdateAllLifecyclePhasesExceptPaint(reason);
3038 } else {
3039 success = View()->UpdateLifecycleToCompositingInputsClean(reason);
3040 }
3041 // The lifecycle update should always succeed, because forced lifecycles
3042 // from script are never throttled.
3043 DCHECK(success);
3044 }
3045 }
3046
IsPageBoxVisible(int page_index)3047 bool Document::IsPageBoxVisible(int page_index) {
3048 return StyleForPage(page_index)->Visibility() !=
3049 EVisibility::kHidden; // display property doesn't apply to @page.
3050 }
3051
PageSizeAndMarginsInPixels(int page_index,DoubleSize & page_size,int & margin_top,int & margin_right,int & margin_bottom,int & margin_left)3052 void Document::PageSizeAndMarginsInPixels(int page_index,
3053 DoubleSize& page_size,
3054 int& margin_top,
3055 int& margin_right,
3056 int& margin_bottom,
3057 int& margin_left) {
3058 scoped_refptr<const ComputedStyle> style = StyleForPage(page_index);
3059
3060 double width = page_size.Width();
3061 double height = page_size.Height();
3062 switch (style->GetPageSizeType()) {
3063 case PageSizeType::kAuto:
3064 break;
3065 case PageSizeType::kLandscape:
3066 if (width < height)
3067 std::swap(width, height);
3068 break;
3069 case PageSizeType::kPortrait:
3070 if (width > height)
3071 std::swap(width, height);
3072 break;
3073 case PageSizeType::kFixed: {
3074 FloatSize size = style->PageSize();
3075 width = size.Width();
3076 height = size.Height();
3077 break;
3078 }
3079 default:
3080 NOTREACHED();
3081 }
3082 page_size = DoubleSize(width, height);
3083
3084 // The percentage is calculated with respect to the width even for margin top
3085 // and bottom.
3086 // http://www.w3.org/TR/CSS2/box.html#margin-properties
3087 margin_top = style->MarginTop().IsAuto()
3088 ? margin_top
3089 : IntValueForLength(style->MarginTop(), width);
3090 margin_right = style->MarginRight().IsAuto()
3091 ? margin_right
3092 : IntValueForLength(style->MarginRight(), width);
3093 margin_bottom = style->MarginBottom().IsAuto()
3094 ? margin_bottom
3095 : IntValueForLength(style->MarginBottom(), width);
3096 margin_left = style->MarginLeft().IsAuto()
3097 ? margin_left
3098 : IntValueForLength(style->MarginLeft(), width);
3099 }
3100
SetIsViewSource(bool is_view_source)3101 void Document::SetIsViewSource(bool is_view_source) {
3102 is_view_source_ = is_view_source;
3103 if (!is_view_source_)
3104 return;
3105 }
3106
SetIsXrOverlay(bool val,Element * overlay_element)3107 void Document::SetIsXrOverlay(bool val, Element* overlay_element) {
3108 if (!documentElement())
3109 return;
3110
3111 if (val == is_xr_overlay_)
3112 return;
3113
3114 is_xr_overlay_ = val;
3115
3116 // On navigation, the layout view may be invalid, skip style changes.
3117 if (!GetLayoutView())
3118 return;
3119
3120 if (val) {
3121 // The UA style sheet for the :xr-overlay pseudoclass uses lazy loading.
3122 // If we get here, we need to ensure that it's present.
3123 GetStyleEngine().EnsureUAStyleForXrOverlay();
3124 }
3125
3126 if (overlay_element) {
3127 // Now that the custom style sheet is loaded, update the pseudostyle for
3128 // the overlay element.
3129 overlay_element->PseudoStateChanged(CSSSelector::kPseudoXrOverlay);
3130 }
3131
3132 // The DOM overlay may change the effective root element. Need to update
3133 // compositing inputs to avoid a mismatch in CompositingRequirementsUpdater.
3134 GetLayoutView()->Layer()->SetNeedsCompositingInputsUpdate();
3135
3136 // Ensure that the graphics layer tree gets fully rebuilt on changes,
3137 // similar to HTMLVideoElement::DidEnterFullscreen(). This may not be
3138 // strictly necessary if the compositing changes are based on visibility
3139 // settings, but helps ensure consistency in case it's changed to
3140 // detaching layers or re-rooting the graphics layer tree.
3141 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
3142 auto* compositor = GetLayoutView()->Compositor();
3143 compositor->SetNeedsCompositingUpdate(kCompositingUpdateRebuildTree);
3144 }
3145 }
3146
ScheduleUseShadowTreeUpdate(SVGUseElement & element)3147 void Document::ScheduleUseShadowTreeUpdate(SVGUseElement& element) {
3148 use_elements_needing_update_.insert(&element);
3149 ScheduleLayoutTreeUpdateIfNeeded();
3150 }
3151
UnscheduleUseShadowTreeUpdate(SVGUseElement & element)3152 void Document::UnscheduleUseShadowTreeUpdate(SVGUseElement& element) {
3153 use_elements_needing_update_.erase(&element);
3154 }
3155
UpdateUseShadowTreesIfNeeded()3156 void Document::UpdateUseShadowTreesIfNeeded() {
3157 ScriptForbiddenScope forbid_script;
3158
3159 // Breadth-first search since nested use elements add to the queue.
3160 while (!use_elements_needing_update_.IsEmpty()) {
3161 HeapHashSet<Member<SVGUseElement>> elements;
3162 use_elements_needing_update_.swap(elements);
3163 for (SVGUseElement* element : elements)
3164 element->BuildPendingResource();
3165 }
3166 }
3167
GetStyleResolver() const3168 StyleResolver* Document::GetStyleResolver() const {
3169 return style_engine_->Resolver();
3170 }
3171
EnsureStyleResolver() const3172 StyleResolver& Document::EnsureStyleResolver() const {
3173 return style_engine_->EnsureResolver();
3174 }
3175
Initialize()3176 void Document::Initialize() {
3177 DCHECK_EQ(lifecycle_.GetState(), DocumentLifecycle::kInactive);
3178 DCHECK(!ax_object_cache_ || this != &AXObjectCacheOwner());
3179
3180 layout_view_ = new LayoutView(this);
3181 SetLayoutObject(layout_view_);
3182
3183 layout_view_->SetStyle(StyleResolver::StyleForViewport(*this));
3184
3185 AttachContext context;
3186 AttachLayoutTree(context);
3187
3188 // The TextAutosizer can't update layout view info while the Document is
3189 // detached, so update now in case anything changed.
3190 if (TextAutosizer* autosizer = GetTextAutosizer())
3191 autosizer->UpdatePageInfo();
3192
3193 frame_->DidAttachDocument();
3194 lifecycle_.AdvanceTo(DocumentLifecycle::kStyleClean);
3195
3196 if (View())
3197 View()->DidAttachDocument();
3198
3199 // Observer(s) should not be initialized until the document is initialized /
3200 // attached to a frame. Otherwise
3201 // ExecutionContextLifecycleObserver::contextDestroyed wouldn't be fired.
3202 network_state_observer_ =
3203 MakeGarbageCollected<NetworkStateObserver>(GetExecutionContext());
3204
3205 // Check for frame_ so we only attach documents with its own scheduler.
3206 if (frame_)
3207 GetAgent()->AttachDocument(this);
3208 }
3209
Shutdown()3210 void Document::Shutdown() {
3211 TRACE_EVENT0("blink", "Document::shutdown");
3212 CHECK(!frame_ || frame_->Tree().ChildCount() == 0);
3213 if (!IsActive())
3214 return;
3215
3216 // An active Document must have an associated frame.
3217 CHECK(frame_);
3218
3219 // Frame navigation can cause a new Document to be attached. Don't allow that,
3220 // since that will cause a situation where LocalFrame still has a Document
3221 // attached after this finishes! Normally, it shouldn't actually be possible
3222 // to trigger navigation here. However, plugins (see below) can cause lots of
3223 // crazy things to happen, since plugin detach involves nested run loops.
3224 FrameNavigationDisabler navigation_disabler(*frame_);
3225 // Defer plugin dispose to avoid plugins trying to run script inside
3226 // ScriptForbiddenScope, which will crash the renderer after
3227 // https://crrev.com/200984
3228 // TODO(dcheng): This is a temporary workaround, Document::Shutdown() should
3229 // not be running script at all.
3230 HTMLFrameOwnerElement::PluginDisposeSuspendScope suspend_plugin_dispose;
3231 // Don't allow script to run in the middle of DetachLayoutTree() because a
3232 // detaching Document is not in a consistent state.
3233 ScriptForbiddenScope forbid_script;
3234
3235 lifecycle_.AdvanceTo(DocumentLifecycle::kStopping);
3236
3237 // Do not add code before this without a documented reason. A postcondition of
3238 // Shutdown() is that |frame_| must not have an attached Document. Allowing
3239 // script execution when the Document is shutting down can make it easy to
3240 // accidentally violate this condition, and the ordering of the scopers above
3241 // is subtle due to legacy interactions with plugins.
3242
3243 if (num_canvases_ > 0)
3244 UMA_HISTOGRAM_COUNTS_100("Blink.Canvas.NumCanvasesPerPage", num_canvases_);
3245
3246 GetFontMatchingMetrics()->PublishUkmMetrics();
3247
3248 GetViewportData().Shutdown();
3249
3250 View()->Dispose();
3251 // TODO(crbug.com/729196): Trace why LocalFrameView::DetachFromLayout crashes.
3252 CHECK(!View()->IsAttached());
3253
3254 // If the EmbeddedContentView of the document's frame owner doesn't match
3255 // view() then LocalFrameView::Dispose() didn't clear the owner's
3256 // EmbeddedContentView. If we don't clear it here, it may be clobbered later
3257 // in LocalFrame::CreateView(). See also https://crbug.com/673170 and the
3258 // comment in LocalFrameView::Dispose().
3259 HTMLFrameOwnerElement* owner_element = frame_->DeprecatedLocalOwner();
3260
3261 // In the case of a provisional frame, skip clearing the EmbeddedContentView.
3262 // A provisional frame is not fully attached to the DOM yet and clearing the
3263 // EmbeddedContentView here could clear a not-yet-swapped-out frame
3264 // (https://crbug.com/807772).
3265 if (owner_element && !frame_->IsProvisional())
3266 owner_element->SetEmbeddedContentView(nullptr);
3267
3268 markers_->PrepareForDestruction();
3269
3270 GetPage()->DocumentDetached(this);
3271
3272 probe::DocumentDetached(this);
3273
3274 scripted_idle_task_controller_.Clear();
3275
3276 if (SvgExtensions())
3277 AccessSVGExtensions().PauseAnimations();
3278
3279 CancelPendingJavaScriptUrls();
3280 http_refresh_scheduler_->Cancel();
3281 GetFrame()->CancelFormSubmission();
3282
3283 DetachCompositorTimeline(Timeline().CompositorTimeline());
3284
3285 if (frame_->IsLocalRoot())
3286 GetPage()->GetChromeClient().AttachRootLayer(nullptr, frame_.Get());
3287 if (!RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
3288 layout_view_->CleanUpCompositor();
3289
3290 if (RegistrationContext())
3291 RegistrationContext()->DocumentWasDetached();
3292
3293 MutationObserver::CleanSlotChangeList(*this);
3294
3295 hover_element_ = nullptr;
3296 active_element_ = nullptr;
3297 autofocus_candidates_.clear();
3298
3299 if (focused_element_.Get()) {
3300 Element* old_focused_element = focused_element_;
3301 focused_element_ = nullptr;
3302 NotifyFocusedElementChanged(old_focused_element, nullptr);
3303 }
3304 sequential_focus_navigation_starting_point_ = nullptr;
3305
3306 if (this == &AXObjectCacheOwner()) {
3307 ax_contexts_.clear();
3308 ClearAXObjectCache();
3309 }
3310 computed_node_mapping_.clear();
3311
3312 layout_view_ = nullptr;
3313 DetachLayoutTree();
3314 // TODO(crbug.com/729196): Trace why LocalFrameView::DetachFromLayout crashes.
3315 CHECK(!View()->IsAttached());
3316
3317 if (this != &AXObjectCacheOwner()) {
3318 if (AXObjectCache* cache = ExistingAXObjectCache()) {
3319 // Documents that are not a root document use the AXObjectCache in
3320 // their root document. Node::removedFrom is called after the
3321 // document has been detached so it can't find the root document.
3322 // We do the removals here instead.
3323 for (Node& node : NodeTraversal::DescendantsOf(*this)) {
3324 cache->Remove(&node);
3325 }
3326 }
3327 }
3328
3329 GetStyleEngine().DidDetach();
3330
3331 frame_->GetEventHandlerRegistry().DocumentDetached(*this);
3332
3333 // Signal destruction to mutation observers.
3334 synchronous_mutation_observer_list_.ForEachObserver(
3335 [](SynchronousMutationObserver* observer) {
3336 observer->ContextDestroyed();
3337 observer->ObserverListWillBeCleared();
3338 });
3339 synchronous_mutation_observer_list_.Clear();
3340
3341 cookie_jar_ = nullptr; // Not accessible after navigated away.
3342 fetcher_->ClearContext();
3343 // If this document is the master for an HTMLImportsController, sever that
3344 // relationship. This ensures that we don't leave import loads in flight,
3345 // thinking they should have access to a valid frame when they don't.
3346 if (imports_controller_) {
3347 imports_controller_->Dispose();
3348 ClearImportsController();
3349 }
3350
3351 if (media_query_matcher_)
3352 media_query_matcher_->DocumentDetached();
3353
3354 lifecycle_.AdvanceTo(DocumentLifecycle::kStopped);
3355 // TODO(crbug.com/729196): Trace why LocalFrameView::DetachFromLayout crashes.
3356 CHECK(!View()->IsAttached());
3357
3358 // Check for frame_ so we only detach documents with its own scheduler.
3359 // TODO(bokan): Can this happen? |frame_| is dereferenced above and CHECKed
3360 // at top.
3361 if (frame_)
3362 GetAgent()->DetachDocument(this);
3363
3364 // TODO(crbug.com/729196): Trace why LocalFrameView::DetachFromLayout crashes.
3365 CHECK(!View()->IsAttached());
3366
3367 needs_to_record_ukm_outlive_time_ = IsInMainFrame();
3368 if (needs_to_record_ukm_outlive_time_) {
3369 // Ensure |ukm_recorder_| and |ukm_source_id_|.
3370 UkmRecorder();
3371 }
3372
3373 mime_handler_view_before_unload_event_listener_ = nullptr;
3374
3375 resource_coordinator_.reset();
3376
3377 // This is required, as our LocalFrame might delete itself as soon as it
3378 // detaches us. However, this violates Node::detachLayoutTree() semantics, as
3379 // it's never possible to re-attach. Eventually Document::detachLayoutTree()
3380 // should be renamed, or this setting of the frame to 0 could be made
3381 // explicit in each of the callers of Document::detachLayoutTree().
3382 frame_ = nullptr;
3383
3384 document_outlive_time_reporter_ =
3385 std::make_unique<DocumentOutliveTimeReporter>(this);
3386 }
3387
RemoveAllEventListeners()3388 void Document::RemoveAllEventListeners() {
3389 ContainerNode::RemoveAllEventListeners();
3390
3391 if (LocalDOMWindow* dom_window = domWindow())
3392 dom_window->RemoveAllEventListeners();
3393 }
3394
AXObjectCacheOwner() const3395 Document& Document::AXObjectCacheOwner() const {
3396 // Every document has its own axObjectCache if accessibility is enabled,
3397 // except for page popups, which share the axObjectCache of their owner.
3398 Document* doc = const_cast<Document*>(this);
3399 if (doc->GetFrame() && doc->GetFrame()->PagePopupOwner()) {
3400 DCHECK(!doc->ax_object_cache_);
3401 return doc->GetFrame()
3402 ->PagePopupOwner()
3403 ->GetDocument()
3404 .AXObjectCacheOwner();
3405 }
3406 return *doc;
3407 }
3408
AddAXContext(AXContext * context)3409 void Document::AddAXContext(AXContext* context) {
3410 // The only case when |&cache_owner| is not |this| is when this is a
3411 // pop-up. We want pop-ups to share the AXObjectCache of their parent
3412 // document. However, there's no valid reason to explicitly create an
3413 // AXContext for a pop-up document, so check to make sure we're not
3414 // trying to do that here.
3415 DCHECK_EQ(&AXObjectCacheOwner(), this);
3416
3417 // If the document has already been detached, do not make a new AXObjectCache.
3418 if (!GetLayoutView())
3419 return;
3420
3421 ax_contexts_.push_back(context);
3422 if (ax_contexts_.size() != 1)
3423 return;
3424
3425 if (!ax_object_cache_)
3426 ax_object_cache_ = AXObjectCache::Create(*this);
3427 }
3428
RemoveAXContext(AXContext * context)3429 void Document::RemoveAXContext(AXContext* context) {
3430 auto** iter =
3431 std::find_if(ax_contexts_.begin(), ax_contexts_.end(),
3432 [&context](const auto& item) { return item == context; });
3433 if (iter != ax_contexts_.end())
3434 ax_contexts_.erase(iter);
3435 if (ax_contexts_.size() == 0)
3436 ClearAXObjectCache();
3437 }
3438
ClearAXObjectCache()3439 void Document::ClearAXObjectCache() {
3440 DCHECK_EQ(&AXObjectCacheOwner(), this);
3441
3442 // Clear the cache member variable before calling delete because attempts
3443 // are made to access it during destruction.
3444 if (ax_object_cache_)
3445 ax_object_cache_->Dispose();
3446 ax_object_cache_.Clear();
3447
3448 // If there's at least one AXContext in scope and there's still a LayoutView
3449 // around, recreate an empty AXObjectCache.
3450 //
3451 // TODO(dmazzoni): right now ClearAXObjectCache() is being used as a way
3452 // to invalidate / reset the AXObjectCache while keeping it around. We
3453 // should rewrite that as a method on AXObjectCache rather than destroying
3454 // and recreating it here.
3455 if (ax_contexts_.size() > 0 && GetLayoutView())
3456 ax_object_cache_ = AXObjectCache::Create(*this);
3457 }
3458
ExistingAXObjectCache() const3459 AXObjectCache* Document::ExistingAXObjectCache() const {
3460 auto& cache_owner = AXObjectCacheOwner();
3461
3462 // If the LayoutView is gone then we are in the process of destruction.
3463 // This method will be called before frame_ = nullptr.
3464 if (!cache_owner.GetLayoutView())
3465 return nullptr;
3466
3467 return cache_owner.ax_object_cache_.Get();
3468 }
3469
GetCanvasFontCache()3470 CanvasFontCache* Document::GetCanvasFontCache() {
3471 if (!canvas_font_cache_)
3472 canvas_font_cache_ = MakeGarbageCollected<CanvasFontCache>(*this);
3473
3474 return canvas_font_cache_.Get();
3475 }
3476
CreateParser()3477 DocumentParser* Document::CreateParser() {
3478 if (auto* html_document = DynamicTo<HTMLDocument>(this)) {
3479 return MakeGarbageCollected<HTMLDocumentParser>(*html_document,
3480 parser_sync_policy_);
3481 }
3482 // FIXME: this should probably pass the frame instead
3483 return MakeGarbageCollected<XMLDocumentParser>(*this, View());
3484 }
3485
IsFrameSet() const3486 bool Document::IsFrameSet() const {
3487 if (!IsA<HTMLDocument>(this))
3488 return false;
3489 return IsA<HTMLFrameSetElement>(body());
3490 }
3491
GetScriptableDocumentParser() const3492 ScriptableDocumentParser* Document::GetScriptableDocumentParser() const {
3493 return Parser() ? Parser()->AsScriptableDocumentParser() : nullptr;
3494 }
3495
DisplayNoneChangedForFrame()3496 void Document::DisplayNoneChangedForFrame() {
3497 if (!documentElement())
3498 return;
3499 // LayoutView()::CanHaveChildren(), hence the existence of style and
3500 // layout tree, depends on the owner being display:none or not. Trigger
3501 // detaching or attaching the style/layout-tree as a result of that
3502 // changing.
3503 documentElement()->SetNeedsStyleRecalc(
3504 kLocalStyleChange,
3505 StyleChangeReasonForTracing::Create(style_change_reason::kFrame));
3506 }
3507
SetPrinting(PrintingState state)3508 void Document::SetPrinting(PrintingState state) {
3509 bool was_printing = Printing();
3510 printing_ = state;
3511 bool is_printing = Printing();
3512
3513 if ((was_printing != is_printing) && documentElement() && GetFrame() &&
3514 !GetFrame()->IsMainFrame() && GetFrame()->Owner() &&
3515 GetFrame()->Owner()->IsDisplayNone()) {
3516 // In non-printing mode we do not generate style or layout objects for
3517 // display:none iframes, yet we do when printing (see
3518 // LayoutView::CanHaveChildren). Trigger a style recalc on the root element
3519 // to create a layout tree for printing.
3520 DisplayNoneChangedForFrame();
3521 }
3522 }
3523
SetIsPaintingPreview(bool is_painting_preview)3524 void Document::SetIsPaintingPreview(bool is_painting_preview) {
3525 is_painting_preview_ = is_painting_preview;
3526 }
3527
3528 // https://html.spec.whatwg.org/C/dynamic-markup-insertion.html#document-open-steps
open(Document * entered_document,ExceptionState & exception_state)3529 void Document::open(Document* entered_document,
3530 ExceptionState& exception_state) {
3531 if (ImportLoader()) {
3532 exception_state.ThrowDOMException(
3533 DOMExceptionCode::kInvalidStateError,
3534 "Imported document doesn't support open().");
3535 return;
3536 }
3537
3538 // If |document| is an XML document, then throw an "InvalidStateError"
3539 // DOMException exception.
3540 if (!IsA<HTMLDocument>(this)) {
3541 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
3542 "Only HTML documents support open().");
3543 return;
3544 }
3545
3546 // If |document|'s throw-on-dynamic-markup-insertion counter is greater than
3547 // 0, then throw an "InvalidStateError" DOMException.
3548 if (throw_on_dynamic_markup_insertion_count_) {
3549 exception_state.ThrowDOMException(
3550 DOMExceptionCode::kInvalidStateError,
3551 "Custom Element constructor should not use open().");
3552 return;
3553 }
3554
3555 if (!AllowedToUseDynamicMarkUpInsertion("open", exception_state))
3556 return;
3557
3558 // If |document|'s origin is not same origin to the origin of the responsible
3559 // document specified by the entry settings object, then throw a
3560 // "SecurityError" DOMException.
3561 if (entered_document && !GetSecurityOrigin()->IsSameOriginWith(
3562 entered_document->GetSecurityOrigin())) {
3563 exception_state.ThrowSecurityError(
3564 "Can only call open() on same-origin documents.");
3565 return;
3566 }
3567
3568 // If |document| has an active parser whose script nesting level is greater
3569 // than 0, then return |document|.
3570 if (ScriptableDocumentParser* parser = GetScriptableDocumentParser()) {
3571 if (parser->IsParsing() && parser->IsExecutingScript())
3572 return;
3573 }
3574
3575 // Similarly, if |document|'s ignore-opens-during-unload counter is greater
3576 // than 0, then return |document|.
3577 if (ignore_opens_during_unload_count_)
3578 return;
3579
3580 // If |document|'s active parser was aborted is true, then return |document|.
3581 if (ignore_opens_and_writes_for_abort_)
3582 return;
3583
3584 // Change |document|'s URL to the URL of the responsible document specified
3585 // by the entry settings object.
3586 if (entered_document && this != entered_document) {
3587 auto* csp = MakeGarbageCollected<ContentSecurityPolicy>();
3588 csp->CopyStateFrom(entered_document->GetContentSecurityPolicy());
3589 // We inherit the sandbox flags of the entered document, so mask on
3590 // the ones contained in the CSP.
3591 GetSecurityContext().ApplySandboxFlags(csp->GetSandboxMask());
3592 InitContentSecurityPolicy(csp);
3593 // Clear the hash fragment from the inherited URL to prevent a
3594 // scroll-into-view for any document.open()'d frame.
3595 KURL new_url = entered_document->Url();
3596 new_url.SetFragmentIdentifier(String());
3597 SetURL(new_url);
3598 if (Loader())
3599 Loader()->UpdateUrlForDocumentOpen(new_url);
3600
3601 GetSecurityContext().SetSecurityOrigin(
3602 entered_document->GetMutableSecurityOrigin());
3603 SetReferrerPolicy(entered_document->GetReferrerPolicy());
3604 SetCookieURL(entered_document->CookieURL());
3605 }
3606
3607 open();
3608 }
3609
3610 // https://html.spec.whatwg.org/C/dynamic-markup-insertion.html#document-open-steps
open()3611 void Document::open() {
3612 DCHECK(!ImportLoader());
3613 DCHECK(!ignore_opens_during_unload_count_);
3614 if (ScriptableDocumentParser* parser = GetScriptableDocumentParser())
3615 DCHECK(!parser->IsParsing() || !parser->IsExecutingScript());
3616
3617 // If |document| has a browsing context and there is an existing attempt to
3618 // navigate |document|'s browsing context, then stop document loading given
3619 // |document|.
3620 //
3621 // As noted in the spec and https://github.com/whatwg/html/issues/3975, we
3622 // want to treat ongoing navigation and queued navigation the same way.
3623 // However, we don't want to consider navigations scheduled too much into the
3624 // future through Refresh headers or a <meta> refresh pragma to be a current
3625 // navigation. Thus, we cut it off with
3626 // IsHttpRefreshScheduledWithin(base::TimeDelta()).
3627 //
3628 // This also prevents window.open(url) -- eg window.open("about:blank") --
3629 // from blowing away results from a subsequent window.document.open /
3630 // window.document.write call.
3631 if (frame_ && (frame_->Loader().HasProvisionalNavigation() ||
3632 IsHttpRefreshScheduledWithin(base::TimeDelta()))) {
3633 frame_->Loader().StopAllLoaders();
3634 // Navigations handled by the client should also be cancelled.
3635 if (frame_ && frame_->Client())
3636 frame_->Client()->AbortClientNavigation();
3637 }
3638 CancelPendingJavaScriptUrls();
3639
3640 // TODO(crbug.com/1085514): Consider making HasProvisionalNavigation() return
3641 // true when form submission task is active, in which case we can delete this
3642 // redundant attempt to cancel it.
3643 if (GetFrame())
3644 GetFrame()->CancelFormSubmission();
3645
3646 // For each shadow-including inclusive descendant |node| of |document|, erase
3647 // all event listeners and handlers given |node|.
3648 //
3649 // Erase all event listeners and handlers given |window|.
3650 //
3651 // NB: Document::RemoveAllEventListeners() (called by
3652 // RemoveAllEventListenersRecursively()) erases event listeners from the
3653 // Window object as well.
3654 RemoveAllEventListenersRecursively();
3655
3656 ResetTreeScope();
3657 if (frame_)
3658 frame_->Selection().Clear();
3659
3660 // Create a new HTML parser and associate it with |document|.
3661 //
3662 // Set the current document readiness of |document| to "loading".
3663 ImplicitOpen(kForceSynchronousParsing);
3664
3665 // This is a script-created parser.
3666 if (ScriptableDocumentParser* parser = GetScriptableDocumentParser())
3667 parser->SetWasCreatedByScript(true);
3668
3669 if (frame_)
3670 frame_->Loader().DidExplicitOpen();
3671 }
3672
DetachParser()3673 void Document::DetachParser() {
3674 if (!parser_)
3675 return;
3676 parser_->Detach();
3677 parser_.Clear();
3678 DocumentParserTiming::From(*this).MarkParserDetached();
3679 }
3680
CancelParsing()3681 void Document::CancelParsing() {
3682 // There appears to be an unspecced assumption that a document.open()
3683 // or document.write() immediately after a navigation start won't cancel
3684 // the navigation. Firefox avoids cancelling the navigation by ignoring an
3685 // open() or write() after an active parser is aborted. See
3686 // https://github.com/whatwg/html/issues/4723 for discussion about
3687 // standardizing this behavior.
3688 if (parser_ && parser_->IsParsing())
3689 ignore_opens_and_writes_for_abort_ = true;
3690 DetachParser();
3691 SetParsingState(kFinishedParsing);
3692 SetReadyState(kComplete);
3693 if (!LoadEventFinished())
3694 load_event_progress_ = kLoadEventCompleted;
3695 CancelPendingJavaScriptUrls();
3696 http_refresh_scheduler_->Cancel();
3697 }
3698
OpenForNavigation(ParserSynchronizationPolicy parser_sync_policy,const AtomicString & mime_type,const AtomicString & encoding)3699 DocumentParser* Document::OpenForNavigation(
3700 ParserSynchronizationPolicy parser_sync_policy,
3701 const AtomicString& mime_type,
3702 const AtomicString& encoding) {
3703 DocumentParser* parser = ImplicitOpen(parser_sync_policy);
3704 if (parser->NeedsDecoder())
3705 parser->SetDecoder(BuildTextResourceDecoderFor(this, mime_type, encoding));
3706 return parser;
3707 }
3708
ImplicitOpen(ParserSynchronizationPolicy parser_sync_policy)3709 DocumentParser* Document::ImplicitOpen(
3710 ParserSynchronizationPolicy parser_sync_policy) {
3711 RemoveChildren();
3712 DCHECK(!focused_element_);
3713
3714 SetCompatibilityMode(kNoQuirksMode);
3715
3716 if (!ThreadedParsingEnabledForTesting()) {
3717 parser_sync_policy = kForceSynchronousParsing;
3718 } else if (parser_sync_policy == kAllowAsynchronousParsing &&
3719 IsPrefetchOnly()) {
3720 // Prefetch must be synchronous.
3721 parser_sync_policy = kForceSynchronousParsing;
3722 }
3723
3724 DetachParser();
3725 parser_sync_policy_ = parser_sync_policy;
3726 parser_ = CreateParser();
3727 DocumentParserTiming::From(*this).MarkParserStart();
3728 SetParsingState(kParsing);
3729 SetReadyState(kLoading);
3730 if (load_event_progress_ != kLoadEventInProgress &&
3731 PageDismissalEventBeingDispatched() == kNoDismissal) {
3732 load_event_progress_ = kLoadEventNotRun;
3733 }
3734
3735 return parser_;
3736 }
3737
body() const3738 HTMLElement* Document::body() const {
3739 if (!IsA<HTMLHtmlElement>(documentElement()))
3740 return nullptr;
3741
3742 for (HTMLElement* child =
3743 Traversal<HTMLElement>::FirstChild(*documentElement());
3744 child; child = Traversal<HTMLElement>::NextSibling(*child)) {
3745 if (IsA<HTMLFrameSetElement>(*child) || IsA<HTMLBodyElement>(*child))
3746 return child;
3747 }
3748
3749 return nullptr;
3750 }
3751
FirstBodyElement() const3752 HTMLBodyElement* Document::FirstBodyElement() const {
3753 if (!IsA<HTMLHtmlElement>(documentElement()))
3754 return nullptr;
3755
3756 for (HTMLElement* child =
3757 Traversal<HTMLElement>::FirstChild(*documentElement());
3758 child; child = Traversal<HTMLElement>::NextSibling(*child)) {
3759 if (auto* body = DynamicTo<HTMLBodyElement>(*child))
3760 return body;
3761 }
3762
3763 return nullptr;
3764 }
3765
setBody(HTMLElement * prp_new_body,ExceptionState & exception_state)3766 void Document::setBody(HTMLElement* prp_new_body,
3767 ExceptionState& exception_state) {
3768 HTMLElement* new_body = prp_new_body;
3769
3770 if (!new_body) {
3771 exception_state.ThrowDOMException(
3772 DOMExceptionCode::kHierarchyRequestError,
3773 ExceptionMessages::ArgumentNullOrIncorrectType(1, "HTMLElement"));
3774 return;
3775 }
3776 if (!documentElement()) {
3777 exception_state.ThrowDOMException(DOMExceptionCode::kHierarchyRequestError,
3778 "No document element exists.");
3779 return;
3780 }
3781
3782 if (!IsA<HTMLBodyElement>(*new_body) &&
3783 !IsA<HTMLFrameSetElement>(*new_body)) {
3784 exception_state.ThrowDOMException(
3785 DOMExceptionCode::kHierarchyRequestError,
3786 "The new body element is of type '" + new_body->tagName() +
3787 "'. It must be either a 'BODY' or 'FRAMESET' element.");
3788 return;
3789 }
3790
3791 HTMLElement* old_body = body();
3792 if (old_body == new_body)
3793 return;
3794
3795 if (old_body)
3796 documentElement()->ReplaceChild(new_body, old_body, exception_state);
3797 else
3798 documentElement()->AppendChild(new_body, exception_state);
3799 }
3800
WillInsertBody()3801 void Document::WillInsertBody() {
3802 if (Loader())
3803 fetcher_->LoosenLoadThrottlingPolicy();
3804
3805 // If we get to the <body> try to resume commits since we should have content
3806 // to paint now.
3807 // TODO(esprehn): Is this really optimal? We might start producing frames
3808 // for very little content, should we wait for some heuristic like
3809 // isVisuallyNonEmpty() ?
3810 BeginLifecycleUpdatesIfRenderingReady();
3811 }
3812
head() const3813 HTMLHeadElement* Document::head() const {
3814 Node* de = documentElement();
3815 if (!de)
3816 return nullptr;
3817
3818 return Traversal<HTMLHeadElement>::FirstChild(*de);
3819 }
3820
ViewportDefiningElement() const3821 Element* Document::ViewportDefiningElement() const {
3822 // If a BODY element sets non-visible overflow, it is to be propagated to the
3823 // viewport, as long as the following conditions are all met:
3824 // (1) The root element is HTML.
3825 // (2) It is the primary BODY element (we only assert for this, expecting
3826 // callers to behave).
3827 // (3) The root element has visible overflow.
3828 // Otherwise it's the root element's properties that are to be propagated.
3829 Element* root_element = documentElement();
3830 Element* body_element = body();
3831 if (!root_element)
3832 return nullptr;
3833 const ComputedStyle* root_style = root_element->GetComputedStyle();
3834 if (!root_style || root_style->IsEnsuredInDisplayNone())
3835 return nullptr;
3836 if (body_element && root_style->IsOverflowVisible() &&
3837 IsA<HTMLHtmlElement>(root_element))
3838 return body_element;
3839 return root_element;
3840 }
3841
open(v8::Isolate * isolate,const AtomicString & type,const AtomicString & replace,ExceptionState & exception_state)3842 Document* Document::open(v8::Isolate* isolate,
3843 const AtomicString& type,
3844 const AtomicString& replace,
3845 ExceptionState& exception_state) {
3846 if (replace == "replace") {
3847 CountUse(WebFeature::kDocumentOpenTwoArgsWithReplace);
3848 }
3849 open(EnteredDOMWindow(isolate)->document(), exception_state);
3850 return this;
3851 }
3852
open(v8::Isolate * isolate,const String & url_string,const AtomicString & name,const AtomicString & features,ExceptionState & exception_state)3853 DOMWindow* Document::open(v8::Isolate* isolate,
3854 const String& url_string,
3855 const AtomicString& name,
3856 const AtomicString& features,
3857 ExceptionState& exception_state) {
3858 if (!domWindow()) {
3859 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
3860 "The document has no window associated.");
3861 return nullptr;
3862 }
3863
3864 return domWindow()->open(isolate, url_string, name, features,
3865 exception_state);
3866 }
3867
3868 // https://html.spec.whatwg.org/C/dynamic-markup-insertion.html#dom-document-close
close(ExceptionState & exception_state)3869 void Document::close(ExceptionState& exception_state) {
3870 if (ImportLoader()) {
3871 exception_state.ThrowDOMException(
3872 DOMExceptionCode::kInvalidStateError,
3873 "Imported document doesn't support close().");
3874 return;
3875 }
3876
3877 // If the Document object is an XML document, then throw an
3878 // "InvalidStateError" DOMException.
3879 if (!IsA<HTMLDocument>(this)) {
3880 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
3881 "Only HTML documents support close().");
3882 return;
3883 }
3884
3885 // If the Document object's throw-on-dynamic-markup-insertion counter is
3886 // greater than zero, then throw an "InvalidStateError" DOMException.
3887 if (throw_on_dynamic_markup_insertion_count_) {
3888 exception_state.ThrowDOMException(
3889 DOMExceptionCode::kInvalidStateError,
3890 "Custom Element constructor should not use close().");
3891 return;
3892 }
3893
3894 if (!AllowedToUseDynamicMarkUpInsertion("close", exception_state))
3895 return;
3896
3897 close();
3898 }
3899
3900 // https://html.spec.whatwg.org/C/dynamic-markup-insertion.html#dom-document-close
close()3901 void Document::close() {
3902 // If there is no script-created parser associated with the document, then
3903 // return.
3904 if (!GetScriptableDocumentParser() ||
3905 !GetScriptableDocumentParser()->WasCreatedByScript() ||
3906 !GetScriptableDocumentParser()->IsParsing())
3907 return;
3908
3909 // Insert an explicit "EOF" character at the end of the parser's input
3910 // stream.
3911 parser_->Finish();
3912
3913 // TODO(timothygu): We should follow the specification more closely.
3914 if (!parser_ || !parser_->IsParsing())
3915 SetReadyState(kComplete);
3916 CheckCompleted();
3917 }
3918
ImplicitClose()3919 void Document::ImplicitClose() {
3920 DCHECK(!InStyleRecalc());
3921
3922 load_event_progress_ = kLoadEventInProgress;
3923
3924 // We have to clear the parser, in case someone document.write()s from the
3925 // onLoad event handler, as in Radar 3206524.
3926 DetachParser();
3927
3928 // JS running below could remove the frame or destroy the LayoutView so we
3929 // call those two functions repeatedly and don't save them on the stack.
3930
3931 // To align the HTML load event and the SVGLoad event for the outermost <svg>
3932 // element, fire it from here, instead of doing it from
3933 // SVGElement::finishedParsingChildren.
3934 if (SvgExtensions())
3935 AccessSVGExtensions().DispatchSVGLoadEventToOutermostSVGElements();
3936
3937 if (domWindow())
3938 domWindow()->DocumentWasClosed();
3939
3940 if (GetFrame() && GetFrame()->IsMainFrame())
3941 GetFrame()->GetLocalFrameHostRemote().DocumentOnLoadCompleted();
3942
3943 if (GetFrame()) {
3944 GetFrame()->Client()->DispatchDidHandleOnloadEvents();
3945 Loader()->GetApplicationCacheHost()->StopDeferringEvents();
3946 }
3947
3948 if (!GetFrame()) {
3949 load_event_progress_ = kLoadEventCompleted;
3950 return;
3951 }
3952
3953 if (GetFrame()->Loader().HasProvisionalNavigation() &&
3954 start_time_.Elapsed() < kCLayoutScheduleThreshold) {
3955 // Just bail out. Before or during the onload we were shifted to another
3956 // page. The old i-Bench suite does this. When this happens don't bother
3957 // painting or laying out.
3958 load_event_progress_ = kLoadEventCompleted;
3959 return;
3960 }
3961
3962 // We used to force a synchronous display and flush here. This really isn't
3963 // necessary and can in fact be actively harmful if pages are loading at a
3964 // rate of > 60fps
3965 // (if your platform is syncing flushes and limiting them to 60fps).
3966 if (!LocalOwner() || (LocalOwner()->GetLayoutObject() &&
3967 !LocalOwner()->GetLayoutObject()->NeedsLayout())) {
3968 UpdateStyleAndLayoutTree();
3969
3970 // Always do a layout after loading if needed.
3971 if (View() && GetLayoutView() &&
3972 (!GetLayoutView()->FirstChild() || GetLayoutView()->NeedsLayout()))
3973 View()->UpdateLayout();
3974 }
3975
3976 load_event_progress_ = kLoadEventCompleted;
3977
3978 if (GetFrame() && GetLayoutView()) {
3979 if (AXObjectCache* cache = ExistingAXObjectCache()) {
3980 if (this == &AXObjectCacheOwner())
3981 cache->HandleLoadComplete(this);
3982 else
3983 cache->HandleLayoutComplete(this);
3984 }
3985 }
3986
3987 if (SvgExtensions())
3988 AccessSVGExtensions().StartAnimations();
3989 }
3990
AllDescendantsAreComplete(Document * document)3991 static bool AllDescendantsAreComplete(Document* document) {
3992 Frame* frame = document->GetFrame();
3993 if (!frame)
3994 return true;
3995 for (Frame* child = frame->Tree().FirstChild(); child;
3996 child = child->Tree().TraverseNext(frame)) {
3997 if (child->IsLoading())
3998 return false;
3999 }
4000 for (PortalContents* portal : DocumentPortals::From(*document).GetPortals()) {
4001 auto* frame = portal->GetFrame();
4002 if (frame && frame->IsLoading())
4003 return false;
4004 }
4005 return true;
4006 }
4007
ShouldComplete()4008 bool Document::ShouldComplete() {
4009 return parsing_state_ == kFinishedParsing && HaveImportsLoaded() &&
4010 !fetcher_->BlockingRequestCount() && !IsDelayingLoadEvent() &&
4011 !javascript_url_task_handle_.IsActive() &&
4012 load_event_progress_ != kLoadEventInProgress &&
4013 AllDescendantsAreComplete(this) && !Fetcher()->IsInRequestResource();
4014 }
4015
Abort()4016 void Document::Abort() {
4017 CancelParsing();
4018 CheckCompletedInternal();
4019 }
4020
CheckCompleted()4021 void Document::CheckCompleted() {
4022 if (CheckCompletedInternal()) {
4023 frame_->Loader().DidFinishNavigation(
4024 FrameLoader::NavigationFinishState::kSuccess);
4025 }
4026 }
4027
CheckCompletedInternal()4028 bool Document::CheckCompletedInternal() {
4029 if (!ShouldComplete())
4030 return false;
4031
4032 if (frame_ && !UnloadStarted()) {
4033 frame_->Client()->RunScriptsAtDocumentIdle();
4034
4035 // Injected scripts may have disconnected this frame.
4036 if (!frame_)
4037 return false;
4038
4039 // Check again, because runScriptsAtDocumentIdle() may have delayed the load
4040 // event.
4041 if (!ShouldComplete())
4042 return false;
4043 }
4044
4045 // OK, completed. Fire load completion events as needed.
4046 SetReadyState(kComplete);
4047 if (LoadEventStillNeeded())
4048 ImplicitClose();
4049
4050 // The readystatechanged or load event may have disconnected this frame.
4051 if (!frame_ || !frame_->IsAttached())
4052 return false;
4053 http_refresh_scheduler_->MaybeStartTimer();
4054 View()->HandleLoadCompleted();
4055 // The document itself is complete, but if a child frame was restarted due to
4056 // an event, this document is still considered to be in progress.
4057 if (!AllDescendantsAreComplete(this))
4058 return false;
4059
4060 // No need to repeat if we've already notified this load as finished.
4061 if (!Loader()->SentDidFinishLoad()) {
4062 if (frame_->IsMainFrame())
4063 GetViewportData().GetViewportDescription().ReportMobilePageStats(frame_);
4064 Loader()->SetSentDidFinishLoad();
4065 frame_->Client()->DispatchDidFinishLoad();
4066 frame_->GetLocalFrameHostRemote().DidFinishLoad(Loader()->Url());
4067 if (!frame_)
4068 return false;
4069
4070 // Send the source ID of the document to the browser.
4071 if (frame_->Client()->GetRemoteNavigationAssociatedInterfaces()) {
4072 mojo::AssociatedRemote<mojom::blink::UkmSourceIdFrameHost> ukm_binding;
4073 frame_->Client()->GetRemoteNavigationAssociatedInterfaces()->GetInterface(
4074 &ukm_binding);
4075 DCHECK(ukm_binding.is_bound());
4076 ukm_binding->SetDocumentSourceId(ukm_source_id_);
4077 }
4078
4079 frame_->GetFrameScheduler()->RegisterStickyFeature(
4080 SchedulingPolicy::Feature::kDocumentLoaded,
4081 {SchedulingPolicy::RecordMetricsForBackForwardCache()});
4082
4083 AnchorElementMetrics::NotifyOnLoad(*this);
4084
4085 // If this is a document associated with a resource loading hints based
4086 // preview, then record the resource loading hints UKM now that the load is
4087 // finished.
4088 PreviewsResourceLoadingHints* hints =
4089 Loader()->GetPreviewsResourceLoadingHints();
4090 if (hints) {
4091 hints->RecordUKM(UkmRecorder());
4092 }
4093 }
4094
4095 if (auto* view = View()) {
4096 if (view->GetFragmentAnchor()) {
4097 // Schedule an animation frame to process fragment anchors. The frame
4098 // can't be scheduled when the fragment anchor is set because, per spec,
4099 // we must wait for the document to be loaded before invoking fragment
4100 // anchors.
4101 View()->ScheduleAnimation();
4102 }
4103 }
4104
4105 return true;
4106 }
4107
DispatchBeforeUnloadEvent(ChromeClient * chrome_client,bool is_reload,bool & did_allow_navigation)4108 bool Document::DispatchBeforeUnloadEvent(ChromeClient* chrome_client,
4109 bool is_reload,
4110 bool& did_allow_navigation) {
4111 if (!dom_window_)
4112 return true;
4113
4114 if (!body())
4115 return true;
4116
4117 if (ProcessingBeforeUnload())
4118 return false;
4119
4120 MainThreadDisallowSynchronousXHRScope disallow_synchronous_xhr;
4121 auto& before_unload_event = *MakeGarbageCollected<BeforeUnloadEvent>();
4122 before_unload_event.initEvent(event_type_names::kBeforeunload, false, true);
4123 load_event_progress_ = kBeforeUnloadEventInProgress;
4124 const base::TimeTicks beforeunload_event_start = base::TimeTicks::Now();
4125 dom_window_->DispatchEvent(before_unload_event, this);
4126 const base::TimeTicks beforeunload_event_end = base::TimeTicks::Now();
4127 load_event_progress_ = kBeforeUnloadEventCompleted;
4128 DEFINE_STATIC_LOCAL(
4129 CustomCountHistogram, beforeunload_histogram,
4130 ("DocumentEventTiming.BeforeUnloadDuration", 0, 10000000, 50));
4131 beforeunload_histogram.CountMicroseconds(beforeunload_event_end -
4132 beforeunload_event_start);
4133 if (!before_unload_event.defaultPrevented())
4134 DefaultEventHandler(before_unload_event);
4135
4136 enum BeforeUnloadDialogHistogramEnum {
4137 kNoDialogNoText,
4138 kNoDialogNoUserGesture,
4139 kNoDialogMultipleConfirmationForNavigation,
4140 kShowDialog,
4141 kNoDialogAutoCancelTrue,
4142 kDialogEnumMax
4143 };
4144 DEFINE_STATIC_LOCAL(EnumerationHistogram, beforeunload_dialog_histogram,
4145 ("Document.BeforeUnloadDialog", kDialogEnumMax));
4146 if (before_unload_event.returnValue().IsNull()) {
4147 beforeunload_dialog_histogram.Count(kNoDialogNoText);
4148 }
4149 if (!GetFrame() || before_unload_event.returnValue().IsNull())
4150 return true;
4151
4152 if (!GetFrame()->HasStickyUserActivation()) {
4153 beforeunload_dialog_histogram.Count(kNoDialogNoUserGesture);
4154 String message =
4155 "Blocked attempt to show a 'beforeunload' confirmation panel for a "
4156 "frame that never had a user gesture since its load. "
4157 "https://www.chromestatus.com/feature/5082396709879808";
4158 Intervention::GenerateReport(frame_, "BeforeUnloadNoGesture", message);
4159 return true;
4160 }
4161
4162 if (did_allow_navigation) {
4163 beforeunload_dialog_histogram.Count(
4164 kNoDialogMultipleConfirmationForNavigation);
4165 String message =
4166 "Blocked attempt to show multiple 'beforeunload' confirmation panels "
4167 "for a single navigation.";
4168 Intervention::GenerateReport(frame_, "BeforeUnloadMultiple", message);
4169 return true;
4170 }
4171
4172 // If |chrome_client| is null simply indicate that the navigation should
4173 // not proceed.
4174 if (!chrome_client) {
4175 beforeunload_dialog_histogram.Count(kNoDialogAutoCancelTrue);
4176 did_allow_navigation = false;
4177 return false;
4178 }
4179
4180 String text = before_unload_event.returnValue();
4181 beforeunload_dialog_histogram.Count(
4182 BeforeUnloadDialogHistogramEnum::kShowDialog);
4183 const base::TimeTicks beforeunload_confirmpanel_start =
4184 base::TimeTicks::Now();
4185 did_allow_navigation =
4186 chrome_client->OpenBeforeUnloadConfirmPanel(text, frame_, is_reload);
4187 const base::TimeTicks beforeunload_confirmpanel_end = base::TimeTicks::Now();
4188 if (did_allow_navigation) {
4189 // Only record when a navigation occurs, since we want to understand
4190 // the impact of the before unload dialog on overall input to navigation.
4191 UMA_HISTOGRAM_MEDIUM_TIMES(
4192 "DocumentEventTiming.BeforeUnloadDialogDuration.ByNavigation",
4193 beforeunload_confirmpanel_end - beforeunload_confirmpanel_start);
4194 return true;
4195 }
4196
4197 return false;
4198 }
4199
DispatchUnloadEvents(SecurityOrigin * committing_origin,base::Optional<Document::UnloadEventTiming> * unload_timing)4200 void Document::DispatchUnloadEvents(
4201 SecurityOrigin* committing_origin,
4202 base::Optional<Document::UnloadEventTiming>* unload_timing) {
4203 PluginScriptForbiddenScope forbid_plugin_destructor_scripting;
4204 MainThreadDisallowSynchronousXHRScope disallow_synchronous_xhr;
4205 if (parser_)
4206 parser_->StopParsing();
4207
4208 if (load_event_progress_ == kLoadEventNotRun)
4209 return;
4210
4211 if (load_event_progress_ <= kUnloadEventInProgress) {
4212 Element* current_focused_element = FocusedElement();
4213 if (auto* input = DynamicTo<HTMLInputElement>(current_focused_element))
4214 input->EndEditing();
4215 if (load_event_progress_ < kPageHideInProgress) {
4216 load_event_progress_ = kPageHideInProgress;
4217 if (LocalDOMWindow* window = domWindow()) {
4218 const base::TimeTicks pagehide_event_start = base::TimeTicks::Now();
4219 window->DispatchEvent(
4220 *PageTransitionEvent::Create(event_type_names::kPagehide, false),
4221 this);
4222 const base::TimeTicks pagehide_event_end = base::TimeTicks::Now();
4223 DEFINE_STATIC_LOCAL(
4224 CustomCountHistogram, pagehide_histogram,
4225 ("DocumentEventTiming.PageHideDuration", 0, 10000000, 50));
4226 pagehide_histogram.CountMicroseconds(pagehide_event_end -
4227 pagehide_event_start);
4228 }
4229 if (!frame_)
4230 return;
4231
4232 // This must be queried before |load_event_progress_| is changed to
4233 // kUnloadVisibilityChangeInProgress because that would change the result.
4234 bool page_visible = IsPageVisible();
4235 load_event_progress_ = kUnloadVisibilityChangeInProgress;
4236 if (page_visible) {
4237 // Dispatch visibilitychange event, but don't bother doing
4238 // other notifications as we're about to be unloaded.
4239 const base::TimeTicks pagevisibility_hidden_event_start =
4240 base::TimeTicks::Now();
4241 DispatchEvent(
4242 *Event::CreateBubble(event_type_names::kVisibilitychange));
4243 const base::TimeTicks pagevisibility_hidden_event_end =
4244 base::TimeTicks::Now();
4245 DEFINE_STATIC_LOCAL(CustomCountHistogram, pagevisibility_histogram,
4246 ("DocumentEventTiming.PageVibilityHiddenDuration",
4247 0, 10000000, 50));
4248 pagevisibility_histogram.CountMicroseconds(
4249 pagevisibility_hidden_event_end -
4250 pagevisibility_hidden_event_start);
4251 DispatchEvent(
4252 *Event::CreateBubble(event_type_names::kWebkitvisibilitychange));
4253 }
4254 if (!frame_)
4255 return;
4256
4257 frame_->Loader().SaveScrollAnchor();
4258
4259 load_event_progress_ = kUnloadEventInProgress;
4260 Event& unload_event = *Event::Create(event_type_names::kUnload);
4261 const base::TimeTicks unload_event_start = base::TimeTicks::Now();
4262 frame_->DomWindow()->DispatchEvent(unload_event, this);
4263 const base::TimeTicks unload_event_end = base::TimeTicks::Now();
4264
4265 if (unload_timing) {
4266 // Record unload event timing when navigating cross-document.
4267 DEFINE_STATIC_LOCAL(
4268 CustomCountHistogram, unload_histogram,
4269 ("DocumentEventTiming.UnloadDuration", 0, 10000000, 50));
4270 unload_histogram.CountMicroseconds(unload_event_end -
4271 unload_event_start);
4272
4273 // Fill in the unload timing if the new document origin has access to
4274 // them.
4275 if (committing_origin->CanRequest(Url())) {
4276 auto& timing = unload_timing->emplace();
4277 timing.unload_event_start = unload_event_start;
4278 timing.unload_event_end = unload_event_end;
4279 }
4280 }
4281 }
4282 load_event_progress_ = kUnloadEventHandled;
4283 }
4284 }
4285
DispatchFreezeEvent()4286 void Document::DispatchFreezeEvent() {
4287 const base::TimeTicks freeze_event_start = base::TimeTicks::Now();
4288 SetFreezingInProgress(true);
4289 DispatchEvent(*Event::Create(event_type_names::kFreeze));
4290 SetFreezingInProgress(false);
4291 const base::TimeTicks freeze_event_end = base::TimeTicks::Now();
4292 DEFINE_STATIC_LOCAL(CustomCountHistogram, freeze_histogram,
4293 ("DocumentEventTiming.FreezeDuration", 0, 10000000, 50));
4294 freeze_histogram.CountMicroseconds(freeze_event_end - freeze_event_start);
4295 UseCounter::Count(*this, WebFeature::kPageLifeCycleFreeze);
4296 }
4297
PageDismissalEventBeingDispatched() const4298 Document::PageDismissalType Document::PageDismissalEventBeingDispatched()
4299 const {
4300 switch (load_event_progress_) {
4301 case kBeforeUnloadEventInProgress:
4302 return kBeforeUnloadDismissal;
4303 case kPageHideInProgress:
4304 return kPageHideDismissal;
4305 case kUnloadVisibilityChangeInProgress:
4306 return kUnloadVisibilityChangeDismissal;
4307 case kUnloadEventInProgress:
4308 return kUnloadDismissal;
4309
4310 case kLoadEventNotRun:
4311 case kLoadEventInProgress:
4312 case kLoadEventCompleted:
4313 case kBeforeUnloadEventCompleted:
4314 case kUnloadEventHandled:
4315 return kNoDismissal;
4316 }
4317 NOTREACHED();
4318 return kNoDismissal;
4319 }
4320
SetParsingState(ParsingState parsing_state)4321 void Document::SetParsingState(ParsingState parsing_state) {
4322 ParsingState previous_state = parsing_state_;
4323 parsing_state_ = parsing_state;
4324
4325 if (Parsing() && !element_data_cache_)
4326 element_data_cache_ = MakeGarbageCollected<ElementDataCache>();
4327 if (previous_state != kFinishedParsing &&
4328 parsing_state_ == kFinishedParsing) {
4329 if (form_controller_ && form_controller_->HasControlStates())
4330 form_controller_->ScheduleRestore();
4331 }
4332 }
4333
ShouldScheduleLayout() const4334 bool Document::ShouldScheduleLayout() const {
4335 // This function will only be called when LocalFrameView thinks a layout is
4336 // needed. This enforces a couple extra rules.
4337 //
4338 // (a) Only schedule a layout once the stylesheets are loaded.
4339 // (b) Only schedule layout once we have a body element.
4340 if (!IsActive())
4341 return false;
4342
4343 if (HaveRenderBlockingResourcesLoaded() && body())
4344 return true;
4345
4346 if (documentElement() && !IsA<HTMLHtmlElement>(documentElement()))
4347 return true;
4348
4349 return false;
4350 }
4351
write(const String & text,Document * entered_document,ExceptionState & exception_state)4352 void Document::write(const String& text,
4353 Document* entered_document,
4354 ExceptionState& exception_state) {
4355 if (ImportLoader()) {
4356 exception_state.ThrowDOMException(
4357 DOMExceptionCode::kInvalidStateError,
4358 "Imported document doesn't support write().");
4359 return;
4360 }
4361
4362 if (!IsA<HTMLDocument>(this)) {
4363 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
4364 "Only HTML documents support write().");
4365 return;
4366 }
4367
4368 if (throw_on_dynamic_markup_insertion_count_) {
4369 exception_state.ThrowDOMException(
4370 DOMExceptionCode::kInvalidStateError,
4371 "Custom Element constructor should not use write().");
4372 return;
4373 }
4374
4375 if (entered_document && !GetSecurityOrigin()->IsSameOriginWith(
4376 entered_document->GetSecurityOrigin())) {
4377 exception_state.ThrowSecurityError(
4378 "Can only call write() on same-origin documents.");
4379 return;
4380 }
4381
4382 if (ignore_opens_and_writes_for_abort_)
4383 return;
4384
4385 NestingLevelIncrementer nesting_level_incrementer(write_recursion_depth_);
4386
4387 write_recursion_is_too_deep_ =
4388 (write_recursion_depth_ > 1) && write_recursion_is_too_deep_;
4389 write_recursion_is_too_deep_ =
4390 (write_recursion_depth_ > kCMaxWriteRecursionDepth) ||
4391 write_recursion_is_too_deep_;
4392
4393 if (write_recursion_is_too_deep_)
4394 return;
4395
4396 bool has_insertion_point = parser_ && parser_->HasInsertionPoint();
4397
4398 if (!has_insertion_point) {
4399 if (ignore_destructive_write_count_) {
4400 AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
4401 mojom::ConsoleMessageSource::kJavaScript,
4402 mojom::ConsoleMessageLevel::kWarning,
4403 ExceptionMessages::FailedToExecute(
4404 "write", "Document",
4405 "It isn't possible to write into a document "
4406 "from an asynchronously-loaded external "
4407 "script unless it is explicitly opened.")));
4408 return;
4409 }
4410 if (ignore_opens_during_unload_count_)
4411 return;
4412
4413 open(entered_document, ASSERT_NO_EXCEPTION);
4414 }
4415
4416 DCHECK(parser_);
4417 PerformanceMonitor::ReportGenericViolation(
4418 domWindow(), PerformanceMonitor::kDiscouragedAPIUse,
4419 "Avoid using document.write(). "
4420 "https://developers.google.com/web/updates/2016/08/"
4421 "removing-document-write",
4422 base::TimeDelta(), nullptr);
4423 probe::BreakableLocation(domWindow(), "Document.write");
4424 parser_->insert(text);
4425 }
4426
writeln(const String & text,Document * entered_document,ExceptionState & exception_state)4427 void Document::writeln(const String& text,
4428 Document* entered_document,
4429 ExceptionState& exception_state) {
4430 write(text, entered_document, exception_state);
4431 if (exception_state.HadException())
4432 return;
4433 write("\n", entered_document);
4434 }
4435
write(v8::Isolate * isolate,const Vector<String> & text,ExceptionState & exception_state)4436 void Document::write(v8::Isolate* isolate,
4437 const Vector<String>& text,
4438 ExceptionState& exception_state) {
4439 if (!AllowedToUseDynamicMarkUpInsertion("write", exception_state))
4440 return;
4441
4442 StringBuilder builder;
4443 for (const String& string : text)
4444 builder.Append(string);
4445 String string =
4446 TrustedTypesCheckForHTML(builder.ToString(), this, exception_state);
4447 if (exception_state.HadException())
4448 return;
4449
4450 write(string, EnteredDOMWindow(isolate)->document(), exception_state);
4451 }
4452
writeln(v8::Isolate * isolate,const Vector<String> & text,ExceptionState & exception_state)4453 void Document::writeln(v8::Isolate* isolate,
4454 const Vector<String>& text,
4455 ExceptionState& exception_state) {
4456 if (!AllowedToUseDynamicMarkUpInsertion("writeln", exception_state))
4457 return;
4458
4459 StringBuilder builder;
4460 for (const String& string : text)
4461 builder.Append(string);
4462 String string =
4463 TrustedTypesCheckForHTML(builder.ToString(), this, exception_state);
4464 if (exception_state.HadException())
4465 return;
4466
4467 writeln(string, EnteredDOMWindow(isolate)->document(), exception_state);
4468 }
4469
IsTrustedTypesEnabledForDoc() const4470 bool Document::IsTrustedTypesEnabledForDoc() const {
4471 return GetExecutionContext()->RequireTrustedTypes();
4472 }
4473
write(v8::Isolate * isolate,TrustedHTML * text,ExceptionState & exception_state)4474 void Document::write(v8::Isolate* isolate,
4475 TrustedHTML* text,
4476 ExceptionState& exception_state) {
4477 DCHECK(RuntimeEnabledFeatures::TrustedDOMTypesEnabled(this));
4478 write(text->toString(), EnteredDOMWindow(isolate)->document(),
4479 exception_state);
4480 }
4481
writeln(v8::Isolate * isolate,TrustedHTML * text,ExceptionState & exception_state)4482 void Document::writeln(v8::Isolate* isolate,
4483 TrustedHTML* text,
4484 ExceptionState& exception_state) {
4485 DCHECK(RuntimeEnabledFeatures::TrustedDOMTypesEnabled(this));
4486 writeln(text->toString(), EnteredDOMWindow(isolate)->document(),
4487 exception_state);
4488 }
4489
urlForBinding() const4490 KURL Document::urlForBinding() const {
4491 if (WebBundleClaimedUrl().IsValid()) {
4492 return WebBundleClaimedUrl();
4493 }
4494 if (!Url().IsNull()) {
4495 return Url();
4496 }
4497 return BlankURL();
4498 }
4499
SetURL(const KURL & url)4500 void Document::SetURL(const KURL& url) {
4501 KURL new_url = url.IsEmpty() ? BlankURL() : url;
4502 if (new_url == url_)
4503 return;
4504
4505 // Count non-targetText occurrences of :~: in the url fragment to make sure
4506 // the delimiter is web-compatible. This can be removed once the feature
4507 // ships.
4508 wtf_size_t delim_pos = new_url.FragmentIdentifier().Find(":~:");
4509 if (delim_pos != kNotFound) {
4510 const wtf_size_t one_past_delim = delim_pos + 3;
4511 if (new_url.FragmentIdentifier().Find(kTextFragmentIdentifierPrefix,
4512 one_past_delim) != one_past_delim) {
4513 // We can't use count here because the DocumentLoader hasn't yet been
4514 // created. It'll be use counted with other delimiters in
4515 // FragmentAnchor::TryCreate.
4516 use_count_fragment_directive_ = true;
4517 }
4518 }
4519
4520 // If text fragment identifiers are enabled, we strip the fragment directive
4521 // from the URL fragment.
4522 // E.g. "#id:~:text=a" --> "#id"
4523 if (RuntimeEnabledFeatures::TextFragmentIdentifiersEnabled(this)) {
4524 String fragment = new_url.FragmentIdentifier();
4525 wtf_size_t start_pos = fragment.Find(kFragmentDirectivePrefix);
4526 if (start_pos != kNotFound) {
4527 fragment_directive_ =
4528 fragment.Substring(start_pos + kFragmentDirectivePrefixStringLength);
4529
4530 if (start_pos == 0)
4531 new_url.RemoveFragmentIdentifier();
4532 else
4533 new_url.SetFragmentIdentifier(fragment.Substring(0, start_pos));
4534 }
4535 }
4536
4537 url_ = new_url;
4538 access_entry_from_url_ = nullptr;
4539 UpdateBaseURL();
4540 GetContextFeatures().UrlDidChange(this);
4541
4542 // TODO(crbug/795354): Move handling of URL recording out of the renderer.
4543 // URL must only be recorded from the main frame.
4544 if (ukm_recorder_ && IsInMainFrame())
4545 ukm_recorder_->UpdateSourceURL(ukm_source_id_, url_);
4546
4547 if (frame_) {
4548 if (FrameScheduler* frame_scheduler = frame_->GetFrameScheduler())
4549 frame_scheduler->TraceUrlChange(url_.GetString());
4550 }
4551 }
4552
ValidBaseElementURL() const4553 KURL Document::ValidBaseElementURL() const {
4554 if (base_element_url_.IsValid())
4555 return base_element_url_;
4556
4557 return KURL();
4558 }
4559
UpdateBaseURL()4560 void Document::UpdateBaseURL() {
4561 KURL old_base_url = base_url_;
4562 // DOM 3 Core: When the Document supports the feature "HTML" [DOM Level 2
4563 // HTML], the base URI is computed using first the value of the href attribute
4564 // of the HTML BASE element if any, and the value of the documentURI attribute
4565 // from the Document interface otherwise (which we store, preparsed, in
4566 // |url_|).
4567 if (!base_element_url_.IsEmpty())
4568 base_url_ = base_element_url_;
4569 else if (!base_url_override_.IsEmpty())
4570 base_url_ = base_url_override_;
4571 else
4572 base_url_ = FallbackBaseURL();
4573
4574 GetSelectorQueryCache().Invalidate();
4575
4576 if (!base_url_.IsValid())
4577 base_url_ = KURL();
4578
4579 if (elem_sheet_) {
4580 // Element sheet is silly. It never contains anything.
4581 DCHECK(!elem_sheet_->Contents()->RuleCount());
4582 elem_sheet_ = CSSStyleSheet::CreateInline(*this, base_url_);
4583 }
4584
4585 if (!EqualIgnoringFragmentIdentifier(old_base_url, base_url_)) {
4586 // Base URL change changes any relative visited links.
4587 // FIXME: There are other URLs in the tree that would need to be
4588 // re-evaluated on dynamic base URL change. Style should be invalidated too.
4589 for (HTMLAnchorElement& anchor :
4590 Traversal<HTMLAnchorElement>::StartsAfter(*this))
4591 anchor.InvalidateCachedVisitedLinkHash();
4592 }
4593 }
4594
FallbackBaseURL() const4595 KURL Document::FallbackBaseURL() const {
4596 if (IsSrcdocDocument()) {
4597 // TODO(tkent): Referring to ParentDocument() is not correct. See
4598 // crbug.com/751329.
4599 if (Document* parent = ParentDocument())
4600 return parent->BaseURL();
4601 } else if (urlForBinding().IsAboutBlankURL()) {
4602 if (context_document_)
4603 return context_document_->BaseURL();
4604 // TODO(tkent): Referring to ParentDocument() is not correct. See
4605 // crbug.com/751329.
4606 if (Document* parent = ParentDocument())
4607 return parent->BaseURL();
4608 }
4609 return urlForBinding();
4610 }
4611
BaseURL() const4612 const KURL& Document::BaseURL() const {
4613 if (!base_url_.IsNull())
4614 return base_url_;
4615 return BlankURL();
4616 }
4617
SetBaseURLOverride(const KURL & url)4618 void Document::SetBaseURLOverride(const KURL& url) {
4619 base_url_override_ = url;
4620 UpdateBaseURL();
4621 }
4622
ProcessBaseElement()4623 void Document::ProcessBaseElement() {
4624 UseCounter::Count(*this, WebFeature::kBaseElement);
4625
4626 // Find the first href attribute in a base element and the first target
4627 // attribute in a base element.
4628 const AtomicString* href = nullptr;
4629 const AtomicString* target = nullptr;
4630 for (HTMLBaseElement* base = Traversal<HTMLBaseElement>::FirstWithin(*this);
4631 base && (!href || !target);
4632 base = Traversal<HTMLBaseElement>::Next(*base)) {
4633 if (!href) {
4634 const AtomicString& value = base->FastGetAttribute(html_names::kHrefAttr);
4635 if (!value.IsNull())
4636 href = &value;
4637 }
4638 if (!target) {
4639 const AtomicString& value =
4640 base->FastGetAttribute(html_names::kTargetAttr);
4641 if (!value.IsNull())
4642 target = &value;
4643 }
4644 if (GetContentSecurityPolicy()->IsActive()) {
4645 UseCounter::Count(*this,
4646 WebFeature::kContentSecurityPolicyWithBaseElement);
4647 }
4648 }
4649
4650 // FIXME: Since this doesn't share code with completeURL it may not handle
4651 // encodings correctly.
4652 KURL base_element_url;
4653 if (href) {
4654 String stripped_href = StripLeadingAndTrailingHTMLSpaces(*href);
4655 if (!stripped_href.IsEmpty())
4656 base_element_url = KURL(FallbackBaseURL(), stripped_href);
4657 }
4658
4659 if (!base_element_url.IsEmpty()) {
4660 if (base_element_url.ProtocolIsData() ||
4661 base_element_url.ProtocolIsJavaScript()) {
4662 UseCounter::Count(*this, WebFeature::kBaseWithDataHref);
4663 AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
4664 mojom::ConsoleMessageSource::kSecurity,
4665 mojom::ConsoleMessageLevel::kError,
4666 "'" + base_element_url.Protocol() +
4667 "' URLs may not be used as base URLs for a document."));
4668 }
4669 if (!GetSecurityOrigin()->CanRequest(base_element_url))
4670 UseCounter::Count(*this, WebFeature::kBaseWithCrossOriginHref);
4671 }
4672
4673 if (base_element_url != base_element_url_ &&
4674 !base_element_url.ProtocolIsData() &&
4675 !base_element_url.ProtocolIsJavaScript() &&
4676 GetContentSecurityPolicy()->AllowBaseURI(base_element_url)) {
4677 base_element_url_ = base_element_url;
4678 UpdateBaseURL();
4679 }
4680
4681 if (target) {
4682 if (target->Contains('\n') || target->Contains('\r'))
4683 UseCounter::Count(*this, WebFeature::kBaseWithNewlinesInTarget);
4684 if (target->Contains('<'))
4685 UseCounter::Count(*this, WebFeature::kBaseWithOpenBracketInTarget);
4686 base_target_ = *target;
4687 } else {
4688 base_target_ = g_null_atom;
4689 }
4690 }
4691
UserAgent() const4692 String Document::UserAgent() const {
4693 return GetFrame() ? GetFrame()->Loader().UserAgent() : String();
4694 }
4695
DidLoadAllImports()4696 void Document::DidLoadAllImports() {
4697 if (!HaveScriptBlockingStylesheetsLoaded())
4698 return;
4699 DidLoadAllScriptBlockingResources();
4700 }
4701
DidAddPendingParserBlockingStylesheet()4702 void Document::DidAddPendingParserBlockingStylesheet() {
4703 if (ScriptableDocumentParser* parser = GetScriptableDocumentParser())
4704 parser->DidAddPendingParserBlockingStylesheet();
4705 }
4706
DidRemoveAllPendingStylesheets()4707 void Document::DidRemoveAllPendingStylesheets() {
4708 // Only imports on master documents can trigger rendering.
4709 if (HTMLImportLoader* import = ImportLoader())
4710 import->DidRemoveAllPendingStylesheets();
4711 if (!HaveImportsLoaded())
4712 return;
4713 DidLoadAllScriptBlockingResources();
4714 }
4715
DidLoadAllPendingParserBlockingStylesheets()4716 void Document::DidLoadAllPendingParserBlockingStylesheets() {
4717 if (ScriptableDocumentParser* parser = GetScriptableDocumentParser())
4718 parser->DidLoadAllPendingParserBlockingStylesheets();
4719 }
4720
DidLoadAllScriptBlockingResources()4721 void Document::DidLoadAllScriptBlockingResources() {
4722 // Use wrapWeakPersistent because the task should not keep this Document alive
4723 // just for executing scripts.
4724 execute_scripts_waiting_for_resources_task_handle_ = PostCancellableTask(
4725 *GetTaskRunner(TaskType::kNetworking), FROM_HERE,
4726 WTF::Bind(&Document::ExecuteScriptsWaitingForResources,
4727 WrapWeakPersistent(this)));
4728
4729 if (IsA<HTMLDocument>(this) && body()) {
4730 // For HTML if we have no more stylesheets to load and we're past the body
4731 // tag, we should have something to paint so resume.
4732 BeginLifecycleUpdatesIfRenderingReady();
4733 } else if (!IsA<HTMLDocument>(this) && documentElement()) {
4734 // For non-HTML there is no body so resume as soon as the sheets are loaded.
4735 BeginLifecycleUpdatesIfRenderingReady();
4736 }
4737 }
4738
ExecuteScriptsWaitingForResources()4739 void Document::ExecuteScriptsWaitingForResources() {
4740 if (!IsScriptExecutionReady())
4741 return;
4742 if (ScriptableDocumentParser* parser = GetScriptableDocumentParser())
4743 parser->ExecuteScriptsWaitingForResources();
4744 }
4745
ElementSheet()4746 CSSStyleSheet& Document::ElementSheet() {
4747 if (!elem_sheet_)
4748 elem_sheet_ = CSSStyleSheet::CreateInline(*this, base_url_);
4749 return *elem_sheet_;
4750 }
4751
MaybeHandleHttpRefresh(const String & content,HttpRefreshType http_refresh_type)4752 void Document::MaybeHandleHttpRefresh(const String& content,
4753 HttpRefreshType http_refresh_type) {
4754 if (is_view_source_ || !frame_)
4755 return;
4756
4757 base::TimeDelta delay;
4758 String refresh_url_string;
4759 if (!ParseHTTPRefresh(content,
4760 http_refresh_type == kHttpRefreshFromMetaTag
4761 ? IsHTMLSpace<UChar>
4762 : nullptr,
4763 delay, refresh_url_string))
4764 return;
4765 KURL refresh_url =
4766 refresh_url_string.IsEmpty() ? Url() : CompleteURL(refresh_url_string);
4767
4768 if (refresh_url.ProtocolIsJavaScript()) {
4769 String message =
4770 "Refused to refresh " + url_.ElidedString() + " to a javascript: URL";
4771 AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
4772 mojom::ConsoleMessageSource::kSecurity,
4773 mojom::ConsoleMessageLevel::kError, message));
4774 return;
4775 }
4776
4777 if (http_refresh_type == kHttpRefreshFromMetaTag &&
4778 IsSandboxed(mojom::blink::WebSandboxFlags::kAutomaticFeatures)) {
4779 String message =
4780 "Refused to execute the redirect specified via '<meta "
4781 "http-equiv='refresh' content='...'>'. The document is sandboxed, and "
4782 "the 'allow-scripts' keyword is not set.";
4783 AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
4784 mojom::ConsoleMessageSource::kSecurity,
4785 mojom::ConsoleMessageLevel::kError, message));
4786 return;
4787 }
4788 if (http_refresh_type == kHttpRefreshFromHeader) {
4789 UseCounter::Count(this, WebFeature::kRefreshHeader);
4790 }
4791 http_refresh_scheduler_->Schedule(delay, refresh_url, http_refresh_type);
4792 }
4793
IsHttpRefreshScheduledWithin(base::TimeDelta interval)4794 bool Document::IsHttpRefreshScheduledWithin(base::TimeDelta interval) {
4795 return http_refresh_scheduler_->IsScheduledWithin(interval);
4796 }
4797
4798 // https://w3c.github.io/webappsec-referrer-policy/#determine-requests-referrer
OutgoingReferrer() const4799 String Document::OutgoingReferrer() const {
4800 // Step 3.1: "If environment's global object is a Window object, then"
4801
4802 // Step 3.1.1: "Let document be the associated Document of environment's
4803 // global object."
4804 const Document* referrer_document = this;
4805
4806 // Step 3.1.2: "If document's origin is an opaque origin, return no referrer."
4807 if (GetSecurityOrigin()->IsOpaque())
4808 return String();
4809
4810 // Step 3.1.3: "While document is an iframe srcdoc document, let document be
4811 // document's browsing context's browsing context container's node document."
4812 if (LocalFrame* frame = frame_) {
4813 while (frame->GetDocument()->IsSrcdocDocument()) {
4814 // Srcdoc documents must be local within the containing frame.
4815 frame = To<LocalFrame>(frame->Tree().Parent());
4816 // Srcdoc documents cannot be top-level documents, by definition,
4817 // because they need to be contained in iframes with the srcdoc.
4818 DCHECK(frame);
4819 }
4820 referrer_document = frame->GetDocument();
4821 }
4822
4823 // Step: 3.1.4: "Let referrerSource be document's URL."
4824 return referrer_document->url_.StrippedForUseAsReferrer();
4825 }
4826
GetReferrerPolicy() const4827 network::mojom::ReferrerPolicy Document::GetReferrerPolicy() const {
4828 return GetExecutionContext() ? GetExecutionContext()->GetReferrerPolicy()
4829 : network::mojom::ReferrerPolicy::kDefault;
4830 }
4831
PerformMouseEventHitTest(const HitTestRequest & request,const PhysicalOffset & document_point,const WebMouseEvent & event)4832 MouseEventWithHitTestResults Document::PerformMouseEventHitTest(
4833 const HitTestRequest& request,
4834 const PhysicalOffset& document_point,
4835 const WebMouseEvent& event) {
4836 DCHECK(!GetLayoutView() || IsA<LayoutView>(GetLayoutView()));
4837
4838 // LayoutView::hitTest causes a layout, and we don't want to hit that until
4839 // the first layout because until then, there is nothing shown on the screen -
4840 // the user can't have intentionally clicked on something belonging to this
4841 // page. Furthermore, mousemove events before the first layout should not
4842 // lead to a premature layout() happening, which could show a flash of white.
4843 // See also the similar code in EventHandler::hitTestResultAtPoint.
4844 if (!GetLayoutView() || !View() || !View()->DidFirstLayout()) {
4845 HitTestLocation location((PhysicalOffset()));
4846 return MouseEventWithHitTestResults(event, location,
4847 HitTestResult(request, location));
4848 }
4849
4850 HitTestLocation location(document_point);
4851 HitTestResult result(request, location);
4852 GetLayoutView()->HitTest(location, result);
4853
4854 if (!request.ReadOnly()) {
4855 UpdateHoverActiveState(request.Active(), !request.Move(),
4856 result.InnerElement());
4857 }
4858
4859 if (auto* canvas = DynamicTo<HTMLCanvasElement>(result.InnerNode())) {
4860 HitTestCanvasResult* hit_test_canvas_result =
4861 canvas->GetControlAndIdIfHitRegionExists(
4862 result.PointInInnerNodeFrame());
4863 if (hit_test_canvas_result->GetControl()) {
4864 result.SetInnerNode(hit_test_canvas_result->GetControl());
4865 }
4866 result.SetCanvasRegionId(hit_test_canvas_result->GetId());
4867 }
4868
4869 return MouseEventWithHitTestResults(event, location, result);
4870 }
4871
4872 // DOM Section 1.1.1
ChildTypeAllowed(NodeType type) const4873 bool Document::ChildTypeAllowed(NodeType type) const {
4874 switch (type) {
4875 case kAttributeNode:
4876 case kCdataSectionNode:
4877 case kDocumentFragmentNode:
4878 case kDocumentNode:
4879 case kTextNode:
4880 return false;
4881 case kCommentNode:
4882 case kProcessingInstructionNode:
4883 return true;
4884 case kDocumentTypeNode:
4885 case kElementNode:
4886 // Documents may contain no more than one of each of these.
4887 // (One Element and one DocumentType.)
4888 for (Node& c : NodeTraversal::ChildrenOf(*this)) {
4889 if (c.getNodeType() == type)
4890 return false;
4891 }
4892 return true;
4893 }
4894 return false;
4895 }
4896
4897 // This is an implementation of step 6 of
4898 // https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
4899 // and https://dom.spec.whatwg.org/#concept-node-replace .
4900 //
4901 // 6. If parent is a document, and any of the statements below, switched on
4902 // node, are true, throw a HierarchyRequestError.
4903 // -> DocumentFragment node
4904 // If node has more than one element child or has a Text node child.
4905 // Otherwise, if node has one element child and either parent has an element
4906 // child, child is a doctype, or child is not null and a doctype is
4907 // following child.
4908 // -> element
4909 // parent has an element child, child is a doctype, or child is not null and
4910 // a doctype is following child.
4911 // -> doctype
4912 // parent has a doctype child, child is non-null and an element is preceding
4913 // child, or child is null and parent has an element child.
4914 //
4915 // 6. If parent is a document, and any of the statements below, switched on
4916 // node, are true, throw a HierarchyRequestError.
4917 // -> DocumentFragment node
4918 // If node has more than one element child or has a Text node child.
4919 // Otherwise, if node has one element child and either parent has an element
4920 // child that is not child or a doctype is following child.
4921 // -> element
4922 // parent has an element child that is not child or a doctype is following
4923 // child.
4924 // -> doctype
4925 // parent has a doctype child that is not child, or an element is preceding
4926 // child.
CanAcceptChild(const Node & new_child,const Node * next,const Node * old_child,ExceptionState & exception_state) const4927 bool Document::CanAcceptChild(const Node& new_child,
4928 const Node* next,
4929 const Node* old_child,
4930 ExceptionState& exception_state) const {
4931 DCHECK(!(next && old_child));
4932 if (old_child && old_child->getNodeType() == new_child.getNodeType())
4933 return true;
4934
4935 int num_doctypes = 0;
4936 int num_elements = 0;
4937 bool has_doctype_after_reference_node = false;
4938 bool has_element_after_reference_node = false;
4939
4940 // First, check how many doctypes and elements we have, not counting
4941 // the child we're about to remove.
4942 bool saw_reference_node = false;
4943 for (Node& child : NodeTraversal::ChildrenOf(*this)) {
4944 if (old_child && *old_child == child) {
4945 saw_reference_node = true;
4946 continue;
4947 }
4948 if (&child == next)
4949 saw_reference_node = true;
4950
4951 switch (child.getNodeType()) {
4952 case kDocumentTypeNode:
4953 num_doctypes++;
4954 has_doctype_after_reference_node = saw_reference_node;
4955 break;
4956 case kElementNode:
4957 num_elements++;
4958 has_element_after_reference_node = saw_reference_node;
4959 break;
4960 default:
4961 break;
4962 }
4963 }
4964
4965 // Then, see how many doctypes and elements might be added by the new child.
4966 if (auto* new_child_fragment = DynamicTo<DocumentFragment>(new_child)) {
4967 for (Node& child : NodeTraversal::ChildrenOf(*new_child_fragment)) {
4968 switch (child.getNodeType()) {
4969 case kAttributeNode:
4970 case kCdataSectionNode:
4971 case kDocumentFragmentNode:
4972 case kDocumentNode:
4973 case kTextNode:
4974 exception_state.ThrowDOMException(
4975 DOMExceptionCode::kHierarchyRequestError,
4976 "Nodes of type '" + new_child.nodeName() +
4977 "' may not be inserted inside nodes of type '#document'.");
4978 return false;
4979 case kCommentNode:
4980 case kProcessingInstructionNode:
4981 break;
4982 case kDocumentTypeNode:
4983 num_doctypes++;
4984 break;
4985 case kElementNode:
4986 num_elements++;
4987 if (has_doctype_after_reference_node) {
4988 exception_state.ThrowDOMException(
4989 DOMExceptionCode::kHierarchyRequestError,
4990 "Can't insert an element before a doctype.");
4991 return false;
4992 }
4993 break;
4994 }
4995 }
4996 } else {
4997 switch (new_child.getNodeType()) {
4998 case kAttributeNode:
4999 case kCdataSectionNode:
5000 case kDocumentFragmentNode:
5001 case kDocumentNode:
5002 case kTextNode:
5003 exception_state.ThrowDOMException(
5004 DOMExceptionCode::kHierarchyRequestError,
5005 "Nodes of type '" + new_child.nodeName() +
5006 "' may not be inserted inside nodes of type '#document'.");
5007 return false;
5008 case kCommentNode:
5009 case kProcessingInstructionNode:
5010 return true;
5011 case kDocumentTypeNode:
5012 num_doctypes++;
5013 if (num_elements > 0 && !has_element_after_reference_node) {
5014 exception_state.ThrowDOMException(
5015 DOMExceptionCode::kHierarchyRequestError,
5016 "Can't insert a doctype before the root element.");
5017 return false;
5018 }
5019 break;
5020 case kElementNode:
5021 num_elements++;
5022 if (has_doctype_after_reference_node) {
5023 exception_state.ThrowDOMException(
5024 DOMExceptionCode::kHierarchyRequestError,
5025 "Can't insert an element before a doctype.");
5026 return false;
5027 }
5028 break;
5029 }
5030 }
5031
5032 if (num_elements > 1 || num_doctypes > 1) {
5033 exception_state.ThrowDOMException(
5034 DOMExceptionCode::kHierarchyRequestError,
5035 String::Format("Only one %s on document allowed.",
5036 num_elements > 1 ? "element" : "doctype"));
5037 return false;
5038 }
5039
5040 return true;
5041 }
5042
Clone(Document & factory,CloneChildrenFlag flag) const5043 Node* Document::Clone(Document& factory, CloneChildrenFlag flag) const {
5044 DCHECK_EQ(this, &factory)
5045 << "Document::Clone() doesn't support importNode mode.";
5046 Document* clone = CloneDocumentWithoutChildren();
5047 clone->CloneDataFromDocument(*this);
5048 if (flag == CloneChildrenFlag::kClone)
5049 clone->CloneChildNodesFrom(*this);
5050 return clone;
5051 }
5052
CloneDocumentWithoutChildren() const5053 Document* Document::CloneDocumentWithoutChildren() const {
5054 DocumentInit init = DocumentInit::Create()
5055 .WithContextDocument(ContextDocument())
5056 .WithOwnerDocument(const_cast<Document*>(this))
5057 .WithURL(Url());
5058 if (IsA<XMLDocument>(this)) {
5059 if (IsXHTMLDocument())
5060 return XMLDocument::CreateXHTML(
5061 init.WithRegistrationContext(RegistrationContext()));
5062 return MakeGarbageCollected<XMLDocument>(init);
5063 }
5064 return MakeGarbageCollected<Document>(init);
5065 }
5066
CloneDataFromDocument(const Document & other)5067 void Document::CloneDataFromDocument(const Document& other) {
5068 SetCompatibilityMode(other.GetCompatibilityMode());
5069 SetEncodingData(other.encoding_data_);
5070 SetContextFeatures(other.GetContextFeatures());
5071 SetMimeType(other.contentType());
5072 }
5073
StyleSheets()5074 StyleSheetList& Document::StyleSheets() {
5075 if (!style_sheet_list_)
5076 style_sheet_list_ = MakeGarbageCollected<StyleSheetList>(this);
5077 return *style_sheet_list_;
5078 }
5079
EvaluateMediaQueryListIfNeeded()5080 void Document::EvaluateMediaQueryListIfNeeded() {
5081 if (!evaluate_media_queries_on_style_recalc_)
5082 return;
5083 EvaluateMediaQueryList();
5084 evaluate_media_queries_on_style_recalc_ = false;
5085 }
5086
EvaluateMediaQueryList()5087 void Document::EvaluateMediaQueryList() {
5088 if (media_query_matcher_)
5089 media_query_matcher_->MediaFeaturesChanged();
5090 }
5091
SetResizedForViewportUnits()5092 void Document::SetResizedForViewportUnits() {
5093 if (media_query_matcher_)
5094 media_query_matcher_->ViewportChanged();
5095 if (!HasViewportUnits())
5096 return;
5097 EnsureStyleResolver().SetResizedForViewportUnits();
5098 SetNeedsStyleRecalcForViewportUnits();
5099 }
5100
ClearResizedForViewportUnits()5101 void Document::ClearResizedForViewportUnits() {
5102 EnsureStyleResolver().ClearResizedForViewportUnits();
5103 }
5104
SetHoverElement(Element * new_hover_element)5105 void Document::SetHoverElement(Element* new_hover_element) {
5106 hover_element_ = new_hover_element;
5107 }
5108
SetActiveElement(Element * new_active_element)5109 void Document::SetActiveElement(Element* new_active_element) {
5110 if (!new_active_element) {
5111 active_element_.Clear();
5112 return;
5113 }
5114
5115 active_element_ = new_active_element;
5116 }
5117
RemoveFocusedElementOfSubtree(Node & node,bool among_children_only)5118 void Document::RemoveFocusedElementOfSubtree(Node& node,
5119 bool among_children_only) {
5120 if (!focused_element_)
5121 return;
5122
5123 // We can't be focused if we're not in the document.
5124 if (!node.isConnected())
5125 return;
5126 bool contains = node.IsShadowIncludingInclusiveAncestorOf(*focused_element_);
5127 if (contains && (focused_element_ != &node || !among_children_only))
5128 ClearFocusedElement();
5129 }
5130
SkipDisplayNoneAncestors(Element * element)5131 static Element* SkipDisplayNoneAncestors(Element* element) {
5132 for (; element; element = FlatTreeTraversal::ParentElement(*element)) {
5133 if (element->GetLayoutObject() || element->HasDisplayContentsStyle())
5134 return element;
5135 }
5136 return nullptr;
5137 }
5138
SkipDisplayNoneAncestorsOrReturnNullIfFlatTreeIsDirty(Element & element)5139 static Element* SkipDisplayNoneAncestorsOrReturnNullIfFlatTreeIsDirty(
5140 Element& element) {
5141 if (element.GetDocument().IsSlotAssignmentOrLegacyDistributionDirty()) {
5142 // We shouldn't use FlatTreeTraversal during detach if slot assignment is
5143 // dirty because it might trigger assignment recalc. The hover and active
5144 // elements are then set to null. The hover element is updated on the next
5145 // lifecycle update instead.
5146 //
5147 // TODO(crbug.com/939769): The active element is not updated on the next
5148 // lifecycle update, and is generally not correctly updated on re-slotting.
5149 return nullptr;
5150 }
5151 return SkipDisplayNoneAncestors(&element);
5152 }
5153
HoveredElementDetached(Element & element)5154 void Document::HoveredElementDetached(Element& element) {
5155 if (!hover_element_)
5156 return;
5157 if (element != hover_element_)
5158 return;
5159 hover_element_ =
5160 SkipDisplayNoneAncestorsOrReturnNullIfFlatTreeIsDirty(element);
5161
5162 // If the mouse cursor is not visible, do not clear existing
5163 // hover effects on the ancestors of |element| and do not invoke
5164 // new hover effects on any other element.
5165 if (!GetPage()->IsCursorVisible())
5166 return;
5167
5168 if (GetFrame())
5169 GetFrame()->GetEventHandler().ScheduleHoverStateUpdate();
5170 }
5171
ActiveChainNodeDetached(Element & element)5172 void Document::ActiveChainNodeDetached(Element& element) {
5173 if (active_element_ && element == active_element_) {
5174 active_element_ =
5175 SkipDisplayNoneAncestorsOrReturnNullIfFlatTreeIsDirty(element);
5176 }
5177 }
5178
AnnotatedRegions() const5179 const Vector<AnnotatedRegionValue>& Document::AnnotatedRegions() const {
5180 return annotated_regions_;
5181 }
5182
SetAnnotatedRegions(const Vector<AnnotatedRegionValue> & regions)5183 void Document::SetAnnotatedRegions(
5184 const Vector<AnnotatedRegionValue>& regions) {
5185 annotated_regions_ = regions;
5186 SetAnnotatedRegionsDirty(false);
5187 }
5188
SetLastFocusType(mojom::blink::FocusType last_focus_type)5189 void Document::SetLastFocusType(mojom::blink::FocusType last_focus_type) {
5190 last_focus_type_ = last_focus_type;
5191 }
5192
SetFocusedElement(Element * new_focused_element,const FocusParams & params)5193 bool Document::SetFocusedElement(Element* new_focused_element,
5194 const FocusParams& params) {
5195 DCHECK(!lifecycle_.InDetach());
5196
5197 clear_focused_element_timer_.Stop();
5198
5199 // Make sure new_focused_element is actually in this document.
5200 if (new_focused_element) {
5201 if (new_focused_element->GetDocument() != this)
5202 return true;
5203
5204 if (NodeChildRemovalTracker::IsBeingRemoved(*new_focused_element))
5205 return true;
5206 }
5207
5208 if (focused_element_ == new_focused_element)
5209 return true;
5210
5211 bool focus_change_blocked = false;
5212 Element* old_focused_element = focused_element_;
5213 focused_element_ = nullptr;
5214
5215 UpdateDistributionForFlatTreeTraversal();
5216 Node* ancestor = (old_focused_element && old_focused_element->isConnected() &&
5217 new_focused_element)
5218 ? FlatTreeTraversal::CommonAncestor(*old_focused_element,
5219 *new_focused_element)
5220 : nullptr;
5221
5222 // Remove focus from the existing focus node (if any)
5223 if (old_focused_element) {
5224 old_focused_element->SetFocused(false, params.type);
5225 old_focused_element->SetHasFocusWithinUpToAncestor(false, ancestor);
5226
5227 DisplayLockUtilities::ElementLostFocus(old_focused_element);
5228
5229 // Dispatch the blur event and let the node do any other blur related
5230 // activities (important for text fields)
5231 // If page lost focus, blur event will have already been dispatched
5232 if (GetPage() && (GetPage()->GetFocusController().IsFocused())) {
5233 old_focused_element->DispatchBlurEvent(new_focused_element, params.type,
5234 params.source_capabilities);
5235 if (focused_element_) {
5236 // handler shifted focus
5237 focus_change_blocked = true;
5238 new_focused_element = nullptr;
5239 }
5240
5241 // 'focusout' is a DOM level 3 name for the bubbling blur event.
5242 old_focused_element->DispatchFocusOutEvent(event_type_names::kFocusout,
5243 new_focused_element,
5244 params.source_capabilities);
5245 // 'DOMFocusOut' is a DOM level 2 name for compatibility.
5246 // FIXME: We should remove firing DOMFocusOutEvent event when we are sure
5247 // no content depends on it, probably when <rdar://problem/8503958> is
5248 // resolved.
5249 old_focused_element->DispatchFocusOutEvent(event_type_names::kDOMFocusOut,
5250 new_focused_element,
5251 params.source_capabilities);
5252
5253 if (focused_element_) {
5254 // handler shifted focus
5255 focus_change_blocked = true;
5256 new_focused_element = nullptr;
5257 }
5258 }
5259 }
5260
5261 if (new_focused_element)
5262 UpdateStyleAndLayoutTreeForNode(new_focused_element);
5263 if (new_focused_element && new_focused_element->IsFocusable()) {
5264 if (IsRootEditableElement(*new_focused_element) &&
5265 !AcceptsEditingFocus(*new_focused_element)) {
5266 // delegate blocks focus change
5267 UpdateStyleAndLayoutTree();
5268 if (LocalFrame* frame = GetFrame())
5269 frame->Selection().DidChangeFocus();
5270 return false;
5271 }
5272 // Set focus on the new node
5273 focused_element_ = new_focused_element;
5274 SetSequentialFocusNavigationStartingPoint(focused_element_.Get());
5275
5276 // Keep track of last focus from user interaction, ignoring focus from code.
5277 if (params.type != mojom::blink::FocusType::kNone)
5278 last_focus_type_ = params.type;
5279
5280 focused_element_->SetFocused(true, params.type);
5281 focused_element_->SetHasFocusWithinUpToAncestor(true, ancestor);
5282 DisplayLockUtilities::ElementGainedFocus(focused_element_.Get());
5283
5284 // Element::setFocused for frames can dispatch events.
5285 if (focused_element_ != new_focused_element) {
5286 UpdateStyleAndLayoutTree();
5287 if (LocalFrame* frame = GetFrame())
5288 frame->Selection().DidChangeFocus();
5289 return false;
5290 }
5291 CancelFocusAppearanceUpdate();
5292 EnsurePaintLocationDataValidForNode(focused_element_,
5293 DocumentUpdateReason::kFocus);
5294 focused_element_->UpdateFocusAppearanceWithOptions(
5295 params.selection_behavior, params.options);
5296
5297 // Dispatch the focus event and let the node do any other focus related
5298 // activities (important for text fields)
5299 // If page lost focus, event will be dispatched on page focus, don't
5300 // duplicate
5301 if (GetPage() && (GetPage()->GetFocusController().IsFocused())) {
5302 focused_element_->DispatchFocusEvent(old_focused_element, params.type,
5303 params.source_capabilities);
5304
5305 if (focused_element_ != new_focused_element) {
5306 // handler shifted focus
5307 UpdateStyleAndLayoutTree();
5308 if (LocalFrame* frame = GetFrame())
5309 frame->Selection().DidChangeFocus();
5310 return false;
5311 }
5312 // DOM level 3 bubbling focus event.
5313 focused_element_->DispatchFocusInEvent(event_type_names::kFocusin,
5314 old_focused_element, params.type,
5315 params.source_capabilities);
5316
5317 if (focused_element_ != new_focused_element) {
5318 // handler shifted focus
5319 UpdateStyleAndLayoutTree();
5320 if (LocalFrame* frame = GetFrame())
5321 frame->Selection().DidChangeFocus();
5322 return false;
5323 }
5324
5325 // For DOM level 2 compatibility.
5326 // FIXME: We should remove firing DOMFocusInEvent event when we are sure
5327 // no content depends on it, probably when <rdar://problem/8503958> is m.
5328 focused_element_->DispatchFocusInEvent(event_type_names::kDOMFocusIn,
5329 old_focused_element, params.type,
5330 params.source_capabilities);
5331
5332 if (focused_element_ != new_focused_element) {
5333 // handler shifted focus
5334 UpdateStyleAndLayoutTree();
5335 if (LocalFrame* frame = GetFrame())
5336 frame->Selection().DidChangeFocus();
5337 return false;
5338 }
5339 }
5340 }
5341
5342 if (!focus_change_blocked)
5343 NotifyFocusedElementChanged(old_focused_element, focused_element_.Get());
5344
5345 UpdateStyleAndLayoutTree();
5346 if (LocalFrame* frame = GetFrame())
5347 frame->Selection().DidChangeFocus();
5348 return !focus_change_blocked;
5349 }
5350
ClearFocusedElement()5351 void Document::ClearFocusedElement() {
5352 SetFocusedElement(nullptr,
5353 FocusParams(SelectionBehaviorOnFocus::kNone,
5354 mojom::blink::FocusType::kNone, nullptr));
5355 }
5356
NotifyFocusedElementChanged(Element * old_focused_element,Element * new_focused_element)5357 void Document::NotifyFocusedElementChanged(Element* old_focused_element,
5358 Element* new_focused_element) {
5359 // |old_focused_element| may not belong to this document by invoking
5360 // adoptNode in event handlers during moving the focus to the new element.
5361 DCHECK(!new_focused_element || new_focused_element->GetDocument() == this);
5362
5363 if (AXObjectCache* cache = ExistingAXObjectCache()) {
5364 cache->HandleFocusedUIElementChanged(old_focused_element,
5365 new_focused_element);
5366 }
5367
5368 if (GetPage()) {
5369 GetPage()->GetValidationMessageClient().DidChangeFocusTo(
5370 new_focused_element);
5371
5372 bool is_editable = false;
5373 gfx::Rect element_bounds;
5374 if (new_focused_element) {
5375 IntRect rect = new_focused_element->BoundsInViewport();
5376 View()->FrameToScreen(rect);
5377 is_editable = IsEditableElement(*new_focused_element);
5378 element_bounds = gfx::Rect(rect);
5379 }
5380
5381 GetFrame()->GetLocalFrameHostRemote().FocusedElementChanged(is_editable,
5382 element_bounds);
5383
5384 Document* old_document =
5385 old_focused_element ? &old_focused_element->GetDocument() : nullptr;
5386 if (old_document && old_document != this && old_document->GetFrame())
5387 old_document->GetFrame()->Client()->FocusedElementChanged(nullptr);
5388
5389 GetFrame()->Client()->FocusedElementChanged(new_focused_element);
5390
5391 GetPage()->GetChromeClient().SetKeyboardFocusURL(new_focused_element);
5392
5393 if (GetSettings()->GetSpatialNavigationEnabled())
5394 GetPage()->GetSpatialNavigationController().FocusedNodeChanged(this);
5395 }
5396 }
5397
SetSequentialFocusNavigationStartingPoint(Node * node)5398 void Document::SetSequentialFocusNavigationStartingPoint(Node* node) {
5399 if (!frame_)
5400 return;
5401 if (!node) {
5402 sequential_focus_navigation_starting_point_ = nullptr;
5403 return;
5404 }
5405 DCHECK_EQ(node->GetDocument(), this);
5406 if (!sequential_focus_navigation_starting_point_)
5407 sequential_focus_navigation_starting_point_ = Range::Create(*this);
5408 sequential_focus_navigation_starting_point_->selectNodeContents(
5409 node, ASSERT_NO_EXCEPTION);
5410 }
5411
SequentialFocusNavigationStartingPoint(mojom::blink::FocusType type) const5412 Element* Document::SequentialFocusNavigationStartingPoint(
5413 mojom::blink::FocusType type) const {
5414 if (focused_element_)
5415 return focused_element_.Get();
5416 if (!sequential_focus_navigation_starting_point_)
5417 return nullptr;
5418 DCHECK(sequential_focus_navigation_starting_point_->IsConnected());
5419 if (!sequential_focus_navigation_starting_point_->collapsed()) {
5420 Node* node = sequential_focus_navigation_starting_point_->startContainer();
5421 DCHECK_EQ(node,
5422 sequential_focus_navigation_starting_point_->endContainer());
5423 if (auto* element = DynamicTo<Element>(node))
5424 return element;
5425 if (Element* neighbor_element = type == mojom::blink::FocusType::kForward
5426 ? ElementTraversal::Previous(*node)
5427 : ElementTraversal::Next(*node))
5428 return neighbor_element;
5429 return node->ParentOrShadowHostElement();
5430 }
5431
5432 // Range::selectNodeContents didn't select contents because the element had
5433 // no children.
5434 auto* element = DynamicTo<Element>(
5435 sequential_focus_navigation_starting_point_->startContainer());
5436 if (element && !element->hasChildren() &&
5437 sequential_focus_navigation_starting_point_->startOffset() == 0)
5438 return element;
5439
5440 // A node selected by Range::selectNodeContents was removed from the
5441 // document tree.
5442 if (Node* next_node =
5443 sequential_focus_navigation_starting_point_->FirstNode()) {
5444 if (next_node->IsShadowRoot())
5445 return next_node->OwnerShadowHost();
5446 // TODO(tkent): Using FlatTreeTraversal is inconsistent with
5447 // FocusController. Ideally we should find backward/forward focusable
5448 // elements before the starting point is disconnected. crbug.com/606582
5449 if (type == mojom::blink::FocusType::kForward) {
5450 Node* previous = FlatTreeTraversal::Previous(*next_node);
5451 for (; previous; previous = FlatTreeTraversal::Previous(*previous)) {
5452 if (auto* element = DynamicTo<Element>(previous))
5453 return element;
5454 }
5455 }
5456 for (Node* next = next_node; next; next = FlatTreeTraversal::Next(*next)) {
5457 if (auto* element = DynamicTo<Element>(next))
5458 return element;
5459 }
5460 }
5461 return nullptr;
5462 }
5463
SetCSSTarget(Element * new_target)5464 void Document::SetCSSTarget(Element* new_target) {
5465 if (css_target_)
5466 css_target_->PseudoStateChanged(CSSSelector::kPseudoTarget);
5467 css_target_ = new_target;
5468 if (css_target_)
5469 css_target_->PseudoStateChanged(CSSSelector::kPseudoTarget);
5470 }
5471
RegisterNodeList(const LiveNodeListBase * list)5472 void Document::RegisterNodeList(const LiveNodeListBase* list) {
5473 node_lists_.Add(list, list->InvalidationType());
5474 if (list->IsRootedAtTreeScope())
5475 lists_invalidated_at_document_.insert(list);
5476 }
5477
UnregisterNodeList(const LiveNodeListBase * list)5478 void Document::UnregisterNodeList(const LiveNodeListBase* list) {
5479 node_lists_.Remove(list, list->InvalidationType());
5480 if (list->IsRootedAtTreeScope()) {
5481 DCHECK(lists_invalidated_at_document_.Contains(list));
5482 lists_invalidated_at_document_.erase(list);
5483 }
5484 }
5485
RegisterNodeListWithIdNameCache(const LiveNodeListBase * list)5486 void Document::RegisterNodeListWithIdNameCache(const LiveNodeListBase* list) {
5487 node_lists_.Add(list, kInvalidateOnIdNameAttrChange);
5488 }
5489
UnregisterNodeListWithIdNameCache(const LiveNodeListBase * list)5490 void Document::UnregisterNodeListWithIdNameCache(const LiveNodeListBase* list) {
5491 node_lists_.Remove(list, kInvalidateOnIdNameAttrChange);
5492 }
5493
AttachNodeIterator(NodeIterator * ni)5494 void Document::AttachNodeIterator(NodeIterator* ni) {
5495 node_iterators_.insert(ni);
5496 }
5497
DetachNodeIterator(NodeIterator * ni)5498 void Document::DetachNodeIterator(NodeIterator* ni) {
5499 // The node iterator can be detached without having been attached if its root
5500 // node didn't have a document when the iterator was created, but has it now.
5501 node_iterators_.erase(ni);
5502 }
5503
MoveNodeIteratorsToNewDocument(Node & node,Document & new_document)5504 void Document::MoveNodeIteratorsToNewDocument(Node& node,
5505 Document& new_document) {
5506 HeapHashSet<WeakMember<NodeIterator>> node_iterators_list = node_iterators_;
5507 for (NodeIterator* ni : node_iterators_list) {
5508 if (ni->root() == node) {
5509 DetachNodeIterator(ni);
5510 new_document.AttachNodeIterator(ni);
5511 }
5512 }
5513 }
5514
DidMoveTreeToNewDocument(const Node & root)5515 void Document::DidMoveTreeToNewDocument(const Node& root) {
5516 DCHECK_NE(root.GetDocument(), this);
5517 if (!ranges_.IsEmpty()) {
5518 AttachedRangeSet ranges = ranges_;
5519 for (Range* range : ranges)
5520 range->UpdateOwnerDocumentIfNeeded();
5521 }
5522 synchronous_mutation_observer_list_.ForEachObserver(
5523 [&](SynchronousMutationObserver* observer) {
5524 observer->DidMoveTreeToNewDocument(root);
5525 });
5526 }
5527
NodeChildrenWillBeRemoved(ContainerNode & container)5528 void Document::NodeChildrenWillBeRemoved(ContainerNode& container) {
5529 EventDispatchForbiddenScope assert_no_event_dispatch;
5530 for (Range* range : ranges_) {
5531 range->NodeChildrenWillBeRemoved(container);
5532 if (range == sequential_focus_navigation_starting_point_)
5533 range->FixupRemovedChildrenAcrossShadowBoundary(container);
5534 }
5535
5536 for (NodeIterator* ni : node_iterators_) {
5537 for (Node& n : NodeTraversal::ChildrenOf(container))
5538 ni->NodeWillBeRemoved(n);
5539 }
5540
5541 synchronous_mutation_observer_list_.ForEachObserver(
5542 [&](SynchronousMutationObserver* observer) {
5543 observer->NodeChildrenWillBeRemoved(container);
5544 });
5545
5546 if (ContainsV1ShadowTree()) {
5547 for (Node& n : NodeTraversal::ChildrenOf(container))
5548 n.CheckSlotChangeBeforeRemoved();
5549 }
5550 }
5551
NodeWillBeRemoved(Node & n)5552 void Document::NodeWillBeRemoved(Node& n) {
5553 for (NodeIterator* ni : node_iterators_)
5554 ni->NodeWillBeRemoved(n);
5555
5556 for (Range* range : ranges_) {
5557 range->NodeWillBeRemoved(n);
5558 if (range == sequential_focus_navigation_starting_point_)
5559 range->FixupRemovedNodeAcrossShadowBoundary(n);
5560 }
5561
5562 synchronous_mutation_observer_list_.ForEachObserver(
5563 [&](SynchronousMutationObserver* observer) {
5564 observer->NodeWillBeRemoved(n);
5565 });
5566
5567 if (ContainsV1ShadowTree())
5568 n.CheckSlotChangeBeforeRemoved();
5569
5570 if (n.InActiveDocument())
5571 GetStyleEngine().NodeWillBeRemoved(n);
5572 }
5573
NotifyUpdateCharacterData(CharacterData * character_data,unsigned offset,unsigned old_length,unsigned new_length)5574 void Document::NotifyUpdateCharacterData(CharacterData* character_data,
5575 unsigned offset,
5576 unsigned old_length,
5577 unsigned new_length) {
5578 synchronous_mutation_observer_list_.ForEachObserver(
5579 [&](SynchronousMutationObserver* observer) {
5580 observer->DidUpdateCharacterData(character_data, offset, old_length,
5581 new_length);
5582 });
5583 }
5584
NotifyChangeChildren(const ContainerNode & container)5585 void Document::NotifyChangeChildren(const ContainerNode& container) {
5586 synchronous_mutation_observer_list_.ForEachObserver(
5587 [&](SynchronousMutationObserver* observer) {
5588 observer->DidChangeChildren(container);
5589 });
5590 }
5591
DidInsertText(const CharacterData & text,unsigned offset,unsigned length)5592 void Document::DidInsertText(const CharacterData& text,
5593 unsigned offset,
5594 unsigned length) {
5595 for (Range* range : ranges_)
5596 range->DidInsertText(text, offset, length);
5597 }
5598
DidRemoveText(const CharacterData & text,unsigned offset,unsigned length)5599 void Document::DidRemoveText(const CharacterData& text,
5600 unsigned offset,
5601 unsigned length) {
5602 for (Range* range : ranges_)
5603 range->DidRemoveText(text, offset, length);
5604 }
5605
DidMergeTextNodes(const Text & merged_node,const Text & node_to_be_removed,unsigned old_length)5606 void Document::DidMergeTextNodes(const Text& merged_node,
5607 const Text& node_to_be_removed,
5608 unsigned old_length) {
5609 NodeWithIndex node_to_be_removed_with_index(
5610 const_cast<Text&>(node_to_be_removed));
5611 if (!ranges_.IsEmpty()) {
5612 for (Range* range : ranges_)
5613 range->DidMergeTextNodes(node_to_be_removed_with_index, old_length);
5614 }
5615
5616 synchronous_mutation_observer_list_.ForEachObserver(
5617 [&](SynchronousMutationObserver* observer) {
5618 observer->DidMergeTextNodes(merged_node, node_to_be_removed_with_index,
5619 old_length);
5620 });
5621
5622 // FIXME: This should update markers for spelling and grammar checking.
5623 }
5624
DidSplitTextNode(const Text & old_node)5625 void Document::DidSplitTextNode(const Text& old_node) {
5626 for (Range* range : ranges_)
5627 range->DidSplitTextNode(old_node);
5628
5629 synchronous_mutation_observer_list_.ForEachObserver(
5630 [&](SynchronousMutationObserver* observer) {
5631 observer->DidSplitTextNode(old_node);
5632 });
5633
5634 // FIXME: This should update markers for spelling and grammar checking.
5635 }
5636
SetWindowAttributeEventListener(const AtomicString & event_type,EventListener * listener)5637 void Document::SetWindowAttributeEventListener(const AtomicString& event_type,
5638 EventListener* listener) {
5639 LocalDOMWindow* dom_window = domWindow();
5640 if (!dom_window)
5641 return;
5642 dom_window->SetAttributeEventListener(event_type, listener);
5643 }
5644
GetWindowAttributeEventListener(const AtomicString & event_type)5645 EventListener* Document::GetWindowAttributeEventListener(
5646 const AtomicString& event_type) {
5647 LocalDOMWindow* dom_window = domWindow();
5648 if (!dom_window)
5649 return nullptr;
5650 return dom_window->GetAttributeEventListener(event_type);
5651 }
5652
EnqueueDisplayLockActivationTask(base::OnceClosure task)5653 void Document::EnqueueDisplayLockActivationTask(base::OnceClosure task) {
5654 scripted_animation_controller_->EnqueueTask(std::move(task));
5655 }
5656
EnqueueAnimationFrameTask(base::OnceClosure task)5657 void Document::EnqueueAnimationFrameTask(base::OnceClosure task) {
5658 scripted_animation_controller_->EnqueueTask(std::move(task));
5659 }
5660
EnqueueAnimationFrameEvent(Event * event)5661 void Document::EnqueueAnimationFrameEvent(Event* event) {
5662 scripted_animation_controller_->EnqueueEvent(event);
5663 }
5664
EnqueueUniqueAnimationFrameEvent(Event * event)5665 void Document::EnqueueUniqueAnimationFrameEvent(Event* event) {
5666 scripted_animation_controller_->EnqueuePerFrameEvent(event);
5667 }
5668
EnqueueScrollEventForNode(Node * target)5669 void Document::EnqueueScrollEventForNode(Node* target) {
5670 // Per the W3C CSSOM View Module only scroll events fired at the document
5671 // should bubble.
5672 overscroll_accumulated_delta_x_ = overscroll_accumulated_delta_y_ = 0;
5673 Event* scroll_event = target->IsDocumentNode()
5674 ? Event::CreateBubble(event_type_names::kScroll)
5675 : Event::Create(event_type_names::kScroll);
5676 scroll_event->SetTarget(target);
5677 scripted_animation_controller_->EnqueuePerFrameEvent(scroll_event);
5678 }
5679
EnqueueScrollEndEventForNode(Node * target)5680 void Document::EnqueueScrollEndEventForNode(Node* target) {
5681 // Mimic bubbling behavior of scroll event for consistency.
5682 overscroll_accumulated_delta_x_ = overscroll_accumulated_delta_y_ = 0;
5683 Event* scroll_end_event =
5684 target->IsDocumentNode()
5685 ? Event::CreateBubble(event_type_names::kScrollend)
5686 : Event::Create(event_type_names::kScrollend);
5687 scroll_end_event->SetTarget(target);
5688 scripted_animation_controller_->EnqueuePerFrameEvent(scroll_end_event);
5689 }
5690
EnqueueOverscrollEventForNode(Node * target,double delta_x,double delta_y)5691 void Document::EnqueueOverscrollEventForNode(Node* target,
5692 double delta_x,
5693 double delta_y) {
5694 // Mimic bubbling behavior of scroll event for consistency.
5695 overscroll_accumulated_delta_x_ += delta_x;
5696 overscroll_accumulated_delta_y_ += delta_y;
5697 bool bubbles = target->IsDocumentNode();
5698 Event* overscroll_event = OverscrollEvent::Create(
5699 event_type_names::kOverscroll, bubbles, overscroll_accumulated_delta_x_,
5700 overscroll_accumulated_delta_y_);
5701 overscroll_event->SetTarget(target);
5702 scripted_animation_controller_->EnqueuePerFrameEvent(overscroll_event);
5703 }
5704
EnqueueResizeEvent()5705 void Document::EnqueueResizeEvent() {
5706 Event* event = Event::Create(event_type_names::kResize);
5707 event->SetTarget(domWindow());
5708 scripted_animation_controller_->EnqueuePerFrameEvent(event);
5709 }
5710
EnqueueMediaQueryChangeListeners(HeapVector<Member<MediaQueryListListener>> & listeners)5711 void Document::EnqueueMediaQueryChangeListeners(
5712 HeapVector<Member<MediaQueryListListener>>& listeners) {
5713 scripted_animation_controller_->EnqueueMediaQueryChangeListeners(listeners);
5714 }
5715
EnqueueVisualViewportScrollEvent()5716 void Document::EnqueueVisualViewportScrollEvent() {
5717 VisualViewportScrollEvent* event =
5718 MakeGarbageCollected<VisualViewportScrollEvent>();
5719 event->SetTarget(domWindow()->visualViewport());
5720 scripted_animation_controller_->EnqueuePerFrameEvent(event);
5721 }
5722
EnqueueVisualViewportResizeEvent()5723 void Document::EnqueueVisualViewportResizeEvent() {
5724 VisualViewportResizeEvent* event =
5725 MakeGarbageCollected<VisualViewportResizeEvent>();
5726 event->SetTarget(domWindow()->visualViewport());
5727 scripted_animation_controller_->EnqueuePerFrameEvent(event);
5728 }
5729
DispatchEventsForPrinting()5730 void Document::DispatchEventsForPrinting() {
5731 scripted_animation_controller_->DispatchEventsAndCallbacksForPrinting();
5732 }
5733
EventFactories()5734 Document::EventFactorySet& Document::EventFactories() {
5735 DEFINE_STATIC_LOCAL(EventFactorySet, event_factory, ());
5736 return event_factory;
5737 }
5738
AccessEntryFromURL()5739 const OriginAccessEntry& Document::AccessEntryFromURL() {
5740 if (!access_entry_from_url_) {
5741 access_entry_from_url_ = std::make_unique<OriginAccessEntry>(
5742 Url(), network::mojom::CorsDomainMatchMode::kAllowRegistrableDomains);
5743 }
5744 return *access_entry_from_url_;
5745 }
5746
SendDidEditFieldInInsecureContext()5747 void Document::SendDidEditFieldInInsecureContext() {
5748 if (!GetFrame())
5749 return;
5750
5751 mojo::Remote<mojom::blink::InsecureInputService> insecure_input_service;
5752 GetFrame()->GetBrowserInterfaceBroker().GetInterface(
5753 insecure_input_service.BindNewPipeAndPassReceiver());
5754
5755 insecure_input_service->DidEditFieldInInsecureContext();
5756 }
5757
RegisterEventFactory(std::unique_ptr<EventFactoryBase> event_factory)5758 void Document::RegisterEventFactory(
5759 std::unique_ptr<EventFactoryBase> event_factory) {
5760 DCHECK(!EventFactories().Contains(event_factory.get()));
5761 EventFactories().insert(std::move(event_factory));
5762 }
5763
createEvent(ScriptState * script_state,const String & event_type,ExceptionState & exception_state)5764 Event* Document::createEvent(ScriptState* script_state,
5765 const String& event_type,
5766 ExceptionState& exception_state) {
5767 Event* event = nullptr;
5768 ExecutionContext* execution_context = ExecutionContext::From(script_state);
5769 for (const auto& factory : EventFactories()) {
5770 event = factory->Create(execution_context, event_type);
5771 if (event) {
5772 // createEvent for TouchEvent should throw DOM exception if touch event
5773 // feature detection is not enabled. See crbug.com/392584#c22
5774 if (EqualIgnoringASCIICase(event_type, "TouchEvent") &&
5775 !RuntimeEnabledFeatures::TouchEventFeatureDetectionEnabled(
5776 execution_context))
5777 break;
5778 return event;
5779 }
5780 }
5781 exception_state.ThrowDOMException(
5782 DOMExceptionCode::kNotSupportedError,
5783 "The provided event type ('" + event_type + "') is invalid.");
5784 return nullptr;
5785 }
5786
AddMutationEventListenerTypeIfEnabled(ListenerType listener_type)5787 void Document::AddMutationEventListenerTypeIfEnabled(
5788 ListenerType listener_type) {
5789 if (ContextFeatures::MutationEventsEnabled(this))
5790 AddListenerType(listener_type);
5791 }
5792
AddListenerTypeIfNeeded(const AtomicString & event_type,EventTarget & event_target)5793 void Document::AddListenerTypeIfNeeded(const AtomicString& event_type,
5794 EventTarget& event_target) {
5795 if (event_type == event_type_names::kDOMSubtreeModified) {
5796 UseCounter::Count(*this, WebFeature::kDOMSubtreeModifiedEvent);
5797 AddMutationEventListenerTypeIfEnabled(kDOMSubtreeModifiedListener);
5798 } else if (event_type == event_type_names::kDOMNodeInserted) {
5799 UseCounter::Count(*this, WebFeature::kDOMNodeInsertedEvent);
5800 AddMutationEventListenerTypeIfEnabled(kDOMNodeInsertedListener);
5801 } else if (event_type == event_type_names::kDOMNodeRemoved) {
5802 UseCounter::Count(*this, WebFeature::kDOMNodeRemovedEvent);
5803 AddMutationEventListenerTypeIfEnabled(kDOMNodeRemovedListener);
5804 } else if (event_type == event_type_names::kDOMNodeRemovedFromDocument) {
5805 UseCounter::Count(*this, WebFeature::kDOMNodeRemovedFromDocumentEvent);
5806 AddMutationEventListenerTypeIfEnabled(kDOMNodeRemovedFromDocumentListener);
5807 } else if (event_type == event_type_names::kDOMNodeInsertedIntoDocument) {
5808 UseCounter::Count(*this, WebFeature::kDOMNodeInsertedIntoDocumentEvent);
5809 AddMutationEventListenerTypeIfEnabled(kDOMNodeInsertedIntoDocumentListener);
5810 } else if (event_type == event_type_names::kDOMCharacterDataModified) {
5811 UseCounter::Count(*this, WebFeature::kDOMCharacterDataModifiedEvent);
5812 AddMutationEventListenerTypeIfEnabled(kDOMCharacterDataModifiedListener);
5813 } else if (event_type == event_type_names::kWebkitAnimationStart ||
5814 event_type == event_type_names::kAnimationstart) {
5815 AddListenerType(kAnimationStartListener);
5816 } else if (event_type == event_type_names::kWebkitAnimationEnd ||
5817 event_type == event_type_names::kAnimationend) {
5818 AddListenerType(kAnimationEndListener);
5819 } else if (event_type == event_type_names::kWebkitAnimationIteration ||
5820 event_type == event_type_names::kAnimationiteration) {
5821 AddListenerType(kAnimationIterationListener);
5822 if (View()) {
5823 // Need to re-evaluate time-to-effect-change for any running animations.
5824 View()->ScheduleAnimation();
5825 }
5826 } else if (event_type == event_type_names::kAnimationcancel) {
5827 AddListenerType(kAnimationCancelListener);
5828 } else if (event_type == event_type_names::kTransitioncancel) {
5829 AddListenerType(kTransitionCancelListener);
5830 } else if (event_type == event_type_names::kTransitionrun) {
5831 AddListenerType(kTransitionRunListener);
5832 } else if (event_type == event_type_names::kTransitionstart) {
5833 AddListenerType(kTransitionStartListener);
5834 } else if (event_type == event_type_names::kWebkitTransitionEnd ||
5835 event_type == event_type_names::kTransitionend) {
5836 AddListenerType(kTransitionEndListener);
5837 } else if (event_type == event_type_names::kScroll) {
5838 AddListenerType(kScrollListener);
5839 } else if (event_type == event_type_names::kLoad) {
5840 if (Node* node = event_target.ToNode()) {
5841 if (IsA<HTMLStyleElement>(*node)) {
5842 AddListenerType(kLoadListenerAtCapturePhaseOrAtStyleElement);
5843 return;
5844 }
5845 }
5846 if (event_target.HasCapturingEventListeners(event_type))
5847 AddListenerType(kLoadListenerAtCapturePhaseOrAtStyleElement);
5848 }
5849 }
5850
LocalOwner() const5851 HTMLFrameOwnerElement* Document::LocalOwner() const {
5852 if (!GetFrame())
5853 return nullptr;
5854 // FIXME: This probably breaks the attempts to layout after a load is finished
5855 // in implicitClose(), and probably tons of other things...
5856 return GetFrame()->DeprecatedLocalOwner();
5857 }
5858
WillChangeFrameOwnerProperties(int margin_width,int margin_height,mojom::blink::ScrollbarMode scrollbar_mode,bool is_display_none)5859 void Document::WillChangeFrameOwnerProperties(
5860 int margin_width,
5861 int margin_height,
5862 mojom::blink::ScrollbarMode scrollbar_mode,
5863 bool is_display_none) {
5864 DCHECK(GetFrame() && GetFrame()->Owner());
5865 FrameOwner* owner = GetFrame()->Owner();
5866
5867 if (is_display_none != owner->IsDisplayNone())
5868 DisplayNoneChangedForFrame();
5869
5870 // body() may become null as a result of modification event listeners, so we
5871 // check before each call.
5872 if (margin_width != owner->MarginWidth()) {
5873 if (auto* body_element = body()) {
5874 body_element->SetIntegralAttribute(html_names::kMarginwidthAttr,
5875 margin_width);
5876 }
5877 }
5878 if (margin_height != owner->MarginHeight()) {
5879 if (auto* body_element = body()) {
5880 body_element->SetIntegralAttribute(html_names::kMarginheightAttr,
5881 margin_height);
5882 }
5883 }
5884 if (scrollbar_mode != owner->ScrollbarMode() && View()) {
5885 View()->SetCanHaveScrollbars(scrollbar_mode !=
5886 mojom::blink::ScrollbarMode::kAlwaysOff);
5887 View()->SetNeedsLayout();
5888 }
5889 }
5890
cookie(ExceptionState & exception_state) const5891 String Document::cookie(ExceptionState& exception_state) const {
5892 if (GetSettings() && !GetSettings()->GetCookieEnabled())
5893 return String();
5894
5895 CountUse(WebFeature::kCookieGet);
5896
5897 if (!GetSecurityOrigin()->CanAccessCookies()) {
5898 if (IsSandboxed(mojom::blink::WebSandboxFlags::kOrigin))
5899 exception_state.ThrowSecurityError(
5900 "The document is sandboxed and lacks the 'allow-same-origin' flag.");
5901 else if (Url().ProtocolIsData())
5902 exception_state.ThrowSecurityError(
5903 "Cookies are disabled inside 'data:' URLs.");
5904 else
5905 exception_state.ThrowSecurityError("Access is denied for this document.");
5906 return String();
5907 } else if (GetSecurityOrigin()->IsLocal()) {
5908 CountUse(WebFeature::kFileAccessedCookies);
5909 }
5910
5911 if (!cookie_jar_)
5912 return String();
5913
5914 return cookie_jar_->Cookies();
5915 }
5916
setCookie(const String & value,ExceptionState & exception_state)5917 void Document::setCookie(const String& value, ExceptionState& exception_state) {
5918 if (GetSettings() && !GetSettings()->GetCookieEnabled())
5919 return;
5920
5921 UseCounter::Count(*this, WebFeature::kCookieSet);
5922
5923 if (!GetSecurityOrigin()->CanAccessCookies()) {
5924 if (IsSandboxed(mojom::blink::WebSandboxFlags::kOrigin))
5925 exception_state.ThrowSecurityError(
5926 "The document is sandboxed and lacks the 'allow-same-origin' flag.");
5927 else if (Url().ProtocolIsData())
5928 exception_state.ThrowSecurityError(
5929 "Cookies are disabled inside 'data:' URLs.");
5930 else
5931 exception_state.ThrowSecurityError("Access is denied for this document.");
5932 return;
5933 } else if (GetSecurityOrigin()->IsLocal()) {
5934 UseCounter::Count(*this, WebFeature::kFileAccessedCookies);
5935 }
5936
5937 if (!cookie_jar_)
5938 return;
5939
5940 cookie_jar_->SetCookie(value);
5941 }
5942
CookiesEnabled() const5943 bool Document::CookiesEnabled() const {
5944 // Compatible behavior in contexts that don't have cookie access.
5945 if (!GetSecurityOrigin()->CanAccessCookies())
5946 return true;
5947
5948 if (!cookie_jar_)
5949 return false;
5950
5951 return cookie_jar_->CookiesEnabled();
5952 }
5953
referrer() const5954 const AtomicString& Document::referrer() const {
5955 if (Loader())
5956 return Loader()->GetReferrer().referrer;
5957 return g_null_atom;
5958 }
5959
domain() const5960 String Document::domain() const {
5961 return GetSecurityOrigin()->Domain();
5962 }
5963
setDomain(const String & raw_domain,ExceptionState & exception_state)5964 void Document::setDomain(const String& raw_domain,
5965 ExceptionState& exception_state) {
5966 UseCounter::Count(*this, WebFeature::kDocumentSetDomain);
5967
5968 const String feature_policy_error =
5969 "Setting `document.domain` is disabled by Feature Policy.";
5970 if (!IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kDocumentDomain,
5971 ReportOptions::kReportOnFailure,
5972 feature_policy_error)) {
5973 exception_state.ThrowSecurityError(feature_policy_error);
5974 return;
5975 }
5976
5977 if (!frame_) {
5978 exception_state.ThrowSecurityError(
5979 "A browsing context is required to set a domain.");
5980 return;
5981 }
5982
5983 if (IsSandboxed(mojom::blink::WebSandboxFlags::kDocumentDomain)) {
5984 exception_state.ThrowSecurityError(
5985 "Assignment is forbidden for sandboxed iframes.");
5986 return;
5987 }
5988
5989 if (SchemeRegistry::IsDomainRelaxationForbiddenForURLScheme(
5990 GetSecurityOrigin()->Protocol())) {
5991 exception_state.ThrowSecurityError("Assignment is forbidden for the '" +
5992 GetSecurityOrigin()->Protocol() +
5993 "' scheme.");
5994 return;
5995 }
5996
5997 bool success = false;
5998 String new_domain = SecurityOrigin::CanonicalizeHost(raw_domain, &success);
5999 if (!success) {
6000 exception_state.ThrowSecurityError("'" + raw_domain +
6001 "' could not be parsed properly.");
6002 return;
6003 }
6004
6005 if (new_domain.IsEmpty()) {
6006 exception_state.ThrowSecurityError("'" + new_domain +
6007 "' is an empty domain.");
6008 return;
6009 }
6010
6011 scoped_refptr<SecurityOrigin> new_origin =
6012 GetSecurityOrigin()->IsolatedCopy();
6013 new_origin->SetDomainFromDOM(new_domain);
6014 OriginAccessEntry access_entry(
6015 *new_origin, network::mojom::CorsDomainMatchMode::kAllowSubdomains);
6016 network::cors::OriginAccessEntry::MatchResult result =
6017 access_entry.MatchesOrigin(*GetSecurityOrigin());
6018 if (result == network::cors::OriginAccessEntry::kDoesNotMatchOrigin) {
6019 exception_state.ThrowSecurityError(
6020 "'" + new_domain + "' is not a suffix of '" + domain() + "'.");
6021 return;
6022 }
6023
6024 if (result ==
6025 network::cors::OriginAccessEntry::kMatchesOriginButIsPublicSuffix) {
6026 exception_state.ThrowSecurityError("'" + new_domain +
6027 "' is a top-level domain.");
6028 return;
6029 }
6030
6031 if (frame_) {
6032 UseCounter::Count(*this,
6033 GetSecurityOrigin()->Port() == 0
6034 ? WebFeature::kDocumentDomainSetWithDefaultPort
6035 : WebFeature::kDocumentDomainSetWithNonDefaultPort);
6036 bool was_cross_origin_to_main_frame = frame_->IsCrossOriginToMainFrame();
6037 bool was_cross_origin_to_parent_frame =
6038 frame_->IsCrossOriginToParentFrame();
6039 GetMutableSecurityOrigin()->SetDomainFromDOM(new_domain);
6040 bool is_cross_origin_to_main_frame = frame_->IsCrossOriginToMainFrame();
6041 if (FrameScheduler* frame_scheduler = frame_->GetFrameScheduler())
6042 frame_scheduler->SetCrossOriginToMainFrame(is_cross_origin_to_main_frame);
6043 if (View() &&
6044 (was_cross_origin_to_main_frame != is_cross_origin_to_main_frame)) {
6045 View()->CrossOriginToMainFrameChanged();
6046 }
6047 if (frame_->IsMainFrame()) {
6048 // Notify descendants if their cross-origin-to-main-frame status changed.
6049 // TODO(pdr): This will notify even if |Frame::IsCrossOriginToMainFrame|
6050 // is the same. Track whether each child was cross-origin to main before
6051 // and after changing the domain, and only notify the changed ones.
6052 for (Frame* child = frame_->Tree().FirstChild(); child;
6053 child = child->Tree().TraverseNext(frame_)) {
6054 auto* child_local_frame = DynamicTo<LocalFrame>(child);
6055 if (child_local_frame && child_local_frame->View())
6056 child_local_frame->View()->CrossOriginToMainFrameChanged();
6057 }
6058 }
6059
6060 if (View() && was_cross_origin_to_parent_frame !=
6061 frame_->IsCrossOriginToParentFrame()) {
6062 View()->CrossOriginToParentFrameChanged();
6063 }
6064 // Notify all child frames if their cross-origin-to-parent status changed.
6065 // TODO(pdr): This will notify even if |Frame::IsCrossOriginToParentFrame|
6066 // is the same. Track whether each child was cross-origin-to-parent before
6067 // and after changing the domain, and only notify the changed ones.
6068 for (Frame* child = frame_->Tree().FirstChild(); child;
6069 child = child->Tree().NextSibling()) {
6070 auto* child_local_frame = DynamicTo<LocalFrame>(child);
6071 if (child_local_frame && child_local_frame->View())
6072 child_local_frame->View()->CrossOriginToParentFrameChanged();
6073 }
6074
6075 frame_->GetScriptController().UpdateSecurityOrigin(GetSecurityOrigin());
6076 }
6077 }
6078
6079 // https://html.spec.whatwg.org/C#dom-document-lastmodified
lastModified() const6080 String Document::lastModified() const {
6081 base::Time::Exploded exploded;
6082 bool found_date = false;
6083 AtomicString http_last_modified = override_last_modified_;
6084 if (http_last_modified.IsEmpty() && frame_) {
6085 if (DocumentLoader* document_loader = Loader()) {
6086 http_last_modified = document_loader->GetResponse().HttpHeaderField(
6087 http_names::kLastModified);
6088 }
6089 }
6090 if (!http_last_modified.IsEmpty()) {
6091 base::Optional<base::Time> date_value = ParseDate(http_last_modified);
6092 if (date_value) {
6093 date_value.value().LocalExplode(&exploded);
6094 found_date = true;
6095 }
6096 }
6097 // FIXME: If this document came from the file system, the HTML5
6098 // specificiation tells us to read the last modification date from the file
6099 // system.
6100 if (!found_date) {
6101 base::Time::Now().LocalExplode(&exploded);
6102 }
6103 return String::Format("%02d/%02d/%04d %02d:%02d:%02d", exploded.month,
6104 exploded.day_of_month, exploded.year, exploded.hour,
6105 exploded.minute, exploded.second);
6106 }
6107
SetFindInPageRoot(Element * find_in_page_root)6108 void Document::SetFindInPageRoot(Element* find_in_page_root) {
6109 DCHECK(RuntimeEnabledFeatures::InvisibleDOMEnabled());
6110 DCHECK(!find_in_page_root || !find_in_page_root_);
6111 find_in_page_root_ = find_in_page_root;
6112 }
6113
TopFrameOrigin() const6114 scoped_refptr<const SecurityOrigin> Document::TopFrameOrigin() const {
6115 if (!GetFrame())
6116 return scoped_refptr<const SecurityOrigin>();
6117
6118 return GetFrame()->Tree().Top().GetSecurityContext()->GetSecurityOrigin();
6119 }
6120
SiteForCookies() const6121 net::SiteForCookies Document::SiteForCookies() const {
6122 // TODO(mkwst): This doesn't properly handle HTML Import documents.
6123
6124 // If this is an imported document, grab its master document's first-party:
6125 if (IsHTMLImport())
6126 return ImportsController()->Master()->SiteForCookies();
6127
6128 if (!GetFrame())
6129 return net::SiteForCookies();
6130
6131 Frame& top = GetFrame()->Tree().Top();
6132 const SecurityOrigin* origin = top.GetSecurityContext()->GetSecurityOrigin();
6133 // TODO(yhirano): Ideally |origin| should not be null here.
6134 if (!origin)
6135 return net::SiteForCookies();
6136
6137 net::SiteForCookies candidate =
6138 net::SiteForCookies::FromOrigin(origin->ToUrlOrigin());
6139
6140 if (SchemeRegistry::ShouldTreatURLSchemeAsFirstPartyWhenTopLevel(
6141 origin->Protocol())) {
6142 return candidate;
6143 }
6144
6145 const Frame* current_frame = GetFrame();
6146 while (current_frame) {
6147 const SecurityOrigin* cur_security_origin =
6148 current_frame->GetSecurityContext()->GetSecurityOrigin();
6149 if (!candidate.IsEquivalent(net::SiteForCookies::FromOrigin(
6150 cur_security_origin->ToUrlOrigin()))) {
6151 return net::SiteForCookies();
6152 }
6153 current_frame = current_frame->Tree().Parent();
6154 }
6155
6156 return candidate;
6157 }
6158
GetPermissionService(ExecutionContext * execution_context)6159 mojom::blink::PermissionService* Document::GetPermissionService(
6160 ExecutionContext* execution_context) {
6161 if (!permission_service_.is_bound()) {
6162 execution_context->GetBrowserInterfaceBroker().GetInterface(
6163 permission_service_.BindNewPipeAndPassReceiver(
6164 execution_context->GetTaskRunner(TaskType::kPermission)));
6165 permission_service_.set_disconnect_handler(WTF::Bind(
6166 &Document::PermissionServiceConnectionError, WrapWeakPersistent(this)));
6167 }
6168 return permission_service_.get();
6169 }
6170
PermissionServiceConnectionError()6171 void Document::PermissionServiceConnectionError() {
6172 permission_service_.reset();
6173 }
6174
hasStorageAccess(ScriptState * script_state) const6175 ScriptPromise Document::hasStorageAccess(ScriptState* script_state) const {
6176 const bool has_access =
6177 TopFrameOrigin() &&
6178 GetSecurityOrigin()->IsSameOriginWith(TopFrameOrigin().get());
6179 ScriptPromiseResolver* resolver =
6180 MakeGarbageCollected<ScriptPromiseResolver>(script_state);
6181
6182 // TODO (http://crbug.com/989663)
6183 // Hookup actual logic to Resolve/Reject this request properly.
6184 ScriptPromise promise = resolver->Promise();
6185 resolver->Resolve(has_access);
6186 return promise;
6187 }
6188
requestStorageAccess(ScriptState * script_state)6189 ScriptPromise Document::requestStorageAccess(ScriptState* script_state) {
6190 DCHECK(frame_);
6191 ScriptPromiseResolver* resolver =
6192 MakeGarbageCollected<ScriptPromiseResolver>(script_state);
6193
6194 // TODO (http://crbug.com/989663)
6195 // Hookup actual logic to Resolve/Reject this request properly.
6196
6197 // Access the promise first to ensure it is created so that the proper state
6198 // can be changed when it is resolved or rejected.
6199 ScriptPromise promise = resolver->Promise();
6200
6201 const bool has_user_gesture = LocalFrame::HasTransientUserActivation(frame_);
6202 if (has_user_gesture) {
6203 auto descriptor = mojom::blink::PermissionDescriptor::New();
6204 descriptor->name = mojom::blink::PermissionName::STORAGE_ACCESS;
6205 GetPermissionService(ExecutionContext::From(script_state))
6206 ->RequestPermission(
6207 std::move(descriptor), has_user_gesture,
6208 WTF::Bind(
6209 [](ScriptPromiseResolver* resolver,
6210 mojom::blink::PermissionStatus status) {
6211 DCHECK(resolver);
6212 (status == mojom::blink::PermissionStatus::GRANTED)
6213 ? resolver->Resolve()
6214 : resolver->Reject();
6215 },
6216 WrapPersistent(resolver)));
6217 } else {
6218 // Without a user gesture any request for storage access is immediately
6219 // denied.
6220 resolver->Reject();
6221 }
6222 return promise;
6223 }
6224
IsValidNameNonASCII(const LChar * characters,unsigned length)6225 static bool IsValidNameNonASCII(const LChar* characters, unsigned length) {
6226 if (!IsValidNameStart(characters[0]))
6227 return false;
6228
6229 for (unsigned i = 1; i < length; ++i) {
6230 if (!IsValidNamePart(characters[i]))
6231 return false;
6232 }
6233
6234 return true;
6235 }
6236
IsValidNameNonASCII(const UChar * characters,unsigned length)6237 static bool IsValidNameNonASCII(const UChar* characters, unsigned length) {
6238 for (unsigned i = 0; i < length;) {
6239 bool first = i == 0;
6240 UChar32 c;
6241 U16_NEXT(characters, i, length, c); // Increments i.
6242 if (first ? !IsValidNameStart(c) : !IsValidNamePart(c))
6243 return false;
6244 }
6245
6246 return true;
6247 }
6248
6249 template <typename CharType>
IsValidNameASCII(const CharType * characters,unsigned length)6250 static inline bool IsValidNameASCII(const CharType* characters,
6251 unsigned length) {
6252 CharType c = characters[0];
6253 if (!(IsASCIIAlpha(c) || c == ':' || c == '_'))
6254 return false;
6255
6256 for (unsigned i = 1; i < length; ++i) {
6257 c = characters[i];
6258 if (!(IsASCIIAlphanumeric(c) || c == ':' || c == '_' || c == '-' ||
6259 c == '.'))
6260 return false;
6261 }
6262
6263 return true;
6264 }
6265
IsValidName(const String & name)6266 bool Document::IsValidName(const String& name) {
6267 unsigned length = name.length();
6268 if (!length)
6269 return false;
6270
6271 if (name.Is8Bit()) {
6272 const LChar* characters = name.Characters8();
6273
6274 if (IsValidNameASCII(characters, length))
6275 return true;
6276
6277 return IsValidNameNonASCII(characters, length);
6278 }
6279
6280 const UChar* characters = name.Characters16();
6281
6282 if (IsValidNameASCII(characters, length))
6283 return true;
6284
6285 return IsValidNameNonASCII(characters, length);
6286 }
6287
6288 enum QualifiedNameStatus {
6289 kQNValid,
6290 kQNMultipleColons,
6291 kQNInvalidStartChar,
6292 kQNInvalidChar,
6293 kQNEmptyPrefix,
6294 kQNEmptyLocalName
6295 };
6296
6297 struct ParseQualifiedNameResult {
6298 QualifiedNameStatus status;
6299 UChar32 character;
6300 ParseQualifiedNameResult() = default;
ParseQualifiedNameResultblink::ParseQualifiedNameResult6301 explicit ParseQualifiedNameResult(QualifiedNameStatus status)
6302 : status(status) {}
ParseQualifiedNameResultblink::ParseQualifiedNameResult6303 ParseQualifiedNameResult(QualifiedNameStatus status, UChar32 character)
6304 : status(status), character(character) {}
6305 };
6306
6307 template <typename CharType>
ParseQualifiedNameInternal(const AtomicString & qualified_name,const CharType * characters,unsigned length,AtomicString & prefix,AtomicString & local_name)6308 static ParseQualifiedNameResult ParseQualifiedNameInternal(
6309 const AtomicString& qualified_name,
6310 const CharType* characters,
6311 unsigned length,
6312 AtomicString& prefix,
6313 AtomicString& local_name) {
6314 bool name_start = true;
6315 bool saw_colon = false;
6316 unsigned colon_pos = 0;
6317
6318 for (unsigned i = 0; i < length;) {
6319 UChar32 c;
6320 U16_NEXT(characters, i, length, c);
6321 if (c == ':') {
6322 if (saw_colon)
6323 return ParseQualifiedNameResult(kQNMultipleColons);
6324 name_start = true;
6325 saw_colon = true;
6326 colon_pos = i - 1;
6327 } else if (name_start) {
6328 if (!IsValidNameStart(c))
6329 return ParseQualifiedNameResult(kQNInvalidStartChar, c);
6330 name_start = false;
6331 } else {
6332 if (!IsValidNamePart(c))
6333 return ParseQualifiedNameResult(kQNInvalidChar, c);
6334 }
6335 }
6336
6337 if (!saw_colon) {
6338 prefix = g_null_atom;
6339 local_name = qualified_name;
6340 } else {
6341 prefix = AtomicString(characters, colon_pos);
6342 if (prefix.IsEmpty())
6343 return ParseQualifiedNameResult(kQNEmptyPrefix);
6344 int prefix_start = colon_pos + 1;
6345 local_name = AtomicString(characters + prefix_start, length - prefix_start);
6346 }
6347
6348 if (local_name.IsEmpty())
6349 return ParseQualifiedNameResult(kQNEmptyLocalName);
6350
6351 return ParseQualifiedNameResult(kQNValid);
6352 }
6353
ParseQualifiedName(const AtomicString & qualified_name,AtomicString & prefix,AtomicString & local_name,ExceptionState & exception_state)6354 bool Document::ParseQualifiedName(const AtomicString& qualified_name,
6355 AtomicString& prefix,
6356 AtomicString& local_name,
6357 ExceptionState& exception_state) {
6358 unsigned length = qualified_name.length();
6359
6360 if (!length) {
6361 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidCharacterError,
6362 "The qualified name provided is empty.");
6363 return false;
6364 }
6365
6366 ParseQualifiedNameResult return_value;
6367 if (qualified_name.Is8Bit())
6368 return_value =
6369 ParseQualifiedNameInternal(qualified_name, qualified_name.Characters8(),
6370 length, prefix, local_name);
6371 else
6372 return_value = ParseQualifiedNameInternal(qualified_name,
6373 qualified_name.Characters16(),
6374 length, prefix, local_name);
6375 if (return_value.status == kQNValid)
6376 return true;
6377
6378 StringBuilder message;
6379 message.Append("The qualified name provided ('");
6380 message.Append(qualified_name);
6381 message.Append("') ");
6382
6383 if (return_value.status == kQNMultipleColons) {
6384 message.Append("contains multiple colons.");
6385 } else if (return_value.status == kQNInvalidStartChar) {
6386 message.Append("contains the invalid name-start character '");
6387 message.Append(return_value.character);
6388 message.Append("'.");
6389 } else if (return_value.status == kQNInvalidChar) {
6390 message.Append("contains the invalid character '");
6391 message.Append(return_value.character);
6392 message.Append("'.");
6393 } else if (return_value.status == kQNEmptyPrefix) {
6394 message.Append("has an empty namespace prefix.");
6395 } else {
6396 DCHECK_EQ(return_value.status, kQNEmptyLocalName);
6397 message.Append("has an empty local name.");
6398 }
6399
6400 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidCharacterError,
6401 message.ToString());
6402 return false;
6403 }
6404
SetEncodingData(const DocumentEncodingData & new_data)6405 void Document::SetEncodingData(const DocumentEncodingData& new_data) {
6406 // It's possible for the encoding of the document to change while we're
6407 // decoding data. That can only occur while we're processing the <head>
6408 // portion of the document. There isn't much user-visible content in the
6409 // <head>, but there is the <title> element. This function detects that
6410 // situation and re-decodes the document's title so that the user doesn't see
6411 // an incorrectly decoded title in the title bar.
6412 if (title_element_ && Encoding() != new_data.Encoding() &&
6413 !ElementTraversal::FirstWithin(*title_element_) &&
6414 Encoding() == Latin1Encoding() &&
6415 title_element_->textContent().ContainsOnlyLatin1OrEmpty()) {
6416 std::string original_bytes = title_element_->textContent().Latin1();
6417 std::unique_ptr<TextCodec> codec = NewTextCodec(new_data.Encoding());
6418 String correctly_decoded_title =
6419 codec->Decode(original_bytes.c_str(),
6420 static_cast<wtf_size_t>(original_bytes.length()),
6421 WTF::FlushBehavior::kDataEOF);
6422 title_element_->setTextContent(correctly_decoded_title);
6423 }
6424
6425 DCHECK(new_data.Encoding().IsValid());
6426 encoding_data_ = new_data;
6427
6428 // FIXME: Should be removed as part of
6429 // https://code.google.com/p/chromium/issues/detail?id=319643
6430 bool should_use_visual_ordering =
6431 encoding_data_.Encoding().UsesVisualOrdering();
6432 if (should_use_visual_ordering != visually_ordered_) {
6433 visually_ordered_ = should_use_visual_ordering;
6434 GetStyleEngine().MarkViewportStyleDirty();
6435 GetStyleEngine().MarkAllElementsForStyleRecalc(
6436 StyleChangeReasonForTracing::Create(
6437 style_change_reason::kVisuallyOrdered));
6438 }
6439 }
6440
CompleteURL(const String & url) const6441 KURL Document::CompleteURL(const String& url) const {
6442 return CompleteURLWithOverride(url, base_url_);
6443 }
6444
CompleteURLWithOverride(const String & url,const KURL & base_url_override) const6445 KURL Document::CompleteURLWithOverride(const String& url,
6446 const KURL& base_url_override) const {
6447 DCHECK(base_url_override.IsEmpty() || base_url_override.IsValid());
6448
6449 // Always return a null URL when passed a null string.
6450 // FIXME: Should we change the KURL constructor to have this behavior?
6451 // See also [CSS]StyleSheet::completeURL(const String&)
6452 if (url.IsNull())
6453 return KURL();
6454 if (!Encoding().IsValid())
6455 return KURL(base_url_override, url);
6456 return KURL(base_url_override, url, Encoding());
6457 }
6458
6459 // static
ShouldInheritSecurityOriginFromOwner(const KURL & url)6460 bool Document::ShouldInheritSecurityOriginFromOwner(const KURL& url) {
6461 // https://html.spec.whatwg.org/C/#origin
6462 //
6463 // If a Document is the initial "about:blank" document The origin and
6464 // effective script origin of the Document are those it was assigned when its
6465 // browsing context was created.
6466 //
6467 // Note: We generalize this to all "blank" URLs and invalid URLs because we
6468 // treat all of these URLs as about:blank.
6469 return url.IsEmpty() || url.ProtocolIsAbout();
6470 }
6471
OpenSearchDescriptionURL()6472 KURL Document::OpenSearchDescriptionURL() {
6473 static const char kOpenSearchMIMEType[] =
6474 "application/opensearchdescription+xml";
6475 static const char kOpenSearchRelation[] = "search";
6476
6477 // FIXME: Why do only top-level frames have openSearchDescriptionURLs?
6478 if (!GetFrame() || GetFrame()->Tree().Parent())
6479 return KURL();
6480
6481 // FIXME: Why do we need to wait for load completion?
6482 if (!LoadEventFinished())
6483 return KURL();
6484
6485 if (!head())
6486 return KURL();
6487
6488 for (HTMLLinkElement* link_element =
6489 Traversal<HTMLLinkElement>::FirstChild(*head());
6490 link_element;
6491 link_element = Traversal<HTMLLinkElement>::NextSibling(*link_element)) {
6492 if (!EqualIgnoringASCIICase(link_element->GetType(), kOpenSearchMIMEType) ||
6493 !EqualIgnoringASCIICase(link_element->Rel(), kOpenSearchRelation))
6494 continue;
6495 if (link_element->Href().IsEmpty())
6496 continue;
6497
6498 // Count usage; perhaps we can lock this to secure contexts.
6499 WebFeature osd_disposition;
6500 scoped_refptr<const SecurityOrigin> target =
6501 SecurityOrigin::Create(link_element->Href());
6502 if (IsSecureContext()) {
6503 osd_disposition = target->IsPotentiallyTrustworthy()
6504 ? WebFeature::kOpenSearchSecureOriginSecureTarget
6505 : WebFeature::kOpenSearchSecureOriginInsecureTarget;
6506 } else {
6507 osd_disposition =
6508 target->IsPotentiallyTrustworthy()
6509 ? WebFeature::kOpenSearchInsecureOriginSecureTarget
6510 : WebFeature::kOpenSearchInsecureOriginInsecureTarget;
6511 }
6512 UseCounter::Count(*this, osd_disposition);
6513
6514 return link_element->Href();
6515 }
6516
6517 return KURL();
6518 }
6519
currentScriptForBinding(HTMLScriptElementOrSVGScriptElement & script_element) const6520 void Document::currentScriptForBinding(
6521 HTMLScriptElementOrSVGScriptElement& script_element) const {
6522 if (!current_script_stack_.IsEmpty()) {
6523 if (ScriptElementBase* script_element_base = current_script_stack_.back())
6524 script_element_base->SetScriptElementForBinding(script_element);
6525 }
6526 }
6527
PushCurrentScript(ScriptElementBase * new_current_script)6528 void Document::PushCurrentScript(ScriptElementBase* new_current_script) {
6529 current_script_stack_.push_back(new_current_script);
6530 }
6531
PopCurrentScript(ScriptElementBase * script)6532 void Document::PopCurrentScript(ScriptElementBase* script) {
6533 DCHECK(!current_script_stack_.IsEmpty());
6534 DCHECK_EQ(current_script_stack_.back(), script);
6535 current_script_stack_.pop_back();
6536 }
6537
SetTransformSource(std::unique_ptr<TransformSource> source)6538 void Document::SetTransformSource(std::unique_ptr<TransformSource> source) {
6539 transform_source_ = std::move(source);
6540 }
6541
designMode() const6542 String Document::designMode() const {
6543 return InDesignMode() ? "on" : "off";
6544 }
6545
setDesignMode(const String & value)6546 void Document::setDesignMode(const String& value) {
6547 bool new_value = design_mode_;
6548 if (EqualIgnoringASCIICase(value, "on")) {
6549 new_value = true;
6550 UseCounter::Count(*this, WebFeature::kDocumentDesignModeEnabeld);
6551 } else if (EqualIgnoringASCIICase(value, "off")) {
6552 new_value = false;
6553 }
6554 if (new_value == design_mode_)
6555 return;
6556 design_mode_ = new_value;
6557 GetStyleEngine().MarkViewportStyleDirty();
6558 GetStyleEngine().MarkAllElementsForStyleRecalc(
6559 StyleChangeReasonForTracing::Create(style_change_reason::kDesignMode));
6560 }
6561
ParentDocument() const6562 Document* Document::ParentDocument() const {
6563 if (!frame_)
6564 return nullptr;
6565 auto* parent_local_frame = DynamicTo<LocalFrame>(frame_->Tree().Parent());
6566 if (!parent_local_frame)
6567 return nullptr;
6568 return parent_local_frame->GetDocument();
6569 }
6570
TopDocument() const6571 Document& Document::TopDocument() const {
6572 // FIXME: Not clear what topDocument() should do in the OOPI case--should it
6573 // return the topmost available Document, or something else?
6574 Document* doc = const_cast<Document*>(this);
6575 for (HTMLFrameOwnerElement* element = doc->LocalOwner(); element;
6576 element = doc->LocalOwner())
6577 doc = &element->GetDocument();
6578
6579 DCHECK(doc);
6580 return *doc;
6581 }
6582
ContextDocument() const6583 Document* Document::ContextDocument() const {
6584 return context_document_ ? context_document_.Get()
6585 : const_cast<Document*>(this);
6586 }
6587
createAttribute(const AtomicString & name,ExceptionState & exception_state)6588 Attr* Document::createAttribute(const AtomicString& name,
6589 ExceptionState& exception_state) {
6590 if (!IsValidName(name)) {
6591 exception_state.ThrowDOMException(DOMExceptionCode::kInvalidCharacterError,
6592 "The localName provided ('" + name +
6593 "') contains an invalid character.");
6594 return nullptr;
6595 }
6596 return MakeGarbageCollected<Attr>(
6597 *this, QualifiedName(g_null_atom, ConvertLocalName(name), g_null_atom),
6598 g_empty_atom);
6599 }
6600
createAttributeNS(const AtomicString & namespace_uri,const AtomicString & qualified_name,ExceptionState & exception_state)6601 Attr* Document::createAttributeNS(const AtomicString& namespace_uri,
6602 const AtomicString& qualified_name,
6603 ExceptionState& exception_state) {
6604 AtomicString prefix, local_name;
6605 if (!ParseQualifiedName(qualified_name, prefix, local_name, exception_state))
6606 return nullptr;
6607
6608 QualifiedName q_name(prefix, local_name, namespace_uri);
6609
6610 if (!HasValidNamespaceForAttributes(q_name)) {
6611 exception_state.ThrowDOMException(
6612 DOMExceptionCode::kNamespaceError,
6613 "The namespace URI provided ('" + namespace_uri +
6614 "') is not valid for the qualified name provided ('" +
6615 qualified_name + "').");
6616 return nullptr;
6617 }
6618
6619 return MakeGarbageCollected<Attr>(*this, q_name, g_empty_atom);
6620 }
6621
SvgExtensions()6622 const SVGDocumentExtensions* Document::SvgExtensions() {
6623 return svg_extensions_.Get();
6624 }
6625
AccessSVGExtensions()6626 SVGDocumentExtensions& Document::AccessSVGExtensions() {
6627 if (!svg_extensions_)
6628 svg_extensions_ = MakeGarbageCollected<SVGDocumentExtensions>(this);
6629 return *svg_extensions_;
6630 }
6631
HasSVGRootNode() const6632 bool Document::HasSVGRootNode() const {
6633 return IsA<SVGSVGElement>(documentElement());
6634 }
6635
images()6636 HTMLCollection* Document::images() {
6637 return EnsureCachedCollection<HTMLCollection>(kDocImages);
6638 }
6639
applets()6640 HTMLCollection* Document::applets() {
6641 return EnsureCachedCollection<HTMLCollection>(kDocApplets);
6642 }
6643
embeds()6644 HTMLCollection* Document::embeds() {
6645 return EnsureCachedCollection<HTMLCollection>(kDocEmbeds);
6646 }
6647
scripts()6648 HTMLCollection* Document::scripts() {
6649 return EnsureCachedCollection<HTMLCollection>(kDocScripts);
6650 }
6651
links()6652 HTMLCollection* Document::links() {
6653 return EnsureCachedCollection<HTMLCollection>(kDocLinks);
6654 }
6655
forms()6656 HTMLCollection* Document::forms() {
6657 return EnsureCachedCollection<HTMLCollection>(kDocForms);
6658 }
6659
anchors()6660 HTMLCollection* Document::anchors() {
6661 return EnsureCachedCollection<HTMLCollection>(kDocAnchors);
6662 }
6663
all()6664 HTMLAllCollection* Document::all() {
6665 return EnsureCachedCollection<HTMLAllCollection>(kDocAll);
6666 }
6667
WindowNamedItems(const AtomicString & name)6668 HTMLCollection* Document::WindowNamedItems(const AtomicString& name) {
6669 return EnsureCachedCollection<WindowNameCollection>(kWindowNamedItems, name);
6670 }
6671
DocumentNamedItems(const AtomicString & name)6672 DocumentNameCollection* Document::DocumentNamedItems(const AtomicString& name) {
6673 return EnsureCachedCollection<DocumentNameCollection>(kDocumentNamedItems,
6674 name);
6675 }
6676
DocumentAllNamedItems(const AtomicString & name)6677 HTMLCollection* Document::DocumentAllNamedItems(const AtomicString& name) {
6678 return EnsureCachedCollection<DocumentAllNameCollection>(
6679 kDocumentAllNamedItems, name);
6680 }
6681
defaultView() const6682 DOMWindow* Document::defaultView() const {
6683 // The HTML spec requires to return null if the document is detached from the
6684 // DOM. However, |dom_window_| is not cleared on the detachment. So, we need
6685 // to check |frame_| to tell whether the document is attached or not.
6686 return frame_ ? dom_window_ : nullptr;
6687 }
6688
6689 namespace {
6690
6691 using performance_manager::mojom::InterventionPolicy;
6692
6693 // A helper function to set the origin trial freeze policy of a document.
SetOriginTrialFreezePolicy(DocumentResourceCoordinator * document_resource_coordinator,ExecutionContext * context)6694 void SetOriginTrialFreezePolicy(
6695 DocumentResourceCoordinator* document_resource_coordinator,
6696 ExecutionContext* context) {
6697 // An explicit opt-out overrides an explicit opt-in if both are present.
6698 if (RuntimeEnabledFeatures::PageFreezeOptOutEnabled(context)) {
6699 document_resource_coordinator->SetOriginTrialFreezePolicy(
6700 InterventionPolicy::kOptOut);
6701 UseCounter::Count(context, WebFeature::kPageFreezeOptOut);
6702 } else if (RuntimeEnabledFeatures::PageFreezeOptInEnabled(context)) {
6703 document_resource_coordinator->SetOriginTrialFreezePolicy(
6704 InterventionPolicy::kOptIn);
6705 UseCounter::Count(context, WebFeature::kPageFreezeOptIn);
6706 }
6707 }
6708
6709 } // namespace
6710
FinishedParsing()6711 void Document::FinishedParsing() {
6712 DCHECK(!GetScriptableDocumentParser() || !parser_->IsParsing());
6713 DCHECK(!GetScriptableDocumentParser() || ready_state_ != kLoading);
6714 SetParsingState(kInDOMContentLoaded);
6715 DocumentParserTiming::From(*this).MarkParserStop();
6716
6717 // FIXME: DOMContentLoaded is dispatched synchronously, but this should be
6718 // dispatched in a queued task, see https://crbug.com/425790
6719 if (document_timing_.DomContentLoadedEventStart().is_null())
6720 document_timing_.MarkDomContentLoadedEventStart();
6721 DispatchEvent(*Event::CreateBubble(event_type_names::kDOMContentLoaded));
6722 if (document_timing_.DomContentLoadedEventEnd().is_null())
6723 document_timing_.MarkDomContentLoadedEventEnd();
6724 SetParsingState(kFinishedParsing);
6725
6726 // Ensure Custom Element callbacks are drained before DOMContentLoaded.
6727 // FIXME: Remove this ad-hoc checkpoint when DOMContentLoaded is dispatched in
6728 // a queued task, which will do a checkpoint anyway. https://crbug.com/425790
6729 Microtask::PerformCheckpoint(V8PerIsolateData::MainThreadIsolate());
6730
6731 ScriptableDocumentParser* parser = GetScriptableDocumentParser();
6732 well_formed_ = parser && parser->WellFormed();
6733
6734 if (LocalFrame* frame = GetFrame()) {
6735 // Guarantee at least one call to the client specifying a title. (If
6736 // |title_| is not empty, then the title has already been dispatched.)
6737 if (title_.IsEmpty())
6738 DispatchDidReceiveTitle();
6739
6740 // Don't update the layout tree if we haven't requested the main resource
6741 // yet to avoid adding extra latency. Note that the first layout tree update
6742 // can be expensive since it triggers the parsing of the default stylesheets
6743 // which are compiled-in.
6744 const bool main_resource_was_already_requested =
6745 frame->Loader().StateMachine()->CommittedFirstRealDocumentLoad();
6746
6747 // FrameLoader::finishedParsing() might end up calling
6748 // Document::implicitClose() if all resource loads are
6749 // complete. HTMLObjectElements can start loading their resources from post
6750 // attach callbacks triggered by recalcStyle(). This means if we parse out
6751 // an <object> tag and then reach the end of the document without updating
6752 // styles, we might not have yet started the resource load and might fire
6753 // the window load event too early. To avoid this we force the styles to be
6754 // up to date before calling FrameLoader::finishedParsing(). See
6755 // https://bugs.webkit.org/show_bug.cgi?id=36864 starting around comment 35.
6756 if (main_resource_was_already_requested)
6757 UpdateStyleAndLayoutTree();
6758
6759 BeginLifecycleUpdatesIfRenderingReady();
6760
6761 frame->Loader().FinishedParsing();
6762
6763 TRACE_EVENT_INSTANT1("devtools.timeline", "MarkDOMContent",
6764 TRACE_EVENT_SCOPE_THREAD, "data",
6765 inspector_mark_load_event::Data(frame));
6766 probe::DomContentLoadedEventFired(frame);
6767 frame->GetIdlenessDetector()->DomContentLoadedEventFired();
6768
6769 // Forward origin trial freeze policy to the corresponding frame object in
6770 // the resource coordinator.
6771 if (auto* document_resource_coordinator = GetResourceCoordinator())
6772 SetOriginTrialFreezePolicy(document_resource_coordinator, domWindow());
6773 }
6774
6775 // Schedule dropping of the ElementDataCache. We keep it alive for a while
6776 // after parsing finishes so that dynamically inserted content can also
6777 // benefit from sharing optimizations. Note that we don't refresh the timer
6778 // on cache access since that could lead to huge caches being kept alive
6779 // indefinitely by something innocuous like JS setting .innerHTML repeatedly
6780 // on a timer.
6781 element_data_cache_clear_timer_.StartOneShot(base::TimeDelta::FromSeconds(10),
6782 FROM_HERE);
6783
6784 // Parser should have picked up all preloads by now
6785 fetcher_->ClearPreloads(ResourceFetcher::kClearSpeculativeMarkupPreloads);
6786 }
6787
ElementDataCacheClearTimerFired(TimerBase *)6788 void Document::ElementDataCacheClearTimerFired(TimerBase*) {
6789 element_data_cache_.Clear();
6790 }
6791
BeginLifecycleUpdatesIfRenderingReady()6792 void Document::BeginLifecycleUpdatesIfRenderingReady() {
6793 if (!IsActive())
6794 return;
6795 if (!HaveRenderBlockingResourcesLoaded())
6796 return;
6797 font_preload_manager_.WillBeginRendering();
6798 View()->BeginLifecycleUpdates();
6799 }
6800
IconURLs(int icon_types_mask)6801 Vector<IconURL> Document::IconURLs(int icon_types_mask) {
6802 IconURL first_favicon;
6803 IconURL first_touch_icon;
6804 IconURL first_touch_precomposed_icon;
6805 Vector<IconURL> secondary_icons;
6806
6807 using TraversalFunction = HTMLLinkElement* (*)(const Node&);
6808 TraversalFunction find_next_candidate =
6809 &Traversal<HTMLLinkElement>::NextSibling;
6810
6811 HTMLLinkElement* first_element = nullptr;
6812 if (head()) {
6813 first_element = Traversal<HTMLLinkElement>::FirstChild(*head());
6814 } else if (IsSVGDocument() && IsA<SVGSVGElement>(documentElement())) {
6815 first_element = Traversal<HTMLLinkElement>::FirstWithin(*documentElement());
6816 find_next_candidate = &Traversal<HTMLLinkElement>::Next;
6817 }
6818
6819 // Start from the first child node so that icons seen later take precedence as
6820 // required by the spec.
6821 for (HTMLLinkElement* link_element = first_element; link_element;
6822 link_element = find_next_candidate(*link_element)) {
6823 if (!((1 << static_cast<int>(link_element->GetIconType())) &
6824 icon_types_mask)) {
6825 continue;
6826 }
6827 if (link_element->Href().IsEmpty())
6828 continue;
6829
6830 IconURL new_url(link_element->Href(), link_element->IconSizes(),
6831 link_element->GetType(), link_element->GetIconType());
6832 if (link_element->GetIconType() ==
6833 mojom::blink::FaviconIconType::kFavicon) {
6834 if (first_favicon.icon_type_ != mojom::blink::FaviconIconType::kInvalid)
6835 secondary_icons.push_back(first_favicon);
6836 first_favicon = new_url;
6837 } else if (link_element->GetIconType() ==
6838 mojom::blink::FaviconIconType::kTouchIcon) {
6839 if (first_touch_icon.icon_type_ !=
6840 mojom::blink::FaviconIconType::kInvalid)
6841 secondary_icons.push_back(first_touch_icon);
6842 first_touch_icon = new_url;
6843 } else if (link_element->GetIconType() ==
6844 mojom::blink::FaviconIconType::kTouchPrecomposedIcon) {
6845 if (first_touch_precomposed_icon.icon_type_ !=
6846 mojom::blink::FaviconIconType::kInvalid)
6847 secondary_icons.push_back(first_touch_precomposed_icon);
6848 first_touch_precomposed_icon = new_url;
6849 } else {
6850 NOTREACHED();
6851 }
6852 }
6853
6854 Vector<IconURL> icon_urls;
6855 if (first_favicon.icon_type_ != mojom::blink::FaviconIconType::kInvalid) {
6856 icon_urls.push_back(first_favicon);
6857 } else if (url_.ProtocolIsInHTTPFamily() &&
6858 icon_types_mask & 1 << static_cast<int>(
6859 mojom::blink::FaviconIconType::kFavicon)) {
6860 icon_urls.push_back(IconURL::DefaultFavicon(url_));
6861 }
6862
6863 if (first_touch_icon.icon_type_ != mojom::blink::FaviconIconType::kInvalid)
6864 icon_urls.push_back(first_touch_icon);
6865 if (first_touch_precomposed_icon.icon_type_ !=
6866 mojom::blink::FaviconIconType::kInvalid)
6867 icon_urls.push_back(first_touch_precomposed_icon);
6868 for (int i = secondary_icons.size() - 1; i >= 0; --i)
6869 icon_urls.push_back(secondary_icons[i]);
6870 return icon_urls;
6871 }
6872
ThemeColor() const6873 base::Optional<Color> Document::ThemeColor() const {
6874 auto* root_element = documentElement();
6875 if (!root_element)
6876 return base::nullopt;
6877 for (HTMLMetaElement& meta_element :
6878 Traversal<HTMLMetaElement>::DescendantsOf(*root_element)) {
6879 Color color;
6880 if (EqualIgnoringASCIICase(meta_element.GetName(), "theme-color") &&
6881 CSSParser::ParseColor(
6882 color, meta_element.Content().GetString().StripWhiteSpace(), true))
6883 return color;
6884 }
6885 return base::nullopt;
6886 }
6887
ColorSchemeMetaChanged()6888 void Document::ColorSchemeMetaChanged() {
6889 if (!RuntimeEnabledFeatures::MetaColorSchemeEnabled())
6890 return;
6891
6892 const CSSValue* color_scheme = nullptr;
6893 if (auto* head_element = head()) {
6894 for (HTMLMetaElement& meta_element :
6895 Traversal<HTMLMetaElement>::DescendantsOf(*head_element)) {
6896 if (EqualIgnoringASCIICase(meta_element.GetName(), "color-scheme")) {
6897 if ((color_scheme = CSSParser::ParseSingleValue(
6898 CSSPropertyID::kColorScheme,
6899 meta_element.Content().GetString().StripWhiteSpace(),
6900 ElementSheet().Contents()->ParserContext()))) {
6901 break;
6902 }
6903 }
6904 }
6905 }
6906 GetStyleEngine().SetColorSchemeFromMeta(color_scheme);
6907 }
6908
GetLinkElement(const Document * doc,bool (* match_fn)(HTMLLinkElement &))6909 static HTMLLinkElement* GetLinkElement(const Document* doc,
6910 bool (*match_fn)(HTMLLinkElement&)) {
6911 HTMLHeadElement* head = doc->head();
6912 if (!head)
6913 return nullptr;
6914
6915 // The first matching link element is used. Others are ignored.
6916 for (HTMLLinkElement& link_element :
6917 Traversal<HTMLLinkElement>::ChildrenOf(*head)) {
6918 if (match_fn(link_element))
6919 return &link_element;
6920 }
6921 return nullptr;
6922 }
6923
LinkManifest() const6924 HTMLLinkElement* Document::LinkManifest() const {
6925 return GetLinkElement(this, [](HTMLLinkElement& link_element) {
6926 return link_element.RelAttribute().IsManifest();
6927 });
6928 }
6929
LinkCanonical() const6930 HTMLLinkElement* Document::LinkCanonical() const {
6931 return GetLinkElement(this, [](HTMLLinkElement& link_element) {
6932 return link_element.RelAttribute().IsCanonical();
6933 });
6934 }
6935
PoliciesInitialized(const DocumentInit & document_initializer)6936 void Document::PoliciesInitialized(const DocumentInit& document_initializer) {
6937 // Processing of the feature policy header is done before the SecurityContext
6938 // is initialized. This method just records the usage.
6939 if (!document_initializer.FeaturePolicyHeader().IsEmpty())
6940 UseCounter::Count(*this, WebFeature::kFeaturePolicyHeader);
6941
6942 // At this point, the document will not have been installed in the frame's
6943 // LocalDOMWindow, so we cannot call frame_->IsFeatureEnabled. This calls
6944 // SecurityContext::IsFeatureEnabled instead, which cannot report, but we
6945 // don't need reporting here in any case.
6946 is_vertical_scroll_enforced_ =
6947 frame_ && !frame_->IsMainFrame() &&
6948 RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
6949 !GetSecurityContext().GetFeaturePolicy()->IsFeatureEnabled(
6950 mojom::blink::FeaturePolicyFeature::kVerticalScroll);
6951 }
6952
GetOwnerContainerPolicy() const6953 const ParsedFeaturePolicy Document::GetOwnerContainerPolicy() const {
6954 // If this frame is not the main frame, then get the container policy from its
6955 // owner.
6956 if (frame_ && frame_->Owner())
6957 return frame_->Owner()->GetFramePolicy().container_policy;
6958 return ParsedFeaturePolicy();
6959 }
6960
GetParentFeaturePolicy() const6961 const FeaturePolicy* Document::GetParentFeaturePolicy() const {
6962 // If this frame is not the main frame, then get the feature policy from its
6963 // parent.
6964 if (frame_ && !frame_->IsMainFrame())
6965 return frame_->Tree().Parent()->GetSecurityContext()->GetFeaturePolicy();
6966 return nullptr;
6967 }
6968
ApplyPendingFramePolicyHeaders()6969 void Document::ApplyPendingFramePolicyHeaders() {
6970 if (frame_) {
6971 frame_->Client()->DidSetFramePolicyHeaders(
6972 GetSandboxFlags(), pending_fp_headers_, pending_dp_headers_);
6973 }
6974 pending_fp_headers_.clear();
6975 pending_dp_headers_.clear();
6976 }
6977
AllowedToUseDynamicMarkUpInsertion(const char * api_name,ExceptionState & exception_state)6978 bool Document::AllowedToUseDynamicMarkUpInsertion(
6979 const char* api_name,
6980 ExceptionState& exception_state) {
6981 if (!RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled()) {
6982 return true;
6983 }
6984 if (!frame_ ||
6985 IsFeatureEnabled(mojom::blink::FeaturePolicyFeature::kDocumentWrite,
6986 ReportOptions::kReportOnFailure)) {
6987 return true;
6988 }
6989
6990 // TODO(ekaramad): Throwing an exception seems an ideal resolution to mishaps
6991 // in using the API against the policy. But this cannot be applied to cross-
6992 // origin as there are security risks involved. We should perhaps unload the
6993 // whole frame instead of throwing.
6994 exception_state.ThrowDOMException(
6995 DOMExceptionCode::kNotAllowedError,
6996 String::Format(
6997 "The use of method '%s' has been blocked by feature policy. The "
6998 "feature "
6999 "'document-write' is disabled in this document.",
7000 api_name));
7001 return false;
7002 }
7003
UkmRecorder()7004 ukm::UkmRecorder* Document::UkmRecorder() {
7005 if (ukm_recorder_)
7006 return ukm_recorder_.get();
7007
7008 mojo::PendingRemote<ukm::mojom::UkmRecorderInterface> recorder;
7009 Platform::Current()->GetBrowserInterfaceBroker()->GetInterface(
7010 recorder.InitWithNewPipeAndPassReceiver());
7011 ukm_recorder_ = std::make_unique<ukm::MojoUkmRecorder>(std::move(recorder));
7012
7013 // TODO(crbug/795354): Move handling of URL recording out of the renderer.
7014 // URL must only be recorded from the main frame.
7015 if (IsInMainFrame())
7016 ukm_recorder_->UpdateSourceURL(ukm_source_id_, url_);
7017 return ukm_recorder_.get();
7018 }
7019
UkmSourceID() const7020 ukm::SourceId Document::UkmSourceID() const {
7021 return ukm_source_id_;
7022 }
7023
GetFontMatchingMetrics()7024 FontMatchingMetrics* Document::GetFontMatchingMetrics() {
7025 if (font_matching_metrics_)
7026 return font_matching_metrics_.get();
7027 font_matching_metrics_ = std::make_unique<FontMatchingMetrics>(
7028 IsInMainFrame(), UkmRecorder(), UkmSourceID());
7029 return font_matching_metrics_.get();
7030 }
7031
InitContentSecurityPolicy(ContentSecurityPolicy * csp)7032 void Document::InitContentSecurityPolicy(ContentSecurityPolicy* csp) {
7033 GetSecurityContext().SetContentSecurityPolicy(csp);
7034 GetContentSecurityPolicy()->BindToDelegate(
7035 GetContentSecurityPolicyDelegate());
7036 }
7037
InitSecurityContext(const DocumentInit & initializer)7038 void Document::InitSecurityContext(const DocumentInit& initializer) {
7039 DCHECK(GetSecurityOrigin());
7040 // If the CSP was provided by the DocumentLoader or is from ImportsController
7041 // it doesn't need to be bound right now. ImportsController takes a reference
7042 // to a master document's CSP which is already bound. Document construction
7043 // occurs in the DocumentLoader occurs before the frame reference is bound so
7044 // callbacks from binding the CSP delegate immediately would not get called
7045 // if it was bound immediately. eg. Callbacks back to browser or console
7046 // logging.
7047 if (!initializer.HasSecurityContext()) {
7048 // No source for a security context.
7049 // This can occur via document.implementation.createDocument().
7050 cookie_url_ = KURL(g_empty_string);
7051 return;
7052 }
7053 GetSecurityContext().SetInsecureRequestPolicy(
7054 initializer.GetInsecureRequestPolicy());
7055 if (initializer.InsecureNavigationsToUpgrade()) {
7056 for (auto to_upgrade : *initializer.InsecureNavigationsToUpgrade())
7057 GetSecurityContext().AddInsecureNavigationUpgrade(to_upgrade);
7058 }
7059
7060 bool inherit_cookie_url_from_owner = initializer.IsSrcdocDocument() ||
7061 url_.IsAboutBlankURL() ||
7062 !initializer.OriginToCommit();
7063
7064 cookie_url_ = inherit_cookie_url_from_owner && initializer.OwnerDocument()
7065 ? initializer.OwnerDocument()->CookieURL()
7066 : url_;
7067
7068 GetSecurityContext().SetAddressSpace(initializer.GetIPAddressSpace());
7069 }
7070
BindContentSecurityPolicy()7071 void Document::BindContentSecurityPolicy() {
7072 DCHECK(!GetContentSecurityPolicy()->IsBound());
7073 GetContentSecurityPolicy()->BindToDelegate(
7074 GetContentSecurityPolicyDelegate());
7075 }
7076
CanExecuteScripts(ReasonForCallingCanExecuteScripts reason)7077 bool Document::CanExecuteScripts(ReasonForCallingCanExecuteScripts reason) {
7078 DCHECK(GetFrame())
7079 << "you are querying canExecuteScripts on a non contextDocument.";
7080
7081 // Normally, scripts are not allowed in sandboxed contexts that disallow them.
7082 // However, there is an exception for cases when the script should bypass the
7083 // main world's CSP (such as for privileged isolated worlds). See
7084 // https://crbug.com/811528.
7085 if (IsSandboxed(mojom::blink::WebSandboxFlags::kScripts) &&
7086 !ContentSecurityPolicy::ShouldBypassMainWorld(domWindow())) {
7087 // FIXME: This message should be moved off the console once a solution to
7088 // https://bugs.webkit.org/show_bug.cgi?id=103274 exists.
7089 if (reason == kAboutToExecuteScript) {
7090 AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
7091 mojom::ConsoleMessageSource::kSecurity,
7092 mojom::ConsoleMessageLevel::kError,
7093 "Blocked script execution in '" + Url().ElidedString() +
7094 "' because the document's frame is sandboxed and the "
7095 "'allow-scripts' permission is not set."));
7096 }
7097 return false;
7098 }
7099
7100 // No scripting on a detached frame.
7101 if (!GetFrame()->Client())
7102 return false;
7103
7104 WebContentSettingsClient* settings_client =
7105 GetFrame()->GetContentSettingsClient();
7106
7107 Settings* settings = GetFrame()->GetSettings();
7108 bool script_enabled = settings && settings->GetScriptEnabled();
7109 if (settings_client)
7110 script_enabled = settings_client->AllowScript(script_enabled);
7111 if (!script_enabled && reason == kAboutToExecuteScript && settings_client)
7112 settings_client->DidNotAllowScript();
7113 return script_enabled;
7114 }
7115
AllowInlineEventHandler(Node * node,EventListener * listener,const String & context_url,const WTF::OrdinalNumber & context_line)7116 bool Document::AllowInlineEventHandler(Node* node,
7117 EventListener* listener,
7118 const String& context_url,
7119 const WTF::OrdinalNumber& context_line) {
7120 auto* element = DynamicTo<Element>(node);
7121
7122 // https://html.spec.whatwg.org/multipage/webappapis.html#event-handler-content-attributes
7123 // Step 5.1. If the Should element's inline behavior be blocked by Content
7124 // Security Policy? algorithm returns "Blocked" when executed upon element,
7125 // "script attribute", and value, then return. [CSP] [spec text]
7126 if (!GetContentSecurityPolicyForWorld()->AllowInline(
7127 ContentSecurityPolicy::InlineType::kScriptAttribute, element,
7128 listener->ScriptBody(), String() /* nonce */, context_url,
7129 context_line))
7130 return false;
7131
7132 // HTML says that inline script needs browsing context to create its execution
7133 // environment.
7134 // http://www.whatwg.org/specs/web-apps/current-work/multipage/webappapis.html#event-handler-attributes
7135 // Also, if the listening node came from other document, which happens on
7136 // context-less event dispatching, we also need to ask the owner document of
7137 // the node.
7138 LocalFrame* frame = ExecutingFrame();
7139 if (!frame)
7140 return false;
7141 if (!ContextDocument()->CanExecuteScripts(kNotAboutToExecuteScript))
7142 return false;
7143 if (node && node->GetDocument() != this &&
7144 !node->GetDocument().AllowInlineEventHandler(node, listener, context_url,
7145 context_line))
7146 return false;
7147
7148 return true;
7149 }
7150
UpdateFocusAppearanceAfterLayout()7151 void Document::UpdateFocusAppearanceAfterLayout() {
7152 update_focus_appearance_after_layout_ = true;
7153 }
7154
CancelFocusAppearanceUpdate()7155 void Document::CancelFocusAppearanceUpdate() {
7156 update_focus_appearance_after_layout_ = false;
7157 }
7158
WillUpdateFocusAppearance() const7159 bool Document::WillUpdateFocusAppearance() const {
7160 return update_focus_appearance_after_layout_;
7161 }
7162
UpdateFocusAppearance()7163 void Document::UpdateFocusAppearance() {
7164 update_focus_appearance_after_layout_ = false;
7165 Element* element = FocusedElement();
7166 if (!element)
7167 return;
7168 if (element->IsFocusable())
7169 element->UpdateFocusAppearance(SelectionBehaviorOnFocus::kRestore);
7170 }
7171
AttachRange(Range * range)7172 void Document::AttachRange(Range* range) {
7173 DCHECK(!ranges_.Contains(range));
7174 ranges_.insert(range);
7175 }
7176
DetachRange(Range * range)7177 void Document::DetachRange(Range* range) {
7178 // We don't DCHECK ranges_.contains(range) to allow us to call this
7179 // unconditionally to fix: https://bugs.webkit.org/show_bug.cgi?id=26044
7180 ranges_.erase(range);
7181 }
7182
InitDNSPrefetch()7183 void Document::InitDNSPrefetch() {
7184 Settings* settings = GetSettings();
7185
7186 have_explicitly_disabled_dns_prefetch_ = false;
7187 is_dns_prefetch_enabled_ = settings && settings->GetDNSPrefetchingEnabled() &&
7188 GetSecurityOrigin()->Protocol() == "http";
7189
7190 // Inherit DNS prefetch opt-out from parent frame
7191 if (Document* parent = ParentDocument()) {
7192 if (!parent->IsDNSPrefetchEnabled())
7193 is_dns_prefetch_enabled_ = false;
7194 }
7195 }
7196
ParseDNSPrefetchControlHeader(const String & dns_prefetch_control)7197 void Document::ParseDNSPrefetchControlHeader(
7198 const String& dns_prefetch_control) {
7199 if (EqualIgnoringASCIICase(dns_prefetch_control, "on") &&
7200 !have_explicitly_disabled_dns_prefetch_) {
7201 is_dns_prefetch_enabled_ = true;
7202 return;
7203 }
7204
7205 is_dns_prefetch_enabled_ = false;
7206 have_explicitly_disabled_dns_prefetch_ = true;
7207 }
7208
GetIntersectionObserverController()7209 IntersectionObserverController* Document::GetIntersectionObserverController() {
7210 return intersection_observer_controller_;
7211 }
7212
7213 IntersectionObserverController&
EnsureIntersectionObserverController()7214 Document::EnsureIntersectionObserverController() {
7215 if (!intersection_observer_controller_) {
7216 intersection_observer_controller_ =
7217 MakeGarbageCollected<IntersectionObserverController>(
7218 GetExecutionContext());
7219 }
7220 return *intersection_observer_controller_;
7221 }
7222
7223 ElementIntersectionObserverData*
DocumentExplicitRootIntersectionObserverData() const7224 Document::DocumentExplicitRootIntersectionObserverData() const {
7225 return document_explicit_root_intersection_observer_data_.Get();
7226 }
7227
7228 ElementIntersectionObserverData&
EnsureDocumentExplicitRootIntersectionObserverData()7229 Document::EnsureDocumentExplicitRootIntersectionObserverData() {
7230 if (!document_explicit_root_intersection_observer_data_) {
7231 document_explicit_root_intersection_observer_data_ =
7232 MakeGarbageCollected<ElementIntersectionObserverData>();
7233 }
7234 return *document_explicit_root_intersection_observer_data_;
7235 }
7236
EnsureResizeObserverController()7237 ResizeObserverController& Document::EnsureResizeObserverController() {
7238 if (!resize_observer_controller_) {
7239 resize_observer_controller_ =
7240 MakeGarbageCollected<ResizeObserverController>();
7241 }
7242 return *resize_observer_controller_;
7243 }
7244
AddConsoleMessage(ConsoleMessage * message,bool discard_duplicates)7245 void Document::AddConsoleMessage(ConsoleMessage* message,
7246 bool discard_duplicates) {
7247 // Don't let non-attached Documents spam the console.
7248 if (domWindow())
7249 domWindow()->AddConsoleMessage(message, discard_duplicates);
7250 }
7251
AddInspectorIssue(InspectorIssue * issue)7252 void Document::AddInspectorIssue(InspectorIssue* issue) {
7253 Page* page = GetPage();
7254
7255 if (!page) {
7256 return;
7257 }
7258
7259 page->GetInspectorIssueStorage().AddInspectorIssue(GetExecutionContext(),
7260 issue);
7261 }
7262
AddToTopLayer(Element * element,const Element * before)7263 void Document::AddToTopLayer(Element* element, const Element* before) {
7264 if (element->IsInTopLayer())
7265 return;
7266
7267 DCHECK(!top_layer_elements_.Contains(element));
7268 DCHECK(!before || top_layer_elements_.Contains(before));
7269 if (before) {
7270 wtf_size_t before_position = top_layer_elements_.Find(before);
7271 top_layer_elements_.insert(before_position, element);
7272 } else {
7273 top_layer_elements_.push_back(element);
7274 }
7275 element->SetIsInTopLayer(true);
7276 }
7277
RemoveFromTopLayer(Element * element)7278 void Document::RemoveFromTopLayer(Element* element) {
7279 if (!element->IsInTopLayer())
7280 return;
7281 wtf_size_t position = top_layer_elements_.Find(element);
7282 DCHECK_NE(position, kNotFound);
7283 top_layer_elements_.EraseAt(position);
7284 element->SetIsInTopLayer(false);
7285 }
7286
ActiveModalDialog() const7287 HTMLDialogElement* Document::ActiveModalDialog() const {
7288 for (auto it = top_layer_elements_.rbegin(); it != top_layer_elements_.rend();
7289 ++it) {
7290 if (auto* dialog = DynamicTo<HTMLDialogElement>(*it->Get()))
7291 return dialog;
7292 }
7293
7294 return nullptr;
7295 }
7296
exitPointerLock()7297 void Document::exitPointerLock() {
7298 if (!GetPage())
7299 return;
7300 if (Element* target = GetPage()->GetPointerLockController().GetElement()) {
7301 if (target->GetDocument() != this)
7302 return;
7303 GetPage()->GetPointerLockController().RequestPointerUnlock();
7304 }
7305 }
7306
PointerLockElement() const7307 Element* Document::PointerLockElement() const {
7308 if (!GetPage() || GetPage()->GetPointerLockController().LockPending())
7309 return nullptr;
7310 if (Element* element = GetPage()->GetPointerLockController().GetElement()) {
7311 if (element->GetDocument() == this)
7312 return element;
7313 }
7314 return nullptr;
7315 }
7316
DecrementLoadEventDelayCount()7317 void Document::DecrementLoadEventDelayCount() {
7318 DCHECK(load_event_delay_count_);
7319 --load_event_delay_count_;
7320
7321 if (!load_event_delay_count_)
7322 CheckLoadEventSoon();
7323 }
7324
DecrementLoadEventDelayCountAndCheckLoadEvent()7325 void Document::DecrementLoadEventDelayCountAndCheckLoadEvent() {
7326 DCHECK(load_event_delay_count_);
7327 --load_event_delay_count_;
7328
7329 if (!load_event_delay_count_)
7330 CheckCompleted();
7331 }
7332
CheckLoadEventSoon()7333 void Document::CheckLoadEventSoon() {
7334 if (GetFrame() && !load_event_delay_timer_.IsActive())
7335 load_event_delay_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
7336 }
7337
IsDelayingLoadEvent()7338 bool Document::IsDelayingLoadEvent() {
7339 // Always delay load events until after garbage collection.
7340 // This way we don't have to explicitly delay load events via
7341 // incrementLoadEventDelayCount and decrementLoadEventDelayCount in
7342 // Node destructors.
7343 if (ThreadState::Current()->SweepForbidden()) {
7344 if (!load_event_delay_count_)
7345 CheckLoadEventSoon();
7346 return true;
7347 }
7348 return load_event_delay_count_;
7349 }
7350
LoadEventDelayTimerFired(TimerBase *)7351 void Document::LoadEventDelayTimerFired(TimerBase*) {
7352 CheckCompleted();
7353 }
7354
LoadPluginsSoon()7355 void Document::LoadPluginsSoon() {
7356 // FIXME: Remove this timer once we don't need to compute layout to load
7357 // plugins.
7358 if (!plugin_loading_timer_.IsActive())
7359 plugin_loading_timer_.StartOneShot(base::TimeDelta(), FROM_HERE);
7360 }
7361
PluginLoadingTimerFired(TimerBase *)7362 void Document::PluginLoadingTimerFired(TimerBase*) {
7363 UpdateStyleAndLayout(DocumentUpdateReason::kPlugin);
7364 }
7365
GetScriptedAnimationController()7366 ScriptedAnimationController& Document::GetScriptedAnimationController() {
7367 return *scripted_animation_controller_;
7368 }
7369
RequestAnimationFrame(FrameRequestCallbackCollection::FrameCallback * callback)7370 int Document::RequestAnimationFrame(
7371 FrameRequestCallbackCollection::FrameCallback* callback) {
7372 return scripted_animation_controller_->RegisterFrameCallback(callback);
7373 }
7374
CancelAnimationFrame(int id)7375 void Document::CancelAnimationFrame(int id) {
7376 scripted_animation_controller_->CancelFrameCallback(id);
7377 }
7378
ServiceScriptedAnimations(base::TimeTicks monotonic_animation_start_time)7379 void Document::ServiceScriptedAnimations(
7380 base::TimeTicks monotonic_animation_start_time) {
7381 auto start_time = base::TimeTicks::Now();
7382 scripted_animation_controller_->ServiceScriptedAnimations(
7383 monotonic_animation_start_time);
7384 if (GetFrame()) {
7385 GetFrame()->GetFrameScheduler()->AddTaskTime(base::TimeTicks::Now() -
7386 start_time);
7387 }
7388 }
7389
RequestPostAnimationFrame(FrameRequestCallbackCollection::FrameCallback * cb)7390 int Document::RequestPostAnimationFrame(
7391 FrameRequestCallbackCollection::FrameCallback* cb) {
7392 return scripted_animation_controller_->RegisterPostFrameCallback(cb);
7393 }
7394
CancelPostAnimationFrame(int id)7395 void Document::CancelPostAnimationFrame(int id) {
7396 scripted_animation_controller_->CancelPostFrameCallback(id);
7397 }
7398
RunPostAnimationFrameCallbacks()7399 void Document::RunPostAnimationFrameCallbacks() {
7400 bool was_throttled = current_frame_is_throttled_;
7401 current_frame_is_throttled_ = false;
7402 if (was_throttled)
7403 return;
7404 scripted_animation_controller_->RunPostFrameCallbacks();
7405 }
7406
EnsureScriptedIdleTaskController()7407 ScriptedIdleTaskController& Document::EnsureScriptedIdleTaskController() {
7408 if (!scripted_idle_task_controller_) {
7409 scripted_idle_task_controller_ =
7410 ScriptedIdleTaskController::Create(domWindow());
7411 // We need to make sure that we don't start up if we're detached.
7412 if (!domWindow() || domWindow()->IsContextDestroyed()) {
7413 scripted_idle_task_controller_->ContextLifecycleStateChanged(
7414 mojom::FrameLifecycleState::kFrozen);
7415 }
7416 }
7417 return *scripted_idle_task_controller_;
7418 }
7419
RequestIdleCallback(ScriptedIdleTaskController::IdleTask * idle_task,const IdleRequestOptions * options)7420 int Document::RequestIdleCallback(
7421 ScriptedIdleTaskController::IdleTask* idle_task,
7422 const IdleRequestOptions* options) {
7423 return EnsureScriptedIdleTaskController().RegisterCallback(idle_task,
7424 options);
7425 }
7426
CancelIdleCallback(int id)7427 void Document::CancelIdleCallback(int id) {
7428 if (!scripted_idle_task_controller_)
7429 return;
7430 scripted_idle_task_controller_->CancelCallback(id);
7431 }
7432
Loader() const7433 DocumentLoader* Document::Loader() const {
7434 if (!frame_)
7435 return nullptr;
7436
7437 // TODO(dcheng): remove this check. frame_ is guaranteed to be non-null only
7438 // if frame_->GetDocument() == this.
7439 if (frame_->GetDocument() != this)
7440 return nullptr;
7441
7442 return frame_->Loader().GetDocumentLoader();
7443 }
7444
EventTargetNodeForDocument(Document * doc)7445 Node* EventTargetNodeForDocument(Document* doc) {
7446 if (!doc)
7447 return nullptr;
7448 Node* node = doc->FocusedElement();
7449 auto* plugin_document = DynamicTo<PluginDocument>(doc);
7450 if (plugin_document && !node) {
7451 node = plugin_document->PluginNode();
7452 }
7453 if (!node && IsA<HTMLDocument>(doc))
7454 node = doc->body();
7455 if (!node)
7456 node = doc->documentElement();
7457 return node;
7458 }
7459
AdjustFloatQuadsForScrollAndAbsoluteZoom(Vector<FloatQuad> & quads,const LayoutObject & layout_object) const7460 void Document::AdjustFloatQuadsForScrollAndAbsoluteZoom(
7461 Vector<FloatQuad>& quads,
7462 const LayoutObject& layout_object) const {
7463 if (!View())
7464 return;
7465
7466 for (wtf_size_t i = 0; i < quads.size(); ++i) {
7467 AdjustForAbsoluteZoom::AdjustFloatQuad(quads[i], layout_object);
7468 }
7469 }
7470
AdjustFloatRectForScrollAndAbsoluteZoom(FloatRect & rect,const LayoutObject & layout_object) const7471 void Document::AdjustFloatRectForScrollAndAbsoluteZoom(
7472 FloatRect& rect,
7473 const LayoutObject& layout_object) const {
7474 if (!View())
7475 return;
7476
7477 AdjustForAbsoluteZoom::AdjustFloatRect(rect, layout_object);
7478 }
7479
SetThreadedParsingEnabledForTesting(bool enabled)7480 void Document::SetThreadedParsingEnabledForTesting(bool enabled) {
7481 g_threaded_parsing_enabled_for_testing = enabled;
7482 }
7483
ThreadedParsingEnabledForTesting()7484 bool Document::ThreadedParsingEnabledForTesting() {
7485 return g_threaded_parsing_enabled_for_testing;
7486 }
7487
GetSnapCoordinator()7488 SnapCoordinator& Document::GetSnapCoordinator() {
7489 if (!snap_coordinator_)
7490 snap_coordinator_ = MakeGarbageCollected<SnapCoordinator>();
7491
7492 return *snap_coordinator_;
7493 }
7494
PerformScrollSnappingTasks()7495 void Document::PerformScrollSnappingTasks() {
7496 SnapCoordinator& snap_coordinator = GetSnapCoordinator();
7497 if (!snap_coordinator.AnySnapContainerDataNeedsUpdate())
7498 return;
7499 snap_coordinator.UpdateAllSnapContainerDataIfNeeded();
7500 if (RuntimeEnabledFeatures::ScrollSnapAfterLayoutEnabled())
7501 snap_coordinator.ResnapAllContainersIfNeeded();
7502 }
7503
SetContextFeatures(ContextFeatures & features)7504 void Document::SetContextFeatures(ContextFeatures& features) {
7505 context_features_ = &features;
7506 }
7507
UpdateHoverActiveState(bool is_active,bool update_active_chain,Element * inner_element)7508 void Document::UpdateHoverActiveState(bool is_active,
7509 bool update_active_chain,
7510 Element* inner_element) {
7511 if (is_active && frame_)
7512 frame_->GetEventHandler().NotifyElementActivated();
7513
7514 Element* inner_element_in_document = inner_element;
7515
7516 while (inner_element_in_document &&
7517 inner_element_in_document->GetDocument() != this) {
7518 inner_element_in_document->GetDocument().UpdateHoverActiveState(
7519 is_active, update_active_chain, inner_element_in_document);
7520 inner_element_in_document =
7521 inner_element_in_document->GetDocument().LocalOwner();
7522 }
7523
7524 UpdateDistributionForFlatTreeTraversal();
7525
7526 UpdateActiveState(is_active, update_active_chain, inner_element_in_document);
7527 UpdateHoverState(inner_element_in_document);
7528 }
7529
UpdateActiveState(bool is_active,bool update_active_chain,Element * inner_element_in_document)7530 void Document::UpdateActiveState(bool is_active,
7531 bool update_active_chain,
7532 Element* inner_element_in_document) {
7533 Element* old_active_element = GetActiveElement();
7534 if (old_active_element && !is_active) {
7535 // The oldActiveElement layoutObject is null, dropped on :active by setting
7536 // display: none, for instance. We still need to clear the ActiveChain as
7537 // the mouse is released.
7538 for (Element* element = old_active_element; element;
7539 element = FlatTreeTraversal::ParentElement(*element)) {
7540 element->SetActive(false);
7541 user_action_elements_.SetInActiveChain(element, false);
7542 }
7543 SetActiveElement(nullptr);
7544 } else {
7545 Element* new_active_element = inner_element_in_document;
7546 if (!old_active_element && new_active_element &&
7547 !new_active_element->IsDisabledFormControl() && is_active) {
7548 // We are setting the :active chain and freezing it. If future moves
7549 // happen, they will need to reference this chain.
7550 for (Element* element = new_active_element; element;
7551 element = FlatTreeTraversal::ParentElement(*element)) {
7552 user_action_elements_.SetInActiveChain(element, true);
7553 }
7554 SetActiveElement(new_active_element);
7555 }
7556 }
7557
7558 // If the mouse has just been pressed, set :active on the chain. Those (and
7559 // only those) nodes should remain :active until the mouse is released.
7560 bool allow_active_changes = !old_active_element && GetActiveElement();
7561 if (!allow_active_changes)
7562 return;
7563
7564 DCHECK(is_active);
7565
7566 Element* new_element = SkipDisplayNoneAncestors(inner_element_in_document);
7567
7568 // Now set the active state for our new object up to the root. If the mouse
7569 // is down and if this is a mouse move event, we want to restrict changes in
7570 // :active to only apply to elements that are in the :active chain that we
7571 // froze at the time the mouse went down.
7572 for (Element* curr = new_element; curr;
7573 curr = FlatTreeTraversal::ParentElement(*curr)) {
7574 if (update_active_chain || curr->InActiveChain())
7575 curr->SetActive(true);
7576 }
7577 }
7578
UpdateHoverState(Element * inner_element_in_document)7579 void Document::UpdateHoverState(Element* inner_element_in_document) {
7580 Element* old_hover_element = HoverElement();
7581
7582 // The passed in innerElement may not be a result of a hit test for the
7583 // current up-to-date flat/layout tree. That means the element may be
7584 // display:none at this point. Skip up the ancestor chain until we reach an
7585 // element with a layoutObject or a display:contents element.
7586 Element* new_hover_element =
7587 SkipDisplayNoneAncestors(inner_element_in_document);
7588
7589 // Update our current hover element.
7590 SetHoverElement(new_hover_element);
7591
7592 if (old_hover_element == new_hover_element)
7593 return;
7594
7595 Node* ancestor_element = nullptr;
7596 if (old_hover_element && old_hover_element->isConnected() &&
7597 new_hover_element) {
7598 Node* ancestor = FlatTreeTraversal::CommonAncestor(*old_hover_element,
7599 *new_hover_element);
7600 if (auto* element = DynamicTo<Element>(ancestor))
7601 ancestor_element = element;
7602 }
7603
7604 HeapVector<Member<Element>, 32> elements_to_remove_from_chain;
7605 HeapVector<Member<Element>, 32> elements_to_add_to_hover_chain;
7606
7607 // The old hover path only needs to be cleared up to (and not including) the
7608 // common ancestor;
7609 //
7610 // TODO(emilio): old_hover_element may be disconnected from the tree already.
7611 if (old_hover_element && old_hover_element->isConnected()) {
7612 for (Element* curr = old_hover_element; curr && curr != ancestor_element;
7613 curr = FlatTreeTraversal::ParentElement(*curr)) {
7614 elements_to_remove_from_chain.push_back(curr);
7615 }
7616 }
7617
7618 // Now set the hover state for our new object up to the root.
7619 for (Element* curr = new_hover_element; curr;
7620 curr = FlatTreeTraversal::ParentElement(*curr)) {
7621 elements_to_add_to_hover_chain.push_back(curr);
7622 }
7623
7624 for (Element* element : elements_to_remove_from_chain)
7625 element->SetHovered(false);
7626
7627 bool saw_common_ancestor = false;
7628 for (Element* element : elements_to_add_to_hover_chain) {
7629 if (element == ancestor_element)
7630 saw_common_ancestor = true;
7631 if (!saw_common_ancestor || element == hover_element_)
7632 element->SetHovered(true);
7633 }
7634 }
7635
HaveScriptBlockingStylesheetsLoaded() const7636 bool Document::HaveScriptBlockingStylesheetsLoaded() const {
7637 return style_engine_->HaveScriptBlockingStylesheetsLoaded();
7638 }
7639
HaveRenderBlockingResourcesLoaded() const7640 bool Document::HaveRenderBlockingResourcesLoaded() const {
7641 return HaveImportsLoaded() &&
7642 style_engine_->HaveRenderBlockingStylesheetsLoaded() &&
7643 !font_preload_manager_.HasPendingRenderBlockingFonts();
7644 }
7645
GetCachedLocale(const AtomicString & locale)7646 Locale& Document::GetCachedLocale(const AtomicString& locale) {
7647 AtomicString locale_key = locale;
7648 if (locale.IsEmpty() ||
7649 !RuntimeEnabledFeatures::LangAttributeAwareFormControlUIEnabled())
7650 return Locale::DefaultLocale();
7651 LocaleIdentifierToLocaleMap::AddResult result =
7652 locale_cache_.insert(locale_key, nullptr);
7653 if (result.is_new_entry)
7654 result.stored_value->value = Locale::Create(locale_key);
7655 return *(result.stored_value->value);
7656 }
7657
GetAnimationClock()7658 AnimationClock& Document::GetAnimationClock() {
7659 DCHECK(GetPage());
7660 return GetPage()->Animator().Clock();
7661 }
7662
GetAnimationClock() const7663 const AnimationClock& Document::GetAnimationClock() const {
7664 DCHECK(GetPage());
7665 return GetPage()->Animator().Clock();
7666 }
7667
EnsureTemplateDocument()7668 Document& Document::EnsureTemplateDocument() {
7669 if (IsTemplateDocument())
7670 return *this;
7671
7672 if (template_document_)
7673 return *template_document_;
7674
7675 if (IsA<HTMLDocument>(this)) {
7676 template_document_ = MakeGarbageCollected<HTMLDocument>(
7677 DocumentInit::Create()
7678 .WithContextDocument(ContextDocument())
7679 .WithURL(BlankURL())
7680 .WithNewRegistrationContext());
7681 } else {
7682 template_document_ = MakeGarbageCollected<Document>(
7683 DocumentInit::Create()
7684 .WithContextDocument(ContextDocument())
7685 .WithURL(BlankURL()));
7686 }
7687
7688 template_document_->template_document_host_ = this; // balanced in dtor.
7689
7690 return *template_document_.Get();
7691 }
7692
DidAssociateFormControl(Element * element)7693 void Document::DidAssociateFormControl(Element* element) {
7694 if (!GetFrame() || !GetFrame()->GetPage() || !HasFinishedParsing())
7695 return;
7696
7697 // We add a slight delay because this could be called rapidly.
7698 if (!did_associate_form_controls_timer_.IsActive()) {
7699 did_associate_form_controls_timer_.StartOneShot(
7700 base::TimeDelta::FromMilliseconds(300), FROM_HERE);
7701 }
7702 }
7703
DidAssociateFormControlsTimerFired(TimerBase * timer)7704 void Document::DidAssociateFormControlsTimerFired(TimerBase* timer) {
7705 DCHECK_EQ(timer, &did_associate_form_controls_timer_);
7706 if (!GetFrame() || !GetFrame()->GetPage())
7707 return;
7708
7709 GetFrame()->GetPage()->GetChromeClient().DidAssociateFormControlsAfterLoad(
7710 GetFrame());
7711 }
7712
DevicePixelRatio() const7713 float Document::DevicePixelRatio() const {
7714 return frame_ ? frame_->DevicePixelRatio() : 1.0;
7715 }
7716
GetTextAutosizer()7717 TextAutosizer* Document::GetTextAutosizer() {
7718 if (!text_autosizer_)
7719 text_autosizer_ = MakeGarbageCollected<TextAutosizer>(this);
7720 return text_autosizer_.Get();
7721 }
7722
SetPseudoStateForTesting(Element & element,const String & pseudo,bool matches)7723 bool Document::SetPseudoStateForTesting(Element& element,
7724 const String& pseudo,
7725 bool matches) {
7726 DCHECK(WebTestSupport::IsRunningWebTest());
7727 auto& set = UserActionElements();
7728 if (pseudo == ":focus") {
7729 set.SetFocused(&element, matches);
7730 element.PseudoStateChanged(CSSSelector::kPseudoFocus);
7731 } else if (pseudo == ":focus-within") {
7732 set.SetHasFocusWithin(&element, matches);
7733 element.PseudoStateChanged(CSSSelector::kPseudoFocusWithin);
7734 } else if (pseudo == ":active") {
7735 set.SetActive(&element, matches);
7736 element.PseudoStateChanged(CSSSelector::kPseudoActive);
7737 } else if (pseudo == ":hover") {
7738 set.SetHovered(&element, matches);
7739 element.PseudoStateChanged(CSSSelector::kPseudoHover);
7740 } else {
7741 return false;
7742 }
7743 return true;
7744 }
7745
EnqueueAutofocusCandidate(Element & element)7746 void Document::EnqueueAutofocusCandidate(Element& element) {
7747 // https://html.spec.whatwg.org/C#the-autofocus-attribute
7748 // 7. If topDocument's autofocus processed flag is false, then remove the
7749 // element from topDocument's autofocus candidates, and append the element
7750 // to topDocument's autofocus candidates.
7751 if (autofocus_processed_flag_)
7752 return;
7753 wtf_size_t index = autofocus_candidates_.Find(&element);
7754 if (index != WTF::kNotFound)
7755 autofocus_candidates_.EraseAt(index);
7756 autofocus_candidates_.push_back(element);
7757 }
7758
HasAutofocusCandidates() const7759 bool Document::HasAutofocusCandidates() const {
7760 return autofocus_candidates_.size() > 0;
7761 }
7762
7763 // https://html.spec.whatwg.org/C/#flush-autofocus-candidates
FlushAutofocusCandidates()7764 void Document::FlushAutofocusCandidates() {
7765 // 1. If topDocument's autofocus processed flag is true, then return.
7766 if (autofocus_processed_flag_)
7767 return;
7768
7769 // 3. If candidates is empty, then return.
7770 if (autofocus_candidates_.IsEmpty())
7771 return;
7772
7773 // 4. If topDocument's focused area is not topDocument itself, or
7774 // topDocument's URL's fragment is not empty, then:
7775 // 1. Empty candidates.
7776 // 2. Set topDocument's autofocus processed flag to true.
7777 // 3. Return.
7778 if (AdjustedFocusedElement()) {
7779 autofocus_candidates_.clear();
7780 autofocus_processed_flag_ = true;
7781 AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
7782 mojom::ConsoleMessageSource::kRendering,
7783 mojom::ConsoleMessageLevel::kInfo,
7784 "Autofocus processing was blocked because a "
7785 "document already has a focused element."));
7786 return;
7787 }
7788 if (HasNonEmptyFragment()) {
7789 autofocus_candidates_.clear();
7790 autofocus_processed_flag_ = true;
7791 AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
7792 mojom::ConsoleMessageSource::kRendering,
7793 mojom::ConsoleMessageLevel::kInfo,
7794 "Autofocus processing was blocked because a "
7795 "document's URL has a fragment '#" +
7796 Url().FragmentIdentifier() + "'."));
7797 return;
7798 }
7799
7800 // 5. While candidates is not empty:
7801 while (!autofocus_candidates_.IsEmpty()) {
7802 // 5.1. Let element be candidates[0].
7803 Element& element = *autofocus_candidates_[0];
7804
7805 // 5.2. Let doc be element's node document.
7806 Document* doc = &element.GetDocument();
7807
7808 // 5.3. If doc is not fully active, then remove element from candidates,
7809 // and continue.
7810 // 5.4. If doc's browsing context's top-level browsing context is not same
7811 // as topDocument's browsing context, then remove element from candidates,
7812 // and continue.
7813 if (&doc->TopDocument() != this) {
7814 autofocus_candidates_.EraseAt(0);
7815 continue;
7816 }
7817
7818 // The element is in the fallback content of an OBJECT of which
7819 // fallback state is not fixed yet.
7820 // TODO(tkent): Standardize this behavior.
7821 if (IsInIndeterminateObjectAncestor(&element)) {
7822 return;
7823 }
7824
7825 // 5.5. If doc's script-blocking style sheet counter is greater than 0,
7826 // then return.
7827 // TODO(tkent): Is this necessary? WPT spin-by-blocking-style-sheet.html
7828 // doesn't hit this condition, and FlushAutofocusCandidates() is not called
7829 // until the stylesheet is loaded.
7830 StyleEngine& engine = GetStyleEngine();
7831 if (engine.HasPendingScriptBlockingSheets() ||
7832 engine.HasPendingRenderBlockingSheets()) {
7833 return;
7834 }
7835
7836 // 5.6. Remove element from candidates.
7837 autofocus_candidates_.EraseAt(0);
7838
7839 // 5.7. Let inclusiveAncestorDocuments be a list consisting of doc, plus
7840 // the active documents of each of doc's browsing context's ancestor
7841 // browsing contexts.
7842 // 5.8. If URL's fragment of any Document in inclusiveAncestorDocuments
7843 // is not empty, then continue.
7844 if (doc != this) {
7845 for (HTMLFrameOwnerElement* frameOwner = doc->LocalOwner();
7846 !doc->HasNonEmptyFragment() && frameOwner;
7847 frameOwner = doc->LocalOwner()) {
7848 doc = &frameOwner->GetDocument();
7849 }
7850 if (doc->HasNonEmptyFragment()) {
7851 AddConsoleMessage(MakeGarbageCollected<ConsoleMessage>(
7852 mojom::ConsoleMessageSource::kRendering,
7853 mojom::ConsoleMessageLevel::kInfo,
7854 "Autofocus processing was blocked because a "
7855 "document's URL has a fragment '#" +
7856 doc->Url().FragmentIdentifier() + "'."));
7857 continue;
7858 }
7859 DCHECK_EQ(doc, this);
7860 }
7861
7862 // 9. Let target be element.
7863 Element* target = &element;
7864
7865 // 10. If target is not a focusable area, then set target to the result of
7866 // getting the focusable area for target.
7867 element.GetDocument().UpdateStyleAndLayoutTree();
7868 if (!target->IsFocusable())
7869 target = target->GetFocusableArea();
7870
7871 // 11. If target is not null, then:
7872 if (target) {
7873 // 11.1. Empty candidates.
7874 // 11.2. Set topDocument's autofocus processed flag to true.
7875 FinalizeAutofocus();
7876 // 11.3. Run the focusing steps for element.
7877 element.focus();
7878 } else {
7879 // TODO(tkent): Show a console message, and fix LocalNTP*Test.*
7880 // in browser_tests.
7881 }
7882 }
7883 }
7884
FinalizeAutofocus()7885 void Document::FinalizeAutofocus() {
7886 autofocus_candidates_.clear();
7887 autofocus_processed_flag_ = true;
7888 }
7889
HasNonEmptyFragment() const7890 bool Document::HasNonEmptyFragment() const {
7891 return !Url().FragmentIdentifier().IsEmpty();
7892 }
7893
ActiveElement() const7894 Element* Document::ActiveElement() const {
7895 if (Element* element = AdjustedFocusedElement())
7896 return element;
7897 return body();
7898 }
7899
hasFocus() const7900 bool Document::hasFocus() const {
7901 return GetPage() && GetPage()->GetFocusController().IsDocumentFocused(*this);
7902 }
7903
BodyAttributeValue(const QualifiedName & name) const7904 const AtomicString& Document::BodyAttributeValue(
7905 const QualifiedName& name) const {
7906 if (auto* bodyElement = body())
7907 return bodyElement->FastGetAttribute(name);
7908 return g_null_atom;
7909 }
7910
SetBodyAttribute(const QualifiedName & name,const AtomicString & value)7911 void Document::SetBodyAttribute(const QualifiedName& name,
7912 const AtomicString& value) {
7913 if (auto* bodyElement = body()) {
7914 // FIXME: This check is apparently for benchmarks that set the same value
7915 // repeatedly. It's not clear what benchmarks though, it's also not clear
7916 // why we don't avoid causing a style recalc when setting the same value to
7917 // a presentational attribute in the common case.
7918 if (bodyElement->FastGetAttribute(name) != value)
7919 bodyElement->setAttribute(name, value);
7920 }
7921 }
7922
bgColor() const7923 const AtomicString& Document::bgColor() const {
7924 return BodyAttributeValue(html_names::kBgcolorAttr);
7925 }
7926
setBgColor(const AtomicString & value)7927 void Document::setBgColor(const AtomicString& value) {
7928 if (!IsFrameSet())
7929 SetBodyAttribute(html_names::kBgcolorAttr, value);
7930 }
7931
fgColor() const7932 const AtomicString& Document::fgColor() const {
7933 return BodyAttributeValue(html_names::kTextAttr);
7934 }
7935
setFgColor(const AtomicString & value)7936 void Document::setFgColor(const AtomicString& value) {
7937 if (!IsFrameSet())
7938 SetBodyAttribute(html_names::kTextAttr, value);
7939 }
7940
alinkColor() const7941 const AtomicString& Document::alinkColor() const {
7942 return BodyAttributeValue(html_names::kAlinkAttr);
7943 }
7944
setAlinkColor(const AtomicString & value)7945 void Document::setAlinkColor(const AtomicString& value) {
7946 if (!IsFrameSet())
7947 SetBodyAttribute(html_names::kAlinkAttr, value);
7948 }
7949
linkColor() const7950 const AtomicString& Document::linkColor() const {
7951 return BodyAttributeValue(html_names::kLinkAttr);
7952 }
7953
setLinkColor(const AtomicString & value)7954 void Document::setLinkColor(const AtomicString& value) {
7955 if (!IsFrameSet())
7956 SetBodyAttribute(html_names::kLinkAttr, value);
7957 }
7958
vlinkColor() const7959 const AtomicString& Document::vlinkColor() const {
7960 return BodyAttributeValue(html_names::kVlinkAttr);
7961 }
7962
setVlinkColor(const AtomicString & value)7963 void Document::setVlinkColor(const AtomicString& value) {
7964 if (!IsFrameSet())
7965 SetBodyAttribute(html_names::kVlinkAttr, value);
7966 }
7967
7968 template <unsigned type>
ShouldInvalidateNodeListCachesForAttr(const LiveNodeListRegistry & node_lists,const QualifiedName & attr_name)7969 bool ShouldInvalidateNodeListCachesForAttr(
7970 const LiveNodeListRegistry& node_lists,
7971 const QualifiedName& attr_name) {
7972 auto invalidation_type = static_cast<NodeListInvalidationType>(type);
7973 if (node_lists.ContainsInvalidationType(invalidation_type) &&
7974 LiveNodeListBase::ShouldInvalidateTypeOnAttributeChange(invalidation_type,
7975 attr_name))
7976 return true;
7977 return ShouldInvalidateNodeListCachesForAttr<type + 1>(node_lists, attr_name);
7978 }
7979
7980 template <>
ShouldInvalidateNodeListCachesForAttr(const LiveNodeListRegistry &,const QualifiedName &)7981 bool ShouldInvalidateNodeListCachesForAttr<kNumNodeListInvalidationTypes>(
7982 const LiveNodeListRegistry&,
7983 const QualifiedName&) {
7984 return false;
7985 }
7986
ShouldInvalidateNodeListCaches(const QualifiedName * attr_name) const7987 bool Document::ShouldInvalidateNodeListCaches(
7988 const QualifiedName* attr_name) const {
7989 if (attr_name) {
7990 return ShouldInvalidateNodeListCachesForAttr<
7991 kDoNotInvalidateOnAttributeChanges + 1>(node_lists_, *attr_name);
7992 }
7993
7994 // If the invalidation is not for an attribute, invalidation is needed if
7995 // there is any node list present (with any invalidation type).
7996 return !node_lists_.IsEmpty();
7997 }
7998
InvalidateNodeListCaches(const QualifiedName * attr_name)7999 void Document::InvalidateNodeListCaches(const QualifiedName* attr_name) {
8000 for (const LiveNodeListBase* list : lists_invalidated_at_document_)
8001 list->InvalidateCacheForAttribute(attr_name);
8002 }
8003
PlatformColorsChanged()8004 void Document::PlatformColorsChanged() {
8005 if (!IsActive())
8006 return;
8007
8008 GetStyleEngine().PlatformColorsChanged();
8009 }
8010
DidEnforceInsecureRequestPolicy()8011 void Document::DidEnforceInsecureRequestPolicy() {
8012 if (!GetFrame())
8013 return;
8014 GetFrame()->GetLocalFrameHostRemote().EnforceInsecureRequestPolicy(
8015 GetSecurityContext().GetInsecureRequestPolicy());
8016 }
8017
DidEnforceInsecureNavigationsSet()8018 void Document::DidEnforceInsecureNavigationsSet() {
8019 if (!GetFrame())
8020 return;
8021 GetFrame()->GetLocalFrameHostRemote().EnforceInsecureNavigationsSet(
8022 SecurityContext::SerializeInsecureNavigationSet(
8023 GetSecurityContext().InsecureNavigationsToUpgrade()));
8024 }
8025
SetShadowCascadeOrder(ShadowCascadeOrder order)8026 void Document::SetShadowCascadeOrder(ShadowCascadeOrder order) {
8027 DCHECK_NE(order, ShadowCascadeOrder::kShadowCascadeNone);
8028 if (order == shadow_cascade_order_)
8029 return;
8030
8031 if (order == ShadowCascadeOrder::kShadowCascadeV0) {
8032 may_contain_v0_shadow_ = true;
8033 if (shadow_cascade_order_ == ShadowCascadeOrder::kShadowCascadeV1) {
8034 // ::slotted() rules has to be moved to tree boundary rule sets.
8035 style_engine_->V0ShadowAddedOnV1Document();
8036 UseCounter::Count(*this, WebFeature::kMixedShadowRootV0AndV1);
8037 }
8038 }
8039
8040 // For V0 -> V1 upgrade, we need style recalculation for all elements.
8041 if (shadow_cascade_order_ == ShadowCascadeOrder::kShadowCascadeV0 &&
8042 order == ShadowCascadeOrder::kShadowCascadeV1) {
8043 GetStyleEngine().MarkAllElementsForStyleRecalc(
8044 StyleChangeReasonForTracing::Create(style_change_reason::kShadow));
8045 UseCounter::Count(*this, WebFeature::kMixedShadowRootV0AndV1);
8046 }
8047
8048 if (order > shadow_cascade_order_)
8049 shadow_cascade_order_ = order;
8050 }
8051
GetPropertyRegistry()8052 PropertyRegistry* Document::GetPropertyRegistry() {
8053 // TODO(timloh): When the flag is removed, return a reference instead.
8054 if (!property_registry_ && RuntimeEnabledFeatures::CSSVariables2Enabled())
8055 property_registry_ = MakeGarbageCollected<PropertyRegistry>();
8056 return property_registry_;
8057 }
8058
GetPropertyRegistry() const8059 const PropertyRegistry* Document::GetPropertyRegistry() const {
8060 return const_cast<Document*>(this)->GetPropertyRegistry();
8061 }
8062
MaybeQueueSendDidEditFieldInInsecureContext()8063 void Document::MaybeQueueSendDidEditFieldInInsecureContext() {
8064 if (logged_field_edit_ || sensitive_input_edited_task_.IsActive() ||
8065 IsSecureContext()) {
8066 // Send a message on the first edit; the browser process doesn't care
8067 // about the presence of additional edits.
8068 //
8069 // The browser process only cares about editing fields on pages where the
8070 // top-level URL is not secure. Secure contexts must have a top-level URL
8071 // that is secure, so there is no need to send notifications for editing
8072 // in secure contexts.
8073 return;
8074 }
8075 logged_field_edit_ = true;
8076 sensitive_input_edited_task_ = PostCancellableTask(
8077 *GetTaskRunner(TaskType::kUserInteraction), FROM_HERE,
8078 WTF::Bind(&Document::SendDidEditFieldInInsecureContext,
8079 WrapWeakPersistent(this)));
8080 }
8081
GetProbeSink()8082 CoreProbeSink* Document::GetProbeSink() {
8083 LocalFrame* frame = GetFrame();
8084 if (!frame && TemplateDocumentHost())
8085 frame = TemplateDocumentHost()->GetFrame();
8086 return probe::ToCoreProbeSink(frame);
8087 }
8088
GetBrowserInterfaceBroker()8089 BrowserInterfaceBrokerProxy& Document::GetBrowserInterfaceBroker() {
8090 if (!GetFrame())
8091 return GetEmptyBrowserInterfaceBroker();
8092
8093 return GetFrame()->GetBrowserInterfaceBroker();
8094 }
8095
GetResourceCoordinator()8096 DocumentResourceCoordinator* Document::GetResourceCoordinator() {
8097 if (!resource_coordinator_ && GetFrame()) {
8098 resource_coordinator_ =
8099 DocumentResourceCoordinator::MaybeCreate(GetBrowserInterfaceBroker());
8100 }
8101 return resource_coordinator_.get();
8102 }
8103
GetScheduler()8104 FrameOrWorkerScheduler* Document::GetScheduler() {
8105 DCHECK(IsMainThread());
8106 return GetExecutionContext()->GetScheduler();
8107 }
8108
GetTaskRunner(TaskType type)8109 scoped_refptr<base::SingleThreadTaskRunner> Document::GetTaskRunner(
8110 TaskType type) {
8111 DCHECK(IsMainThread());
8112
8113 if (ContextDocument() && ContextDocument()->GetFrame())
8114 return ContextDocument()->GetFrame()->GetTaskRunner(type);
8115 // In most cases, ContextDocument() will get us to a relevant Frame. In some
8116 // cases, though, there isn't a good candidate (most commonly when either the
8117 // passed-in document or ContextDocument() used to be attached to a Frame but
8118 // has since been detached).
8119 return Thread::Current()->GetTaskRunner();
8120 }
8121
featurePolicy()8122 DOMFeaturePolicy* Document::featurePolicy() {
8123 if (!policy_)
8124 policy_ = MakeGarbageCollected<DOMDocumentPolicy>(this);
8125 return policy_.Get();
8126 }
8127
RequiredCSP()8128 const AtomicString& Document::RequiredCSP() {
8129 if (!Loader())
8130 return g_null_atom;
8131 return frame_->Loader().RequiredCSP();
8132 }
8133
ComputedStyleMap(Element * element)8134 StylePropertyMapReadOnly* Document::ComputedStyleMap(Element* element) {
8135 ElementComputedStyleMap::AddResult add_result =
8136 element_computed_style_map_.insert(element, nullptr);
8137 if (add_result.is_new_entry) {
8138 add_result.stored_value->value =
8139 MakeGarbageCollected<ComputedStylePropertyMap>(element);
8140 }
8141 return add_result.stored_value->value;
8142 }
8143
AddComputedStyleMapItem(Element * element,StylePropertyMapReadOnly * computed_style)8144 void Document::AddComputedStyleMapItem(
8145 Element* element,
8146 StylePropertyMapReadOnly* computed_style) {
8147 element_computed_style_map_.insert(element, computed_style);
8148 }
8149
RemoveComputedStyleMapItem(Element * element)8150 StylePropertyMapReadOnly* Document::RemoveComputedStyleMapItem(
8151 Element* element) {
8152 return element_computed_style_map_.Take(element);
8153 }
8154
Trace(Visitor * visitor)8155 void Document::Trace(Visitor* visitor) {
8156 visitor->Trace(security_context_);
8157 visitor->Trace(imports_controller_);
8158 visitor->Trace(use_counter_during_construction_);
8159 visitor->Trace(doc_type_);
8160 visitor->Trace(implementation_);
8161 visitor->Trace(autofocus_candidates_);
8162 visitor->Trace(focused_element_);
8163 visitor->Trace(sequential_focus_navigation_starting_point_);
8164 visitor->Trace(hover_element_);
8165 visitor->Trace(active_element_);
8166 visitor->Trace(document_element_);
8167 visitor->Trace(root_scroller_controller_);
8168 visitor->Trace(title_element_);
8169 visitor->Trace(ax_object_cache_);
8170 visitor->Trace(markers_);
8171 visitor->Trace(css_target_);
8172 visitor->Trace(current_script_stack_);
8173 visitor->Trace(script_runner_);
8174 visitor->Trace(lists_invalidated_at_document_);
8175 visitor->Trace(node_lists_);
8176 visitor->Trace(top_layer_elements_);
8177 visitor->Trace(elem_sheet_);
8178 visitor->Trace(node_iterators_);
8179 visitor->Trace(ranges_);
8180 visitor->Trace(document_explicit_root_intersection_observer_data_);
8181 visitor->Trace(style_engine_);
8182 visitor->Trace(form_controller_);
8183 visitor->Trace(visited_link_state_);
8184 visitor->Trace(element_computed_style_map_);
8185 visitor->Trace(window_agent_factory_);
8186 visitor->Trace(frame_);
8187 visitor->Trace(dom_window_);
8188 visitor->Trace(fetcher_);
8189 visitor->Trace(parser_);
8190 visitor->Trace(context_features_);
8191 visitor->Trace(http_refresh_scheduler_);
8192 visitor->Trace(style_sheet_list_);
8193 visitor->Trace(document_timing_);
8194 visitor->Trace(media_query_matcher_);
8195 visitor->Trace(scripted_animation_controller_);
8196 visitor->Trace(scripted_idle_task_controller_);
8197 visitor->Trace(text_autosizer_);
8198 visitor->Trace(registration_context_);
8199 visitor->Trace(custom_element_microtask_run_queue_);
8200 visitor->Trace(element_data_cache_);
8201 visitor->Trace(use_elements_needing_update_);
8202 visitor->Trace(template_document_);
8203 visitor->Trace(template_document_host_);
8204 visitor->Trace(user_action_elements_);
8205 visitor->Trace(svg_extensions_);
8206 visitor->Trace(document_animations_);
8207 visitor->Trace(timeline_);
8208 visitor->Trace(pending_animations_);
8209 visitor->Trace(worklet_animation_controller_);
8210 visitor->Trace(context_document_);
8211 visitor->Trace(canvas_font_cache_);
8212 visitor->Trace(intersection_observer_controller_);
8213 visitor->Trace(snap_coordinator_);
8214 visitor->Trace(resize_observer_controller_);
8215 visitor->Trace(property_registry_);
8216 visitor->Trace(network_state_observer_);
8217 visitor->Trace(policy_);
8218 visitor->Trace(slot_assignment_engine_);
8219 visitor->Trace(viewport_data_);
8220 visitor->Trace(display_lock_contexts_);
8221 visitor->Trace(navigation_initiator_);
8222 visitor->Trace(lazy_load_image_observer_);
8223 visitor->Trace(isolated_world_csp_map_);
8224 visitor->Trace(find_in_page_root_);
8225 visitor->Trace(computed_node_mapping_);
8226 visitor->Trace(mime_handler_view_before_unload_event_listener_);
8227 visitor->Trace(cookie_jar_);
8228 visitor->Trace(synchronous_mutation_observer_list_);
8229 visitor->Trace(element_explicitly_set_attr_elements_map_);
8230 visitor->Trace(display_lock_activation_observer_);
8231 visitor->Trace(permission_service_);
8232 visitor->Trace(font_preload_manager_);
8233 Supplementable<Document>::Trace(visitor);
8234 TreeScope::Trace(visitor);
8235 ContainerNode::Trace(visitor);
8236 }
8237
RecordUkmOutliveTimeAfterShutdown(int outlive_time_count)8238 void Document::RecordUkmOutliveTimeAfterShutdown(int outlive_time_count) {
8239 if (!needs_to_record_ukm_outlive_time_)
8240 return;
8241
8242 DCHECK(ukm_recorder_);
8243 DCHECK(ukm_source_id_ != ukm::kInvalidSourceId);
8244
8245 ukm::builders::Document_OutliveTimeAfterShutdown(ukm_source_id_)
8246 .SetGCCount(outlive_time_count)
8247 .Record(ukm_recorder_.get());
8248 }
8249
CurrentFrameHadRAF() const8250 bool Document::CurrentFrameHadRAF() const {
8251 return scripted_animation_controller_->CurrentFrameHadRAF();
8252 }
8253
NextFrameHasPendingRAF() const8254 bool Document::NextFrameHasPendingRAF() const {
8255 return scripted_animation_controller_->NextFrameHasPendingRAF();
8256 }
8257
NavigateLocalAdsFrames()8258 void Document::NavigateLocalAdsFrames() {
8259 // This navigates all the frames detected as an advertisement to about:blank.
8260 DCHECK(frame_);
8261 for (Frame* child = frame_->Tree().FirstChild(); child;
8262 child = child->Tree().TraverseNext(frame_)) {
8263 if (auto* child_local_frame = DynamicTo<LocalFrame>(child)) {
8264 if (child_local_frame->IsAdSubframe()) {
8265 FrameLoadRequest request(this, ResourceRequest(BlankURL()));
8266 child_local_frame->Navigate(request, WebFrameLoadType::kStandard);
8267 }
8268 }
8269 // TODO(yuzus): Once AdsTracker for remote frames is implemented and OOPIF
8270 // is enabled on low-end devices, navigate remote ads as well.
8271 }
8272 }
8273
GetSlotAssignmentEngine()8274 SlotAssignmentEngine& Document::GetSlotAssignmentEngine() {
8275 if (!slot_assignment_engine_)
8276 slot_assignment_engine_ = MakeGarbageCollected<SlotAssignmentEngine>();
8277 return *slot_assignment_engine_;
8278 }
8279
IsSlotAssignmentOrLegacyDistributionDirty() const8280 bool Document::IsSlotAssignmentOrLegacyDistributionDirty() const {
8281 if (ChildNeedsDistributionRecalc())
8282 return true;
8283 if (slot_assignment_engine_ &&
8284 slot_assignment_engine_->HasPendingSlotAssignmentRecalc()) {
8285 return true;
8286 }
8287 return false;
8288 }
8289
IsLazyLoadPolicyEnforced() const8290 bool Document::IsLazyLoadPolicyEnforced() const {
8291 return RuntimeEnabledFeatures::ExperimentalProductivityFeaturesEnabled() &&
8292 !GetSecurityContext().GetFeaturePolicy()->IsFeatureEnabled(
8293 mojom::blink::FeaturePolicyFeature::kLazyLoad);
8294 }
8295
IsFocusAllowed() const8296 bool Document::IsFocusAllowed() const {
8297 if (frame_ && frame_->GetPage()->InsidePortal())
8298 return false;
8299
8300 if (!frame_ || frame_->IsMainFrame() ||
8301 LocalFrame::HasTransientUserActivation(frame_)) {
8302 // 'autofocus' runs Element::focus asynchronously at which point the
8303 // document might not have a frame (see https://crbug.com/960224).
8304 return true;
8305 }
8306
8307 WebFeature uma_type;
8308 bool sandboxed = IsSandboxed(mojom::blink::WebSandboxFlags::kNavigation);
8309 bool ad = frame_->IsAdSubframe();
8310 if (sandboxed) {
8311 uma_type = ad ? WebFeature::kFocusWithoutUserActivationSandboxedAdFrame
8312 : WebFeature::kFocusWithoutUserActivationSandboxedNotAdFrame;
8313 } else {
8314 uma_type =
8315 ad ? WebFeature::kFocusWithoutUserActivationNotSandboxedAdFrame
8316 : WebFeature::kFocusWithoutUserActivationNotSandboxedNotAdFrame;
8317 }
8318 CountUse(uma_type);
8319 if (!RuntimeEnabledFeatures::BlockingFocusWithoutUserActivationEnabled())
8320 return true;
8321 return IsFeatureEnabled(
8322 mojom::blink::FeaturePolicyFeature::kFocusWithoutUserActivation);
8323 }
8324
NavigationInitiator()8325 NavigationInitiatorImpl& Document::NavigationInitiator() {
8326 if (!navigation_initiator_) {
8327 navigation_initiator_ =
8328 MakeGarbageCollected<NavigationInitiatorImpl>(*this);
8329 }
8330 return *navigation_initiator_;
8331 }
8332
EnsureLazyLoadImageObserver()8333 LazyLoadImageObserver& Document::EnsureLazyLoadImageObserver() {
8334 if (!lazy_load_image_observer_) {
8335 lazy_load_image_observer_ =
8336 MakeGarbageCollected<LazyLoadImageObserver>(*this);
8337 }
8338 return *lazy_load_image_observer_;
8339 }
8340
GetWindowAgent()8341 WindowAgent& Document::GetWindowAgent() {
8342 return *static_cast<WindowAgent*>(GetAgent());
8343 }
8344
CountPotentialFeaturePolicyViolation(mojom::blink::FeaturePolicyFeature feature) const8345 void Document::CountPotentialFeaturePolicyViolation(
8346 mojom::blink::FeaturePolicyFeature feature) const {
8347 wtf_size_t index = static_cast<wtf_size_t>(feature);
8348 if (potentially_violated_features_.size() == 0) {
8349 potentially_violated_features_.resize(
8350 static_cast<wtf_size_t>(mojom::blink::FeaturePolicyFeature::kMaxValue) +
8351 1);
8352 } else if (potentially_violated_features_[index]) {
8353 return;
8354 }
8355 potentially_violated_features_[index] = true;
8356 UMA_HISTOGRAM_ENUMERATION("Blink.UseCounter.FeaturePolicy.PotentialViolation",
8357 feature);
8358 }
ReportFeaturePolicyViolation(mojom::blink::FeaturePolicyFeature feature,mojom::blink::PolicyDisposition disposition,const String & message,const String & source_file) const8359 void Document::ReportFeaturePolicyViolation(
8360 mojom::blink::FeaturePolicyFeature feature,
8361 mojom::blink::PolicyDisposition disposition,
8362 const String& message,
8363 const String& source_file) const {
8364 if (!RuntimeEnabledFeatures::FeaturePolicyReportingEnabled(this))
8365 return;
8366 LocalFrame* frame = GetFrame();
8367 if (!frame)
8368 return;
8369
8370 // Construct the feature policy violation report.
8371 const String& feature_name = GetNameForFeature(feature);
8372 const String& disp_str =
8373 (disposition == mojom::blink::PolicyDisposition::kReport ? "report"
8374 : "enforce");
8375
8376 FeaturePolicyViolationReportBody* body =
8377 source_file.IsEmpty()
8378 ? MakeGarbageCollected<FeaturePolicyViolationReportBody>(
8379 feature_name, "Feature policy violation", disp_str)
8380 : MakeGarbageCollected<FeaturePolicyViolationReportBody>(
8381 feature_name, "Feature policy violation", disp_str,
8382 source_file);
8383
8384 Report* report = MakeGarbageCollected<Report>(
8385 ReportType::kFeaturePolicyViolation, Url().GetString(), body);
8386
8387 // Send the feature policy violation report to any ReportingObservers.
8388 auto* reporting_context = ReportingContext::From(domWindow());
8389 reporting_context->QueueReport(report);
8390
8391 // TODO(iclelland): Report something different in report-only mode
8392 if (disposition == mojom::blink::PolicyDisposition::kEnforce) {
8393 frame->Console().AddMessage(MakeGarbageCollected<ConsoleMessage>(
8394 mojom::ConsoleMessageSource::kViolation,
8395 mojom::ConsoleMessageLevel::kError,
8396 (message.IsEmpty() ? ("Feature policy violation: " + feature_name +
8397 " is not allowed in this document.")
8398 : message)));
8399 }
8400 }
8401
ReportDocumentPolicyViolation(mojom::blink::DocumentPolicyFeature feature,mojom::blink::PolicyDisposition disposition,const String & message,const String & source_file) const8402 void Document::ReportDocumentPolicyViolation(
8403 mojom::blink::DocumentPolicyFeature feature,
8404 mojom::blink::PolicyDisposition disposition,
8405 const String& message,
8406 const String& source_file) const {
8407 LocalFrame* frame = GetFrame();
8408 if (!frame)
8409 return;
8410
8411 // Construct the document policy violation report.
8412 const String& feature_name =
8413 GetDocumentPolicyFeatureInfoMap().at(feature).feature_name.c_str();
8414 bool is_report_only = disposition == mojom::blink::PolicyDisposition::kReport;
8415 const String& disp_str = is_report_only ? "report" : "enforce";
8416 const DocumentPolicy* relevant_document_policy =
8417 is_report_only ? GetSecurityContext().GetReportOnlyDocumentPolicy()
8418 : GetSecurityContext().GetDocumentPolicy();
8419
8420 DocumentPolicyViolationReportBody* body =
8421 source_file.IsEmpty()
8422 ? MakeGarbageCollected<DocumentPolicyViolationReportBody>(
8423 feature_name, "Document policy violation", disp_str)
8424 : MakeGarbageCollected<DocumentPolicyViolationReportBody>(
8425 feature_name, "Document policy violation", disp_str,
8426 source_file);
8427
8428 Report* report = MakeGarbageCollected<Report>(
8429 ReportType::kDocumentPolicyViolation, Url().GetString(), body);
8430
8431 // Send the document policy violation report to any ReportingObservers.
8432 auto* reporting_context = ReportingContext::From(domWindow());
8433 const base::Optional<std::string> endpoint =
8434 relevant_document_policy->GetFeatureEndpoint(feature);
8435
8436 reporting_context->QueueReport(
8437 report, endpoint ? Vector<String>{endpoint->c_str()} : Vector<String>{});
8438
8439 // TODO(iclelland): Report something different in report-only mode
8440 if (!is_report_only) {
8441 frame->Console().AddMessage(MakeGarbageCollected<ConsoleMessage>(
8442 mojom::blink::ConsoleMessageSource::kViolation,
8443 mojom::blink::ConsoleMessageLevel::kError,
8444 (message.IsEmpty() ? ("Document policy violation: " + feature_name +
8445 " is not allowed in this document.")
8446 : message)));
8447 }
8448 }
8449
IncrementNumberOfCanvases()8450 void Document::IncrementNumberOfCanvases() {
8451 num_canvases_++;
8452 }
8453
IncrementDisplayLockBlockingAllActivation()8454 void Document::IncrementDisplayLockBlockingAllActivation() {
8455 ++display_lock_blocking_all_activation_count_;
8456 }
8457
DecrementDisplayLockBlockingAllActivation()8458 void Document::DecrementDisplayLockBlockingAllActivation() {
8459 DCHECK_GT(display_lock_blocking_all_activation_count_, 0);
8460 --display_lock_blocking_all_activation_count_;
8461 }
8462
DisplayLockBlockingAllActivationCount() const8463 int Document::DisplayLockBlockingAllActivationCount() const {
8464 return display_lock_blocking_all_activation_count_;
8465 }
8466
AddLockedDisplayLock()8467 void Document::AddLockedDisplayLock() {
8468 ++locked_display_lock_count_;
8469 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("blink.debug.display_lock"),
8470 "LockedDisplayLockCount", TRACE_ID_LOCAL(this),
8471 locked_display_lock_count_);
8472 }
8473
RemoveLockedDisplayLock()8474 void Document::RemoveLockedDisplayLock() {
8475 DCHECK_GT(locked_display_lock_count_, 0);
8476 --locked_display_lock_count_;
8477 TRACE_COUNTER_ID1(TRACE_DISABLED_BY_DEFAULT("blink.debug.display_lock"),
8478 "LockedDisplayLockCount", TRACE_ID_LOCAL(this),
8479 locked_display_lock_count_);
8480 }
8481
LockedDisplayLockCount() const8482 int Document::LockedDisplayLockCount() const {
8483 return locked_display_lock_count_;
8484 }
8485
AddDisplayLockContext(DisplayLockContext * context)8486 void Document::AddDisplayLockContext(DisplayLockContext* context) {
8487 display_lock_contexts_.insert(context);
8488 }
8489
RemoveDisplayLockContext(DisplayLockContext * context)8490 void Document::RemoveDisplayLockContext(DisplayLockContext* context) {
8491 display_lock_contexts_.erase(context);
8492 }
8493
DisplayLockCount() const8494 int Document::DisplayLockCount() const {
8495 return display_lock_contexts_.size();
8496 }
8497
NotifySelectionRemovedFromDisplayLocks()8498 void Document::NotifySelectionRemovedFromDisplayLocks() {
8499 for (auto context : display_lock_contexts_)
8500 context->NotifySubtreeLostSelection();
8501 }
8502
8503 Document::ScopedForceActivatableDisplayLocks
GetScopedForceActivatableLocks()8504 Document::GetScopedForceActivatableLocks() {
8505 return ScopedForceActivatableDisplayLocks(this);
8506 }
8507
8508 Document::ScopedForceActivatableDisplayLocks::
ScopedForceActivatableDisplayLocks(Document * document)8509 ScopedForceActivatableDisplayLocks(Document* document)
8510 : document_(document) {
8511 if (++document_->activatable_display_locks_forced_ == 1) {
8512 for (auto context : document_->display_lock_contexts_)
8513 context->DidForceActivatableDisplayLocks();
8514 }
8515 }
8516
8517 Document::ScopedForceActivatableDisplayLocks::
ScopedForceActivatableDisplayLocks(ScopedForceActivatableDisplayLocks && other)8518 ScopedForceActivatableDisplayLocks(
8519 ScopedForceActivatableDisplayLocks&& other)
8520 : document_(other.document_) {
8521 other.document_ = nullptr;
8522 }
8523
8524 Document::ScopedForceActivatableDisplayLocks&
operator =(ScopedForceActivatableDisplayLocks && other)8525 Document::ScopedForceActivatableDisplayLocks::operator=(
8526 ScopedForceActivatableDisplayLocks&& other) {
8527 document_ = other.document_;
8528 other.document_ = nullptr;
8529 return *this;
8530 }
8531
8532 Document::ScopedForceActivatableDisplayLocks::
~ScopedForceActivatableDisplayLocks()8533 ~ScopedForceActivatableDisplayLocks() {
8534 if (!document_)
8535 return;
8536 DCHECK(document_->activatable_display_locks_forced_);
8537 --document_->activatable_display_locks_forced_;
8538 }
8539
RegisterDisplayLockActivationObservation(Element * element)8540 void Document::RegisterDisplayLockActivationObservation(Element* element) {
8541 EnsureDisplayLockActivationObserver().observe(element);
8542 }
8543
UnregisterDisplayLockActivationObservation(Element * element)8544 void Document::UnregisterDisplayLockActivationObservation(Element* element) {
8545 EnsureDisplayLockActivationObserver().unobserve(element);
8546 }
8547
EnsureDisplayLockActivationObserver()8548 IntersectionObserver& Document::EnsureDisplayLockActivationObserver() {
8549 if (!display_lock_activation_observer_) {
8550 // Use kPostTaskToDeliver method, since a commit can dirty layout, and we
8551 // want to avoid dirtying layout during post-lifecycle steps.
8552 // Note that we use 50% margin (on the viewport) so that we get the
8553 // observation before the element enters the viewport.
8554 display_lock_activation_observer_ = IntersectionObserver::Create(
8555 {Length::Percent(50.f)}, {std::numeric_limits<float>::min()}, this,
8556 WTF::BindRepeating(&Document::ProcessDisplayLockActivationObservation,
8557 WrapWeakPersistent(this)),
8558 IntersectionObserver::kDeliverDuringPostLifecycleSteps);
8559 }
8560 return *display_lock_activation_observer_;
8561 }
8562
ProcessDisplayLockActivationObservation(const HeapVector<Member<IntersectionObserverEntry>> & entries)8563 void Document::ProcessDisplayLockActivationObservation(
8564 const HeapVector<Member<IntersectionObserverEntry>>& entries) {
8565 DCHECK(View());
8566 for (auto& entry : entries) {
8567 auto* context = entry->target()->GetDisplayLockContext();
8568 DCHECK(context);
8569 if (entry->isIntersecting()) {
8570 View()->EnqueueStartOfLifecycleTask(
8571 WTF::Bind(&DisplayLockContext::NotifyIsIntersectingViewport,
8572 WrapWeakPersistent(context)));
8573 } else {
8574 View()->EnqueueStartOfLifecycleTask(
8575 WTF::Bind(&DisplayLockContext::NotifyIsNotIntersectingViewport,
8576 WrapWeakPersistent(context)));
8577 }
8578 }
8579 View()->ScheduleAnimation();
8580 }
8581
ExecuteJavaScriptUrls()8582 void Document::ExecuteJavaScriptUrls() {
8583 DCHECK(frame_);
8584 Vector<PendingJavascriptUrl> urls_to_execute;
8585 urls_to_execute.swap(pending_javascript_urls_);
8586
8587 for (auto& url_to_execute : urls_to_execute) {
8588 frame_->GetScriptController().ExecuteJavaScriptURL(
8589 url_to_execute.url, url_to_execute.disposition);
8590 if (!frame_)
8591 break;
8592 }
8593 CheckCompleted();
8594 }
8595
ProcessJavaScriptUrl(const KURL & url,network::mojom::CSPDisposition disposition)8596 void Document::ProcessJavaScriptUrl(
8597 const KURL& url,
8598 network::mojom::CSPDisposition disposition) {
8599 DCHECK(url.ProtocolIsJavaScript());
8600 if (frame_->Loader().StateMachine()->IsDisplayingInitialEmptyDocument())
8601 load_event_progress_ = kLoadEventNotRun;
8602 frame_->Loader().Progress().ProgressStarted();
8603 pending_javascript_urls_.push_back(PendingJavascriptUrl(url, disposition));
8604 if (!javascript_url_task_handle_.IsActive()) {
8605 javascript_url_task_handle_ = PostCancellableTask(
8606 *GetTaskRunner(TaskType::kNetworking), FROM_HERE,
8607 WTF::Bind(&Document::ExecuteJavaScriptUrls, WrapWeakPersistent(this)));
8608 }
8609 }
8610
CancelPendingJavaScriptUrls()8611 void Document::CancelPendingJavaScriptUrls() {
8612 if (javascript_url_task_handle_.IsActive())
8613 javascript_url_task_handle_.Cancel();
8614 pending_javascript_urls_.clear();
8615 }
8616
IsInWebAppScope() const8617 bool Document::IsInWebAppScope() const {
8618 if (!GetSettings())
8619 return false;
8620
8621 const String& web_app_scope = GetSettings()->GetWebAppScope();
8622 if (web_app_scope.IsNull() || web_app_scope.IsEmpty())
8623 return false;
8624
8625 DCHECK_EQ(KURL(web_app_scope).GetString(), web_app_scope);
8626 return Url().GetString().StartsWith(web_app_scope);
8627 }
8628
ClearIsolatedWorldCSPForTesting(int32_t world_id)8629 void Document::ClearIsolatedWorldCSPForTesting(int32_t world_id) {
8630 isolated_world_csp_map_->erase(world_id);
8631 }
8632
ChildrenCanHaveStyle() const8633 bool Document::ChildrenCanHaveStyle() const {
8634 if (LayoutObject* view = GetLayoutView())
8635 return view->CanHaveChildren();
8636 return false;
8637 }
8638
GetOrCreateComputedAccessibleNode(AXID ax_id,WebComputedAXTree * tree)8639 ComputedAccessibleNode* Document::GetOrCreateComputedAccessibleNode(
8640 AXID ax_id,
8641 WebComputedAXTree* tree) {
8642 if (computed_node_mapping_.find(ax_id) == computed_node_mapping_.end()) {
8643 auto* node =
8644 MakeGarbageCollected<ComputedAccessibleNode>(ax_id, tree, this);
8645 computed_node_mapping_.insert(ax_id, node);
8646 }
8647 return computed_node_mapping_.at(ax_id);
8648 }
8649
SetShowBeforeUnloadDialog(bool show_dialog)8650 void Document::SetShowBeforeUnloadDialog(bool show_dialog) {
8651 if (!mime_handler_view_before_unload_event_listener_) {
8652 if (!show_dialog)
8653 return;
8654
8655 mime_handler_view_before_unload_event_listener_ =
8656 MakeGarbageCollected<BeforeUnloadEventListener>(this);
8657 domWindow()->addEventListener(
8658 event_type_names::kBeforeunload,
8659 mime_handler_view_before_unload_event_listener_, false);
8660 }
8661 mime_handler_view_before_unload_event_listener_->SetShowBeforeUnloadDialog(
8662 show_dialog);
8663 }
8664
ColorSchemeChanged()8665 void Document::ColorSchemeChanged() {
8666 UpdateForcedColors();
8667 GetStyleEngine().ColorSchemeChanged();
8668 MediaQueryAffectingValueChanged(MediaValueChange::kOther);
8669 }
8670
VisionDeficiencyChanged()8671 void Document::VisionDeficiencyChanged() {
8672 GetStyleEngine().VisionDeficiencyChanged();
8673 }
8674
UpdateForcedColors()8675 void Document::UpdateForcedColors() {
8676 auto* web_theme_engine =
8677 RuntimeEnabledFeatures::ForcedColorsEnabled() && Platform::Current()
8678 ? Platform::Current()->ThemeEngine()
8679 : nullptr;
8680 ForcedColors forced_colors = web_theme_engine
8681 ? web_theme_engine->GetForcedColors()
8682 : ForcedColors::kNone;
8683 in_forced_colors_mode_ = forced_colors != ForcedColors::kNone;
8684 }
8685
InForcedColorsMode() const8686 bool Document::InForcedColorsMode() const {
8687 return in_forced_colors_mode_ && !Printing();
8688 }
8689
IsCrossSiteSubframe() const8690 bool Document::IsCrossSiteSubframe() const {
8691 // It'd be nice to avoid the url::Origin temporaries, but that would require
8692 // exposing the net internal helper.
8693 // TODO: If the helper gets exposed, we could do this without any new
8694 // allocations using StringUTF8Adaptor.
8695 return TopFrameOrigin() &&
8696 !net::registry_controlled_domains::SameDomainOrHost(
8697 TopFrameOrigin()->ToUrlOrigin(),
8698 GetSecurityOrigin()->ToUrlOrigin(),
8699 net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
8700 }
8701
CountUse(mojom::WebFeature feature) const8702 void Document::CountUse(mojom::WebFeature feature) const {
8703 if (use_counter_during_construction_)
8704 use_counter_during_construction_->CountUse(feature);
8705 else if (DocumentLoader* loader = Loader())
8706 loader->CountUse(feature);
8707 }
8708
CountUse(mojom::WebFeature feature)8709 void Document::CountUse(mojom::WebFeature feature) {
8710 if (use_counter_during_construction_)
8711 use_counter_during_construction_->CountUse(feature);
8712 else if (DocumentLoader* loader = Loader())
8713 loader->CountUse(feature);
8714 }
8715
CountDeprecation(mojom::WebFeature feature)8716 void Document::CountDeprecation(mojom::WebFeature feature) {
8717 // TODO(yoichio): We should remove these counters when v0 APIs are removed.
8718 // crbug.com/946875.
8719 if (const OriginTrialContext* origin_trial_context =
8720 GetOriginTrialContext()) {
8721 if (feature == WebFeature::kHTMLImports &&
8722 origin_trial_context->IsFeatureEnabled(
8723 OriginTrialFeature::kHTMLImports)) {
8724 CountUse(WebFeature::kHTMLImportsOnReverseOriginTrials);
8725 } else if (feature == WebFeature::kElementCreateShadowRoot &&
8726 origin_trial_context->IsFeatureEnabled(
8727 OriginTrialFeature::kShadowDOMV0)) {
8728 CountUse(WebFeature::kElementCreateShadowRootOnReverseOriginTrials);
8729 } else if (feature == WebFeature::kDocumentRegisterElement &&
8730 origin_trial_context->IsFeatureEnabled(
8731 OriginTrialFeature::kCustomElementsV0)) {
8732 CountUse(WebFeature::kDocumentRegisterElementOnReverseOriginTrials);
8733 }
8734 }
8735
8736 // Don't count usage of WebComponentsV0 for chrome:// URLs, but still report
8737 // the deprecation messages.
8738 if (Url().ProtocolIs("chrome") &&
8739 (feature == WebFeature::kHTMLImports ||
8740 feature == WebFeature::kElementCreateShadowRoot ||
8741 feature == WebFeature::kDocumentRegisterElement)) {
8742 Deprecation::DeprecationWarningOnly(Loader(), feature);
8743 } else {
8744 Deprecation::CountDeprecation(Loader(), feature);
8745 }
8746 }
8747
CountProperty(CSSPropertyID property) const8748 void Document::CountProperty(CSSPropertyID property) const {
8749 if (DocumentLoader* loader = Loader()) {
8750 loader->GetUseCounterHelper().Count(
8751 property, UseCounterHelper::CSSPropertyType::kDefault, GetFrame());
8752 }
8753 }
8754
CountAnimatedProperty(CSSPropertyID property) const8755 void Document::CountAnimatedProperty(CSSPropertyID property) const {
8756 if (DocumentLoader* loader = Loader()) {
8757 loader->GetUseCounterHelper().Count(
8758 property, UseCounterHelper::CSSPropertyType::kAnimation, GetFrame());
8759 }
8760 }
8761
CountUseOnlyInCrossOriginIframe(mojom::WebFeature feature) const8762 void Document::CountUseOnlyInCrossOriginIframe(
8763 mojom::WebFeature feature) const {
8764 LocalFrame* frame = GetFrame();
8765 if (frame && frame->IsCrossOriginToMainFrame())
8766 CountUse(feature);
8767 }
8768
IsUseCounted(mojom::WebFeature feature) const8769 bool Document::IsUseCounted(mojom::WebFeature feature) const {
8770 if (DocumentLoader* loader = Loader()) {
8771 return loader->GetUseCounterHelper().HasRecordedMeasurement(feature);
8772 }
8773 return false;
8774 }
8775
IsPropertyCounted(CSSPropertyID property) const8776 bool Document::IsPropertyCounted(CSSPropertyID property) const {
8777 if (DocumentLoader* loader = Loader()) {
8778 return loader->GetUseCounterHelper().IsCounted(
8779 property, UseCounterHelper::CSSPropertyType::kDefault);
8780 }
8781 return false;
8782 }
8783
IsAnimatedPropertyCounted(CSSPropertyID property) const8784 bool Document::IsAnimatedPropertyCounted(CSSPropertyID property) const {
8785 if (DocumentLoader* loader = Loader()) {
8786 return loader->GetUseCounterHelper().IsCounted(
8787 property, UseCounterHelper::CSSPropertyType::kAnimation);
8788 }
8789 return false;
8790 }
8791
ClearUseCounterForTesting(mojom::WebFeature feature)8792 void Document::ClearUseCounterForTesting(mojom::WebFeature feature) {
8793 if (DocumentLoader* loader = Loader())
8794 loader->GetUseCounterHelper().ClearMeasurementForTesting(feature);
8795 }
8796
FontPreloadingFinishedOrTimedOut()8797 void Document::FontPreloadingFinishedOrTimedOut() {
8798 DCHECK(!font_preload_manager_.HasPendingRenderBlockingFonts());
8799 if (IsA<HTMLDocument>(this) && body()) {
8800 // For HTML, we resume only when we're past the body tag, so that we should
8801 // have something to paint now.
8802 BeginLifecycleUpdatesIfRenderingReady();
8803 } else if (!IsA<HTMLDocument>(this) && documentElement()) {
8804 // For non-HTML there is no body so resume as soon as font preloading is
8805 // done or has timed out.
8806 BeginLifecycleUpdatesIfRenderingReady();
8807 }
8808 }
8809
8810 template class CORE_TEMPLATE_EXPORT Supplement<Document>;
8811
8812 } // namespace blink
8813 #ifndef NDEBUG
liveDocumentSet()8814 static WeakDocumentSet& liveDocumentSet() {
8815 DEFINE_STATIC_LOCAL(blink::Persistent<WeakDocumentSet>, set,
8816 (blink::MakeGarbageCollected<WeakDocumentSet>()));
8817 return *set;
8818 }
8819
showLiveDocumentInstances()8820 void showLiveDocumentInstances() {
8821 WeakDocumentSet& set = liveDocumentSet();
8822 fprintf(stderr, "There are %u documents currently alive:\n", set.size());
8823 for (blink::Document* document : set) {
8824 fprintf(stderr, "- Document %p URL: %s\n", document,
8825 document->Url().GetString().Utf8().c_str());
8826 }
8827 }
8828 #endif
8829