blob: 3a835b91d70ce7b41419ce2af2c1bcc7a4028266 [file] [log] [blame]
/*
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// How ownership works
// -------------------
//
// Big oh represents a refcounted relationship: owner O--- ownee
//
// WebView (for the toplevel frame only)
// O
// | WebFrame
// | O
// | |
// Page O------- LocalFrame (main_frame_) O-------O LocalFrameView
// ||
// ||
// FrameLoader
//
// FrameLoader and LocalFrame are formerly one object that was split apart
// because it got too big. They basically have the same lifetime, hence the
// double line.
//
// From the perspective of the embedder, WebFrame is simply an object that it
// allocates by calling WebFrame::create() and must be freed by calling close().
// Internally, WebFrame is actually refcounted and it holds a reference to its
// corresponding LocalFrame in blink.
//
// Oilpan: the middle objects + Page in the above diagram are Oilpan heap
// allocated, WebView and LocalFrameView are currently not. In terms of
// ownership and control, the relationships stays the same, but the references
// from the off-heap WebView to the on-heap Page is handled by a Persistent<>,
// not a scoped_refptr<>. Similarly, the mutual strong references between the
// on-heap LocalFrame and the off-heap LocalFrameView is through a RefPtr (from
// LocalFrame to LocalFrameView), and a Persistent refers to the LocalFrame in
// the other direction.
//
// From the embedder's point of view, the use of Oilpan brings no changes.
// close() must still be used to signal that the embedder is through with the
// WebFrame. Calling it will bring about the release and finalization of the
// frame object, and everything underneath.
//
// How frames are destroyed
// ------------------------
//
// The main frame is never destroyed and is re-used. The FrameLoader is re-used
// and a reference to the main frame is kept by the Page.
//
// When frame content is replaced, all subframes are destroyed. This happens
// in Frame::detachChildren for each subframe in a pre-order depth-first
// traversal. Note that child node order may not match DOM node order!
// detachChildren() (virtually) calls Frame::detach(), which again calls
// LocalFrameClient::detached(). This triggers WebFrame to clear its reference
// to LocalFrame. LocalFrameClient::detached() also notifies the embedder via
// WebLocalFrameClient that the frame is detached. Most embedders will invoke
// close() on the WebFrame at this point, triggering its deletion unless
// something else is still retaining a reference.
//
// The client is expected to be set whenever the WebLocalFrameImpl is attached
// to the DOM.
#include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
#include <algorithm>
#include <cmath>
#include <memory>
#include <numeric>
#include <utility>
#include "base/compiler_specific.h"
#include "base/notreached.h"
#include "base/numerics/safe_conversions.h"
#include "base/task/single_thread_task_runner.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "mojo/public/cpp/bindings/pending_associated_remote.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "services/network/public/cpp/web_sandbox_flags.h"
#include "services/network/public/mojom/web_sandbox_flags.mojom-blink.h"
#include "third_party/blink/public/common/context_menu_data/context_menu_params_builder.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/frame/fenced_frame_sandbox_flags.h"
#include "third_party/blink/public/common/page_state/page_state.h"
#include "third_party/blink/public/common/storage_key/storage_key.h"
#include "third_party/blink/public/mojom/devtools/inspector_issue.mojom-blink.h"
#include "third_party/blink/public/mojom/fenced_frame/fenced_frame.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/frame_replication_state.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/media_player_action.mojom-blink.h"
#include "third_party/blink/public/mojom/frame/tree_scope_type.mojom-blink.h"
#include "third_party/blink/public/mojom/lcp_critical_path_predictor/lcp_critical_path_predictor.mojom.h"
#include "third_party/blink/public/mojom/permissions_policy/permissions_policy.mojom-blink.h"
#include "third_party/blink/public/platform/interface_registry.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/public/platform/web_isolated_world_info.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_url_error.h"
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/public/web/blink.h"
#include "third_party/blink/public/web/web_associated_url_loader_options.h"
#include "third_party/blink/public/web/web_autofill_client.h"
#include "third_party/blink/public/web/web_console_message.h"
#include "third_party/blink/public/web/web_content_capture_client.h"
#include "third_party/blink/public/web/web_document.h"
#include "third_party/blink/public/web/web_form_element.h"
#include "third_party/blink/public/web/web_frame_owner_properties.h"
#include "third_party/blink/public/web/web_history_item.h"
#include "third_party/blink/public/web/web_input_element.h"
#include "third_party/blink/public/web/web_local_frame_client.h"
#include "third_party/blink/public/web/web_manifest_manager.h"
#include "third_party/blink/public/web/web_navigation_params.h"
#include "third_party/blink/public/web/web_node.h"
#include "third_party/blink/public/web/web_performance_metrics_for_nested_contexts.h"
#include "third_party/blink/public/web/web_performance_metrics_for_reporting.h"
#include "third_party/blink/public/web/web_plugin.h"
#include "third_party/blink/public/web/web_print_client.h"
#include "third_party/blink/public/web/web_print_page_description.h"
#include "third_party/blink/public/web/web_print_params.h"
#include "third_party/blink/public/web/web_print_preset_options.h"
#include "third_party/blink/public/web/web_range.h"
#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/public/web/web_serialized_script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/binding_security.h"
#include "third_party/blink/renderer/bindings/core/v8/isolated_world_csp.h"
#include "third_party/blink/renderer/bindings/core/v8/sanitize_script_errors.h"
#include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
#include "third_party/blink/renderer/bindings/core/v8/script_evaluation_result.h"
#include "third_party/blink/renderer/bindings/core/v8/script_value.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_gc_controller.h"
#include "third_party/blink/renderer/core/clipboard/clipboard_utilities.h"
#include "third_party/blink/renderer/core/clipboard/system_clipboard.h"
#include "third_party/blink/renderer/core/core_initializer.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/events/add_event_listener_options_resolved.h"
#include "third_party/blink/renderer/core/dom/icon_url.h"
#include "third_party/blink/renderer/core/dom/node.h"
#include "third_party/blink/renderer/core/dom/node_traversal.h"
#include "third_party/blink/renderer/core/dom/shadow_root.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/editor.h"
#include "third_party/blink/renderer/core/editing/ephemeral_range.h"
#include "third_party/blink/renderer/core/editing/finder/find_in_page_coordinates.h"
#include "third_party/blink/renderer/core/editing/finder/text_finder.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/ime/edit_context.h"
#include "third_party/blink/renderer/core/editing/ime/ime_text_span_vector_builder.h"
#include "third_party/blink/renderer/core/editing/ime/input_method_controller.h"
#include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
#include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
#include "third_party/blink/renderer/core/editing/plain_text_range.h"
#include "third_party/blink/renderer/core/editing/selection_template.h"
#include "third_party/blink/renderer/core/editing/serializers/serialization.h"
#include "third_party/blink/renderer/core/editing/set_selection_options.h"
#include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/editing/visible_position.h"
#include "third_party/blink/renderer/core/events/after_print_event.h"
#include "third_party/blink/renderer/core/events/before_print_event.h"
#include "third_party/blink/renderer/core/events/touch_event.h"
#include "third_party/blink/renderer/core/execution_context/window_agent.h"
#include "third_party/blink/renderer/core/exported/web_dev_tools_agent_impl.h"
#include "third_party/blink/renderer/core/exported/web_plugin_container_impl.h"
#include "third_party/blink/renderer/core/exported/web_view_impl.h"
#include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
#include "third_party/blink/renderer/core/frame/deprecation/deprecation.h"
#include "third_party/blink/renderer/core/frame/find_in_page.h"
#include "third_party/blink/renderer/core/frame/frame_console.h"
#include "third_party/blink/renderer/core/frame/intervention.h"
#include "third_party/blink/renderer/core/frame/local_dom_window.h"
#include "third_party/blink/renderer/core/frame/local_frame_client_impl.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/page_scale_constraints_set.h"
#include "third_party/blink/renderer/core/frame/pausable_script_executor.h"
#include "third_party/blink/renderer/core/frame/remote_frame.h"
#include "third_party/blink/renderer/core/frame/remote_frame_owner.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/frame/smart_clip.h"
#include "third_party/blink/renderer/core/frame/visual_viewport.h"
#include "third_party/blink/renderer/core/frame/web_frame_widget_impl.h"
#include "third_party/blink/renderer/core/frame/web_remote_frame_impl.h"
#include "third_party/blink/renderer/core/html/fenced_frame/html_fenced_frame_element.h"
#include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
#include "third_party/blink/renderer/core/html/forms/html_form_element.h"
#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
#include "third_party/blink/renderer/core/html/html_anchor_element.h"
#include "third_party/blink/renderer/core/html/html_collection.h"
#include "third_party/blink/renderer/core/html/html_frame_element_base.h"
#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
#include "third_party/blink/renderer/core/html/html_head_element.h"
#include "third_party/blink/renderer/core/html/html_iframe_element.h"
#include "third_party/blink/renderer/core/html/html_image_element.h"
#include "third_party/blink/renderer/core/html/html_link_element.h"
#include "third_party/blink/renderer/core/html/plugin_document.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/input/context_menu_allowed_scope.h"
#include "third_party/blink/renderer/core/input/event_handler.h"
#include "third_party/blink/renderer/core/inspector/console_message.h"
#include "third_party/blink/renderer/core/inspector/inspector_audits_issue.h"
#include "third_party/blink/renderer/core/inspector/inspector_issue.h"
#include "third_party/blink/renderer/core/inspector/inspector_issue_conversion.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/layout_embedded_content.h"
#include "third_party/blink/renderer/core/layout/layout_object.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/lcp_critical_path_predictor/lcp_critical_path_predictor.h"
#include "third_party/blink/renderer/core/loader/document_loader.h"
#include "third_party/blink/renderer/core/loader/frame_load_request.h"
#include "third_party/blink/renderer/core/loader/frame_loader.h"
#include "third_party/blink/renderer/core/loader/history_item.h"
#include "third_party/blink/renderer/core/loader/web_associated_url_loader_impl.h"
#include "third_party/blink/renderer/core/page/context_menu_controller.h"
#include "third_party/blink/renderer/core/page/focus_controller.h"
#include "third_party/blink/renderer/core/page/frame_tree.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/print_context.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/paint/timing/paint_timing.h"
#include "third_party/blink/renderer/core/script/classic_script.h"
#include "third_party/blink/renderer/core/scroll/scroll_types.h"
#include "third_party/blink/renderer/core/scroll/scrollbar_theme.h"
#include "third_party/blink/renderer/core/timing/dom_window_performance.h"
#include "third_party/blink/renderer/core/timing/window_performance.h"
#include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
#include "third_party/blink/renderer/platform/bindings/exception_state.h"
#include "third_party/blink/renderer/platform/bindings/script_forbidden_scope.h"
#include "third_party/blink/renderer/platform/bindings/source_location.h"
#include "third_party/blink/renderer/platform/fonts/font_cache.h"
#include "third_party/blink/renderer/platform/graphics/color.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
#include "third_party/blink/renderer/platform/graphics/paint/ignore_paint_timing_scope.h"
#include "third_party/blink/renderer/platform/graphics/paint/paint_record_builder.h"
#include "third_party/blink/renderer/platform/graphics/paint/scoped_paint_chunk_properties.h"
#include "third_party/blink/renderer/platform/graphics/skia/skia_utils.h"
#include "third_party/blink/renderer/platform/heap/garbage_collected.h"
#include "third_party/blink/renderer/platform/heap/thread_state.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
#include "third_party/blink/renderer/platform/loader/fetch/fetch_context.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_fetcher.h"
#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
#include "third_party/blink/renderer/platform/loader/fetch/url_loader/url_loader_factory.h"
#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h"
#include "third_party/blink/renderer/platform/scheduler/public/scheduling_policy.h"
#include "third_party/blink/renderer/platform/text/text_direction.h"
#include "third_party/blink/renderer/platform/weborigin/kurl.h"
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "third_party/blink/renderer/platform/weborigin/security_policy.h"
#include "third_party/blink/renderer/platform/wtf/casting.h"
#include "third_party/blink/renderer/platform/wtf/hash_map.h"
#include "ui/gfx/geometry/size_conversions.h"
#if BUILDFLAG(IS_WIN)
#include "third_party/blink/public/web/win/web_font_family_names.h"
#include "third_party/blink/renderer/core/layout/layout_font_accessor_win.h"
#endif
namespace blink {
namespace {
int g_frame_count = 0;
class DummyFrameOwner final : public GarbageCollected<DummyFrameOwner>,
public FrameOwner {
public:
void Trace(Visitor* visitor) const override { FrameOwner::Trace(visitor); }
// FrameOwner overrides:
Frame* ContentFrame() const override { return nullptr; }
void SetContentFrame(Frame&) override {}
void ClearContentFrame() override {}
const FramePolicy& GetFramePolicy() const override {
DEFINE_STATIC_LOCAL(FramePolicy, frame_policy, ());
return frame_policy;
}
void AddResourceTiming(mojom::blink::ResourceTimingInfoPtr) override {}
void DispatchLoad() override {}
void IntrinsicSizingInfoChanged() override {}
void SetNeedsOcclusionTracking(bool) override {}
AtomicString BrowsingContextContainerName() const override {
return AtomicString();
}
mojom::blink::ScrollbarMode ScrollbarMode() const override {
return mojom::blink::ScrollbarMode::kAuto;
}
int MarginWidth() const override { return -1; }
int MarginHeight() const override { return -1; }
bool AllowFullscreen() const override { return false; }
bool AllowPaymentRequest() const override { return false; }
bool IsDisplayNone() const override { return false; }
mojom::blink::ColorScheme GetColorScheme() const override {
return mojom::blink::ColorScheme::kLight;
}
bool ShouldLazyLoadChildren() const override { return false; }
private:
// Intentionally private to prevent redundant checks when the type is
// already DummyFrameOwner.
bool IsLocal() const override { return false; }
bool IsRemote() const override { return false; }
};
} // namespace
// Simple class to override some of PrintContext behavior. Some of the methods
// made virtual so that they can be overridden by ChromePluginPrintContext.
class ChromePrintContext : public PrintContext {
public:
explicit ChromePrintContext(LocalFrame* frame) : PrintContext(frame) {}
ChromePrintContext(const ChromePrintContext&) = delete;
ChromePrintContext& operator=(const ChromePrintContext&) = delete;
~ChromePrintContext() override = default;
virtual WebPrintPageDescription GetPageDescription(uint32_t page_index) {
return GetFrame()->GetDocument()->GetPageDescription(page_index);
}
void SpoolSinglePage(cc::PaintCanvas* canvas, wtf_size_t page_number) {
// The page rect gets scaled and translated, so specify the entire
// print content area here as the recording rect.
PaintRecordBuilder builder;
GraphicsContext& context = builder.Context();
context.SetPrintingMetafile(canvas->GetPrintingMetafile());
context.SetPrinting(true);
context.BeginRecording();
SpoolPage(context, page_number);
canvas->drawPicture(context.EndRecording());
}
void SpoolPagesWithBoundariesForTesting(cc::PaintCanvas* canvas,
const gfx::Size& spool_size_in_pixels,
const WebVector<uint32_t>* pages) {
gfx::Rect all_pages_rect(spool_size_in_pixels);
PaintRecordBuilder builder;
GraphicsContext& context = builder.Context();
context.SetPrintingMetafile(canvas->GetPrintingMetafile());
context.SetPrinting(true);
context.BeginRecording();
// Fill the whole background by white.
context.FillRect(all_pages_rect, Color::kWhite, AutoDarkMode::Disabled());
WebVector<uint32_t> all_pages;
if (!pages) {
all_pages.reserve(PageCount());
all_pages.resize(PageCount());
std::iota(all_pages.begin(), all_pages.end(), 0);
pages = &all_pages;
}
int current_height = 0;
for (uint32_t page_index : *pages) {
if (page_index >= PageCount()) {
break;
}
// Draw a line for a page boundary if this isn't the first page.
if (page_index != pages->front()) {
const gfx::Rect boundary_line_rect(0, current_height - 1,
spool_size_in_pixels.width(), 1);
context.FillRect(boundary_line_rect, Color(0, 0, 255),
AutoDarkMode::Disabled());
}
WebPrintPageDescription description =
GetFrame()->GetDocument()->GetPageDescription(page_index);
AffineTransform transform;
// The transform offset should be in integers, or everything will look
// blurry. The value is also rounded to the nearest integer (not ceil /
// floor), to better match what it would look like if the same offset were
// applied from within the document contents (e.g. margin / padding on a
// regular DIV). Some tests depend on this.
transform.Translate(std::round(description.margin_left),
current_height + std::round(description.margin_top));
if (description.orientation == PageOrientation::kUpright) {
current_height += description.size.height() + 1;
} else {
if (description.orientation == PageOrientation::kRotateRight) {
transform.Translate(description.size.height(), 0);
transform.Rotate(90);
} else {
DCHECK_EQ(description.orientation, PageOrientation::kRotateLeft);
transform.Translate(0, description.size.width());
transform.Rotate(-90);
}
current_height += description.size.width() + 1;
}
context.Save();
context.ConcatCTM(transform);
SpoolPage(context, page_index);
context.Restore();
}
canvas->drawPicture(context.EndRecording());
}
protected:
virtual void SpoolPage(GraphicsContext& context, wtf_size_t page_number) {
DispatchEventsForPrintingOnAllFrames();
if (!IsFrameValid()) {
return;
}
auto* frame_view = GetFrame()->View();
DCHECK(frame_view);
frame_view->UpdateLifecyclePhasesForPrinting();
if (!IsFrameValid() || page_number >= PageCount()) {
// TODO(crbug.com/452672): The number of pages may change after layout for
// pagination.
return;
}
gfx::Rect page_rect = PageRect(page_number);
AffineTransform transform;
const LayoutView* layout_view = frame_view->GetLayoutView();
// Layout may have used a larger viewport size in order to fit more
// unbreakable content in the inline direction. Now we need to scale it down
// to fit on the actual pages.
float inverse_scale = 1.f / layout_view->PageScaleFactor();
transform.Scale(inverse_scale, inverse_scale);
transform.Translate(static_cast<float>(-page_rect.x()),
static_cast<float>(-page_rect.y()));
context.Save();
context.ConcatCTM(transform);
context.ClipRect(gfx::RectToSkRect(page_rect));
auto property_tree_state =
layout_view->FirstFragment().LocalBorderBoxProperties();
PaintRecordBuilder builder(context);
frame_view->PaintOutsideOfLifecycle(
builder.Context(),
PaintFlag::kOmitCompositingInfo | PaintFlag::kAddUrlMetadata,
CullRect(page_rect));
OutputLinkedDestinations(builder.Context(), property_tree_state, page_rect);
context.DrawRecord(builder.EndRecording(property_tree_state.Unalias()));
context.Restore();
}
private:
void DispatchEventsForPrintingOnAllFrames() {
HeapVector<Member<Document>> documents;
for (Frame* current_frame = GetFrame(); current_frame;
current_frame = current_frame->Tree().TraverseNext(GetFrame())) {
if (auto* current_local_frame = DynamicTo<LocalFrame>(current_frame))
documents.push_back(current_local_frame->GetDocument());
}
for (auto& doc : documents)
doc->DispatchEventsForPrinting();
}
};
// Simple class to override some of PrintContext behavior. This is used when
// the frame hosts a plugin that supports custom printing. In this case, we
// want to delegate all printing related calls to the plugin.
class ChromePluginPrintContext final : public ChromePrintContext {
public:
ChromePluginPrintContext(LocalFrame* frame, WebPluginContainerImpl* plugin)
: ChromePrintContext(frame), plugin_(plugin) {}
~ChromePluginPrintContext() override = default;
void Trace(Visitor* visitor) const override {
visitor->Trace(plugin_);
ChromePrintContext::Trace(visitor);
}
const gfx::Rect& PageRect(wtf_size_t) const = delete;
WebPrintPageDescription GetPageDescription(uint32_t page_index) override {
// Plug-ins aren't really able to provide any page description apart from
// the "default" one. Yet, the printing code calls this function for
// plug-ins, which isn't ideal, but something we have to cope with for now.
return default_page_description_;
}
wtf_size_t PageCount() const override { return page_count_; }
void BeginPrintMode(const WebPrintParams& print_params) override {
default_page_description_ = print_params.default_page_description;
page_count_ = plugin_->PrintBegin(print_params);
}
void EndPrintMode() override {
plugin_->PrintEnd();
// TODO(junov): The following should not be necessary because
// the document's printing state does not need to be set when printing
// via a plugin. The problem is that WebLocalFrameImpl::DispatchBeforePrint
// modifies this state regardless of whether a plug-in is being used.
// This code should be refactored so that the print_context_ is in scope
// when beforeprint/afterprint events are dispatched So that plug-in
// behavior can be differentiated. Also, should beforeprint/afterprint
// events even be dispatched when using a plug-in?
if (IsFrameValid())
GetFrame()->GetDocument()->SetPrinting(Document::kNotPrinting);
}
protected:
void SpoolPage(GraphicsContext& context, wtf_size_t page_number) override {
PaintRecordBuilder builder(context);
plugin_->PrintPage(page_number, builder.Context());
context.DrawRecord(builder.EndRecording());
}
private:
// Set when printing.
Member<WebPluginContainerImpl> plugin_;
WebPrintPageDescription default_page_description_;
wtf_size_t page_count_ = 0;
};
class PaintPreviewContext : public PrintContext {
public:
explicit PaintPreviewContext(LocalFrame* frame) : PrintContext(frame) {
use_printing_layout_ = false;
}
PaintPreviewContext(const PaintPreviewContext&) = delete;
PaintPreviewContext& operator=(const PaintPreviewContext&) = delete;
~PaintPreviewContext() override = default;
bool Capture(cc::PaintCanvas* canvas,
const gfx::Rect& bounds,
bool include_linked_destinations) {
// This code is based on ChromePrintContext::SpoolSinglePage()/SpoolPage().
// It differs in that it:
// 1. Uses a different set of flags for painting and the graphics context.
// 2. Paints a single "page" of `bounds` size without applying print
// modifications to the page.
// 3. Does no scaling.
if (!GetFrame()->GetDocument() ||
!GetFrame()->GetDocument()->GetLayoutView())
return false;
GetFrame()->View()->UpdateLifecyclePhasesForPrinting();
if (!GetFrame()->GetDocument() ||
!GetFrame()->GetDocument()->GetLayoutView())
return false;
PaintRecordBuilder builder;
builder.Context().SetPaintPreviewTracker(canvas->GetPaintPreviewTracker());
LocalFrameView* frame_view = GetFrame()->View();
DCHECK(frame_view);
auto property_tree_state =
frame_view->GetLayoutView()->FirstFragment().ContentsProperties();
// This calls BeginRecording on |builder| with dimensions specified by the
// CullRect.
PaintFlags flags = PaintFlag::kOmitCompositingInfo;
if (include_linked_destinations)
flags |= PaintFlag::kAddUrlMetadata;
frame_view->PaintOutsideOfLifecycle(builder.Context(), flags,
CullRect(bounds));
if (include_linked_destinations) {
OutputLinkedDestinations(builder.Context(), property_tree_state, bounds);
}
canvas->drawPicture(builder.EndRecording(property_tree_state.Unalias()));
return true;
}
};
// Android WebView requires hit testing results on every touch event. This
// pushes the hit test result to the callback that is registered.
class TouchStartEventListener : public NativeEventListener {
public:
explicit TouchStartEventListener(
base::RepeatingCallback<void(const blink::WebHitTestResult&)> callback)
: callback_(std::move(callback)) {}
void Invoke(ExecutionContext*, Event* event) override {
auto* touch_event = DynamicTo<TouchEvent>(event);
if (!touch_event)
return;
const auto* native_event = touch_event->NativeEvent();
if (!native_event)
return;
DCHECK_EQ(WebInputEvent::Type::kTouchStart,
native_event->Event().GetType());
const auto& web_touch_event =
static_cast<const WebTouchEvent&>(native_event->Event());
if (web_touch_event.touches_length != 1u)
return;
LocalDOMWindow* dom_window = event->currentTarget()->ToLocalDOMWindow();
CHECK(dom_window);
WebGestureEvent tap_event(
WebInputEvent::Type::kGestureTap, WebInputEvent::kNoModifiers,
base::TimeTicks::Now(), WebGestureDevice::kTouchscreen);
// GestureTap is only ever from a touchscreen.
tap_event.SetPositionInWidget(
web_touch_event.touches[0].PositionInWidget());
tap_event.SetPositionInScreen(
web_touch_event.touches[0].PositionInScreen());
tap_event.SetFrameScale(web_touch_event.FrameScale());
tap_event.SetFrameTranslate(web_touch_event.FrameTranslate());
tap_event.data.tap.tap_count = 1;
tap_event.data.tap.height = tap_event.data.tap.width =
std::max(web_touch_event.touches[0].radius_x,
web_touch_event.touches[0].radius_y);
HitTestResult result =
dom_window->GetFrame()
->GetEventHandler()
.HitTestResultForGestureEvent(
tap_event, HitTestRequest::kReadOnly | HitTestRequest::kActive)
.GetHitTestResult();
result.SetToShadowHostIfInUAShadowRoot();
callback_.Run(result);
}
private:
base::RepeatingCallback<void(const blink::WebHitTestResult&)> callback_;
};
// WebFrame -------------------------------------------------------------------
static CreateWebFrameWidgetCallback* g_create_web_frame_widget = nullptr;
void InstallCreateWebFrameWidgetHook(
CreateWebFrameWidgetCallback* create_widget) {
// This DCHECK's aims to avoid unexpected replacement of the hook.
DCHECK(!g_create_web_frame_widget || !create_widget);
g_create_web_frame_widget = create_widget;
}
WebFrameWidget* WebLocalFrame::InitializeFrameWidget(
CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
mojo_frame_widget_host,
CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
mojo_frame_widget,
CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
mojo_widget_host,
CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
mojo_widget,
const viz::FrameSinkId& frame_sink_id,
bool is_for_nested_main_frame,
bool is_for_scalable_page,
bool hidden) {
CreateFrameWidgetInternal(
base::PassKey<WebLocalFrame>(), std::move(mojo_frame_widget_host),
std::move(mojo_frame_widget), std::move(mojo_widget_host),
std::move(mojo_widget), frame_sink_id, is_for_nested_main_frame,
is_for_scalable_page, hidden);
return FrameWidget();
}
int WebFrame::InstanceCount() {
return g_frame_count;
}
// static
WebFrame* WebFrame::FromFrameToken(const FrameToken& frame_token) {
auto* frame = Frame::ResolveFrame(frame_token);
return WebFrame::FromCoreFrame(frame);
}
// static
WebLocalFrame* WebLocalFrame::FromFrameToken(
const LocalFrameToken& frame_token) {
auto* frame = LocalFrame::FromFrameToken(frame_token);
return WebLocalFrameImpl::FromFrame(frame);
}
WebLocalFrame* WebLocalFrame::FrameForCurrentContext() {
v8::Isolate* isolate = v8::Isolate::TryGetCurrent();
if (UNLIKELY(!isolate)) {
return nullptr;
}
v8::Local<v8::Context> context = isolate->GetCurrentContext();
if (context.IsEmpty())
return nullptr;
return FrameForContext(context);
}
void WebLocalFrameImpl::NotifyUserActivation(
mojom::blink::UserActivationNotificationType notification_type) {
LocalFrame::NotifyUserActivation(GetFrame(), notification_type);
}
bool WebLocalFrameImpl::HasStickyUserActivation() {
return GetFrame()->HasStickyUserActivation();
}
bool WebLocalFrameImpl::HasTransientUserActivation() {
return LocalFrame::HasTransientUserActivation(GetFrame());
}
bool WebLocalFrameImpl::ConsumeTransientUserActivation(
UserActivationUpdateSource update_source) {
return LocalFrame::ConsumeTransientUserActivation(GetFrame(), update_source);
}
bool WebLocalFrameImpl::LastActivationWasRestricted() const {
return GetFrame()->LastActivationWasRestricted();
}
#if BUILDFLAG(IS_WIN)
WebFontFamilyNames WebLocalFrameImpl::GetWebFontFamilyNames() const {
FontFamilyNames font_family_names;
GetFontsUsedByFrame(*GetFrame(), font_family_names);
WebFontFamilyNames result;
for (const String& font_family_name : font_family_names.font_names) {
result.font_names.push_back(font_family_name);
}
return result;
}
#endif
WebLocalFrame* WebLocalFrame::FrameForContext(v8::Local<v8::Context> context) {
return WebLocalFrameImpl::FromFrame(ToLocalFrameIfNotDetached(context));
}
bool WebLocalFrameImpl::IsWebLocalFrame() const {
return true;
}
WebLocalFrame* WebLocalFrameImpl::ToWebLocalFrame() {
return this;
}
const WebLocalFrame* WebLocalFrameImpl::ToWebLocalFrame() const {
return this;
}
bool WebLocalFrameImpl::IsWebRemoteFrame() const {
return false;
}
WebRemoteFrame* WebLocalFrameImpl::ToWebRemoteFrame() {
NOTREACHED();
return nullptr;
}
const WebRemoteFrame* WebLocalFrameImpl::ToWebRemoteFrame() const {
NOTREACHED();
return nullptr;
}
void WebLocalFrameImpl::Close() {
WebLocalFrame::Close();
if (frame_widget_) {
frame_widget_->Close();
frame_widget_ = nullptr;
}
client_ = nullptr;
if (dev_tools_agent_)
dev_tools_agent_.Clear();
self_keep_alive_.Clear();
if (print_context_)
PrintEnd();
print_client_.reset();
#if DCHECK_IS_ON()
is_in_printing_ = false;
#endif
}
WebString WebLocalFrameImpl::AssignedName() const {
return GetFrame()->Tree().GetName();
}
ui::AXTreeID WebLocalFrameImpl::GetAXTreeID() const {
const std::optional<base::UnguessableToken>& embedding_token =
GetEmbeddingToken();
if (embedding_token && !embedding_token->is_empty())
return ui::AXTreeID::FromToken(embedding_token.value());
return ui::AXTreeIDUnknown();
}
void WebLocalFrameImpl::SetName(const WebString& name) {
GetFrame()->Tree().SetName(name, FrameTree::kReplicate);
}
WebContentSettingsClient* WebLocalFrameImpl::GetContentSettingsClient() const {
return content_settings_client_;
}
void WebLocalFrameImpl::SetContentSettingsClient(
WebContentSettingsClient* client) {
content_settings_client_ = client;
}
ScrollableArea* WebLocalFrameImpl::LayoutViewport() const {
if (LocalFrameView* view = GetFrameView())
return view->LayoutViewport();
return nullptr;
}
bool WebLocalFrameImpl::IsFocused() const {
if (!ViewImpl() || !ViewImpl()->GetPage())
return false;
return this ==
WebFrame::FromCoreFrame(
ViewImpl()->GetPage()->GetFocusController().FocusedFrame());
}
bool WebLocalFrameImpl::DispatchedPagehideAndStillHidden() const {
// Dispatching pagehide is the first step in unloading, so we must have
// already dispatched pagehide if unload had started.
if (GetFrame() && GetFrame()->GetDocument() &&
GetFrame()->GetDocument()->UnloadStarted()) {
return true;
}
if (!ViewImpl() || !ViewImpl()->GetPage())
return false;
// We might have dispatched pagehide without unloading the document.
return ViewImpl()->GetPage()->DispatchedPagehideAndStillHidden();
}
bool WebLocalFrameImpl::UsePrintingLayout() const {
return print_context_ ? print_context_->use_printing_layout() : false;
}
void WebLocalFrameImpl::CopyToFindPboard() {
#if BUILDFLAG(IS_MAC)
if (HasSelection())
GetFrame()->GetSystemClipboard()->CopyToFindPboard(SelectionAsText());
#endif
}
void WebLocalFrameImpl::CenterSelection() {
if (HasSelection()) {
GetFrame()->Selection().RevealSelection(ScrollAlignment::CenterAlways());
}
}
gfx::PointF WebLocalFrameImpl::GetScrollOffset() const {
if (ScrollableArea* scrollable_area = LayoutViewport())
return scrollable_area->ScrollPosition();
return gfx::PointF();
}
void WebLocalFrameImpl::SetScrollOffset(const gfx::PointF& offset) {
if (ScrollableArea* scrollable_area = LayoutViewport()) {
scrollable_area->SetScrollOffset(
scrollable_area->ScrollPositionToOffset(offset),
mojom::blink::ScrollType::kProgrammatic);
}
}
gfx::Size WebLocalFrameImpl::DocumentSize() const {
if (!GetFrameView() || !GetFrameView()->GetLayoutView())
return gfx::Size();
return ToPixelSnappedRect(GetFrameView()->GetLayoutView()->DocumentRect())
.size();
}
bool WebLocalFrameImpl::HasVisibleContent() const {
auto* layout_object = GetFrame()->OwnerLayoutObject();
if (layout_object &&
layout_object->StyleRef().Visibility() != EVisibility::kVisible) {
return false;
}
if (LocalFrameView* view = GetFrameView())
return view->Width() > 0 && view->Height() > 0;
return false;
}
gfx::Rect WebLocalFrameImpl::VisibleContentRect() const {
if (LocalFrameView* view = GetFrameView())
return view->LayoutViewport()->VisibleContentRect();
return gfx::Rect();
}
WebView* WebLocalFrameImpl::View() const {
return ViewImpl();
}
WebDocument WebLocalFrameImpl::GetDocument() const {
if (!GetFrame() || !GetFrame()->GetDocument())
return WebDocument();
return WebDocument(GetFrame()->GetDocument());
}
WebPerformanceMetricsForReporting
WebLocalFrameImpl::PerformanceMetricsForReporting() const {
if (!GetFrame())
return WebPerformanceMetricsForReporting();
return WebPerformanceMetricsForReporting(
DOMWindowPerformance::performance(*(GetFrame()->DomWindow())));
}
WebPerformanceMetricsForNestedContexts
WebLocalFrameImpl::PerformanceMetricsForNestedContexts() const {
if (!GetFrame())
return WebPerformanceMetricsForNestedContexts();
return WebPerformanceMetricsForNestedContexts(
DOMWindowPerformance::performance(*(GetFrame()->DomWindow())));
}
bool WebLocalFrameImpl::IsAdFrame() const {
DCHECK(GetFrame());
return GetFrame()->IsAdFrame();
}
bool WebLocalFrameImpl::IsAdScriptInStack() const {
DCHECK(GetFrame());
return GetFrame()->IsAdScriptInStack();
}
void WebLocalFrameImpl::SetAdEvidence(
const blink::FrameAdEvidence& ad_evidence) {
DCHECK(GetFrame());
GetFrame()->SetAdEvidence(ad_evidence);
}
const std::optional<blink::FrameAdEvidence>& WebLocalFrameImpl::AdEvidence() {
DCHECK(GetFrame());
return GetFrame()->AdEvidence();
}
bool WebLocalFrameImpl::IsFrameCreatedByAdScript() {
DCHECK(GetFrame());
return GetFrame()->IsFrameCreatedByAdScript();
}
void WebLocalFrameImpl::ExecuteScript(const WebScriptSource& source) {
DCHECK(GetFrame());
ClassicScript::CreateUnspecifiedScript(source)->RunScript(
GetFrame()->DomWindow());
}
void WebLocalFrameImpl::ExecuteScriptInIsolatedWorld(
int32_t world_id,
const WebScriptSource& source_in,
BackForwardCacheAware back_forward_cache_aware) {
DCHECK(GetFrame());
CHECK_GT(world_id, DOMWrapperWorld::kMainWorldId);
CHECK_LT(world_id, DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit);
if (back_forward_cache_aware == BackForwardCacheAware::kPossiblyDisallow) {
GetFrame()->GetFrameScheduler()->RegisterStickyFeature(
SchedulingPolicy::Feature::kInjectedJavascript,
{SchedulingPolicy::DisableBackForwardCache()});
}
// Note: An error event in an isolated world will never be dispatched to
// a foreign world.
v8::HandleScope handle_scope(ToIsolate(GetFrame()));
ClassicScript::CreateUnspecifiedScript(source_in,
SanitizeScriptErrors::kDoNotSanitize)
->RunScriptInIsolatedWorldAndReturnValue(GetFrame()->DomWindow(),
world_id);
}
v8::Local<v8::Value>
WebLocalFrameImpl::ExecuteScriptInIsolatedWorldAndReturnValue(
int32_t world_id,
const WebScriptSource& source_in,
BackForwardCacheAware back_forward_cache_aware) {
DCHECK(GetFrame());
CHECK_GT(world_id, DOMWrapperWorld::kMainWorldId);
CHECK_LT(world_id, DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit);
if (back_forward_cache_aware == BackForwardCacheAware::kPossiblyDisallow) {
GetFrame()->GetFrameScheduler()->RegisterStickyFeature(
SchedulingPolicy::Feature::kInjectedJavascript,
{SchedulingPolicy::DisableBackForwardCache()});
}
// Note: An error event in an isolated world will never be dispatched to
// a foreign world.
return ClassicScript::CreateUnspecifiedScript(
source_in, SanitizeScriptErrors::kDoNotSanitize)
->RunScriptInIsolatedWorldAndReturnValue(GetFrame()->DomWindow(),
world_id)
.GetSuccessValueOrEmpty();
}
void WebLocalFrameImpl::ClearIsolatedWorldCSPForTesting(int32_t world_id) {
if (!GetFrame())
return;
if (world_id <= DOMWrapperWorld::kMainWorldId ||
world_id >= DOMWrapperWorld::kDOMWrapperWorldEmbedderWorldIdLimit) {
return;
}
GetFrame()->DomWindow()->ClearIsolatedWorldCSPForTesting(world_id);
}
void WebLocalFrameImpl::Alert(const WebString& message) {
DCHECK(GetFrame());
ScriptState* script_state = ToScriptStateForMainWorld(GetFrame());
DCHECK(script_state);
GetFrame()->DomWindow()->alert(script_state, message);
}
bool WebLocalFrameImpl::Confirm(const WebString& message) {
DCHECK(GetFrame());
ScriptState* script_state = ToScriptStateForMainWorld(GetFrame());
DCHECK(script_state);
return GetFrame()->DomWindow()->confirm(script_state, message);
}
WebString WebLocalFrameImpl::Prompt(const WebString& message,
const WebString& default_value) {
DCHECK(GetFrame());
ScriptState* script_state = ToScriptStateForMainWorld(GetFrame());
DCHECK(script_state);
return GetFrame()->DomWindow()->prompt(script_state, message, default_value);
}
void WebLocalFrameImpl::GenerateInterventionReport(const WebString& message_id,
const WebString& message) {
DCHECK(GetFrame());
Intervention::GenerateReport(GetFrame(), message_id, message);
}
void WebLocalFrameImpl::CollectGarbageForTesting() {
if (!GetFrame())
return;
if (!GetFrame()->GetSettings()->GetScriptEnabled())
return;
ThreadState::Current()->CollectAllGarbageForTesting();
}
v8::MaybeLocal<v8::Value> WebLocalFrameImpl::ExecuteMethodAndReturnValue(
v8::Local<v8::Function> function,
v8::Local<v8::Value> receiver,
int argc,
v8::Local<v8::Value> argv[]) {
DCHECK(GetFrame());
return GetFrame()
->DomWindow()
->GetScriptController()
.EvaluateMethodInMainWorld(function, receiver, argc, argv);
}
v8::Local<v8::Value> WebLocalFrameImpl::ExecuteScriptAndReturnValue(
const WebScriptSource& source) {
DCHECK(GetFrame());
return ClassicScript::CreateUnspecifiedScript(source)
->RunScriptAndReturnValue(GetFrame()->DomWindow())
.GetSuccessValueOrEmpty();
}
void WebLocalFrameImpl::RequestExecuteV8Function(
v8::Local<v8::Context> context,
v8::Local<v8::Function> function,
v8::Local<v8::Value> receiver,
int argc,
v8::Local<v8::Value> argv[],
WebScriptExecutionCallback callback) {
DCHECK(GetFrame());
const auto want_result_option =
callback ? mojom::blink::WantResultOption::kWantResult
: mojom::blink::WantResultOption::kNoResult;
PausableScriptExecutor::CreateAndRun(context, function, receiver, argc, argv,
want_result_option, std::move(callback));
}
void WebLocalFrameImpl::RequestExecuteScript(
int32_t world_id,
base::span<const WebScriptSource> sources,
mojom::blink::UserActivationOption user_gesture,
mojom::blink::EvaluationTiming evaluation_timing,
mojom::blink::LoadEventBlockingOption blocking_option,
WebScriptExecutionCallback callback,
BackForwardCacheAware back_forward_cache_aware,
mojom::blink::WantResultOption want_result_option,
mojom::blink::PromiseResultOption promise_behavior) {
DCHECK(GetFrame());
GetFrame()->RequestExecuteScript(
world_id, sources, user_gesture, evaluation_timing, blocking_option,
std::move(callback), back_forward_cache_aware, want_result_option,
promise_behavior);
}
v8::MaybeLocal<v8::Value> WebLocalFrameImpl::CallFunctionEvenIfScriptDisabled(
v8::Local<v8::Function> function,
v8::Local<v8::Value> receiver,
int argc,
v8::Local<v8::Value> argv[]) {
DCHECK(GetFrame());
return V8ScriptRunner::CallFunction(
function, GetFrame()->DomWindow(), receiver, argc,
static_cast<v8::Local<v8::Value>*>(argv), ToIsolate(GetFrame()));
}
v8::Local<v8::Context> WebLocalFrameImpl::MainWorldScriptContext() const {
ScriptState* script_state = ToScriptStateForMainWorld(GetFrame());
DCHECK(script_state);
return script_state->GetContext();
}
int32_t WebLocalFrameImpl::GetScriptContextWorldId(
v8::Local<v8::Context> script_context) const {
DCHECK_EQ(this, FrameForContext(script_context));
return DOMWrapperWorld::World(script_context).GetWorldId();
}
v8::Local<v8::Context> WebLocalFrameImpl::GetScriptContextFromWorldId(
v8::Isolate* isolate,
int world_id) const {
DOMWrapperWorld* world =
DOMWrapperWorld::EnsureIsolatedWorld(isolate, world_id);
return ToScriptState(GetFrame(), *world)->GetContext();
}
v8::Local<v8::Object> WebLocalFrameImpl::GlobalProxy(
v8::Isolate* isolate) const {
return MainWorldScriptContext()->Global();
}
bool WebFrame::ScriptCanAccess(v8::Isolate* isolate, WebFrame* target) {
return BindingSecurity::ShouldAllowAccessTo(
CurrentDOMWindow(isolate), ToCoreFrame(*target)->DomWindow());
}
void WebLocalFrameImpl::StartReload(WebFrameLoadType frame_load_type) {
// TODO(clamy): Remove this function once RenderFrame calls StartNavigation
// for all requests.
DCHECK(GetFrame());
DCHECK(IsReloadLoadType(frame_load_type));
TRACE_EVENT1("navigation", "WebLocalFrameImpl::StartReload", "load_type",
static_cast<int>(frame_load_type));
ResourceRequest request =
GetFrame()->Loader().ResourceRequestForReload(frame_load_type);
if (request.IsNull())
return;
if (GetTextFinder())
GetTextFinder()->ClearActiveFindMatch();
FrameLoadRequest frame_load_request(GetFrame()->DomWindow(), request);
GetFrame()->Loader().StartNavigation(frame_load_request, frame_load_type);
}
void WebLocalFrameImpl::ReloadImage(const WebNode& web_node) {
Node* node = web_node; // Use implicit WebNode->Node* cast.
HitTestResult hit_test_result;
hit_test_result.SetInnerNode(node);
hit_test_result.SetToShadowHostIfInUAShadowRoot();
node = hit_test_result.InnerNodeOrImageMapImage();
if (auto* image_element = DynamicTo<HTMLImageElement>(*node))
image_element->ForceReload();
}
void WebLocalFrameImpl::ClearActiveFindMatchForTesting() {
DCHECK(GetFrame());
if (GetTextFinder())
GetTextFinder()->ClearActiveFindMatch();
}
WebDocumentLoader* WebLocalFrameImpl::GetDocumentLoader() const {
DCHECK(GetFrame());
return GetFrame()->Loader().GetDocumentLoader();
}
void WebLocalFrameImpl::EnableViewSourceMode(bool enable) {
if (GetFrame())
GetFrame()->SetInViewSourceMode(enable);
}
bool WebLocalFrameImpl::IsViewSourceModeEnabled() const {
if (!GetFrame())
return false;
return GetFrame()->InViewSourceMode();
}
void WebLocalFrameImpl::SetReferrerForRequest(WebURLRequest& request,
const WebURL& referrer_url) {
String referrer = referrer_url.IsEmpty()
? GetFrame()->DomWindow()->OutgoingReferrer()
: String(referrer_url.GetString());
ResourceRequest& resource_request = request.ToMutableResourceRequest();
resource_request.SetReferrerPolicy(
GetFrame()->DomWindow()->GetReferrerPolicy());
resource_request.SetReferrerString(referrer);
}
std::unique_ptr<WebAssociatedURLLoader>
WebLocalFrameImpl::CreateAssociatedURLLoader(
const WebAssociatedURLLoaderOptions& options) {
return std::make_unique<WebAssociatedURLLoaderImpl>(GetFrame()->DomWindow(),
options);
}
void WebLocalFrameImpl::DeprecatedStopLoading() {
if (!GetFrame())
return;
// FIXME: Figure out what we should really do here. It seems like a bug
// that FrameLoader::stopLoading doesn't call stopAllLoaders.
GetFrame()->Loader().StopAllLoaders(/*abort_client=*/true);
}
void WebLocalFrameImpl::ReplaceSelection(const WebString& text) {
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
GetFrame()->GetEditor().ReplaceSelection(text);
}
void WebLocalFrameImpl::UnmarkText() {
GetFrame()->GetInputMethodController().CancelComposition();
}
bool WebLocalFrameImpl::HasMarkedText() const {
return GetFrame()->GetInputMethodController().HasComposition();
}
WebRange WebLocalFrameImpl::MarkedRange() const {
return GetFrame()->GetInputMethodController().CompositionEphemeralRange();
}
bool WebLocalFrameImpl::FirstRectForCharacterRange(
uint32_t location,
uint32_t length,
gfx::Rect& rect_in_viewport) const {
if ((location + length < location) && (location + length))
length = 0;
if (EditContext* edit_context =
GetFrame()->GetInputMethodController().GetActiveEditContext()) {
return edit_context->FirstRectForCharacterRange(location, length,
rect_in_viewport);
}
Element* editable =
GetFrame()->Selection().RootEditableElementOrDocumentElement();
if (!editable)
return false;
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. see http://crbug.com/590369 for more details.
editable->GetDocument().UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
const EphemeralRange range =
PlainTextRange(location, location + length).CreateRange(*editable);
if (range.IsNull())
return false;
rect_in_viewport =
GetFrame()->View()->FrameToViewport(FirstRectForRange(range));
return true;
}
bool WebLocalFrameImpl::ExecuteCommand(const WebString& name) {
DCHECK(GetFrame());
if (name.length() <= 2)
return false;
// Since we don't have NSControl, we will convert the format of command
// string and call the function on Editor directly.
String command = name;
// Make sure the first letter is upper case.
command.replace(0, 1, command.Substring(0, 1).UpperASCII());
// Remove the trailing ':' if existing.
if (command[command.length() - 1] == UChar(':'))
command = command.Substring(0, command.length() - 1);
Node* plugin_lookup_context_node = nullptr;
if (WebPluginContainerImpl::SupportsCommand(name))
plugin_lookup_context_node = ContextMenuNodeInner();
WebPluginContainerImpl* plugin_container =
GetFrame()->GetWebPluginContainer(plugin_lookup_context_node);
if (plugin_container && plugin_container->ExecuteEditCommand(name))
return true;
return GetFrame()->GetEditor().ExecuteCommand(command);
}
bool WebLocalFrameImpl::ExecuteCommand(const WebString& name,
const WebString& value) {
DCHECK(GetFrame());
WebPluginContainerImpl* plugin_container =
GetFrame()->GetWebPluginContainer();
if (plugin_container && plugin_container->ExecuteEditCommand(name, value))
return true;
return GetFrame()->GetEditor().ExecuteCommand(name, value);
}
bool WebLocalFrameImpl::IsCommandEnabled(const WebString& name) const {
DCHECK(GetFrame());
return GetFrame()->GetEditor().IsCommandEnabled(name);
}
bool WebLocalFrameImpl::SelectionTextDirection(
base::i18n::TextDirection& start,
base::i18n::TextDirection& end) const {
FrameSelection& selection = frame_->Selection();
if (!selection.IsAvailable()) {
// plugins/mouse-capture-inside-shadow.html reaches here
return false;
}
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
frame_->GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kSelection);
if (selection.ComputeVisibleSelectionInDOMTree()
.ToNormalizedEphemeralRange()
.IsNull())
return false;
start = ToBaseTextDirection(PrimaryDirectionOf(
*selection.ComputeVisibleSelectionInDOMTree().Start().AnchorNode()));
end = ToBaseTextDirection(PrimaryDirectionOf(
*selection.ComputeVisibleSelectionInDOMTree().End().AnchorNode()));
return true;
}
bool WebLocalFrameImpl::IsSelectionAnchorFirst() const {
FrameSelection& selection = frame_->Selection();
if (!selection.IsAvailable()) {
// plugins/mouse-capture-inside-shadow.html reaches here
return false;
}
return selection.GetSelectionInDOMTree().IsAnchorFirst();
}
void WebLocalFrameImpl::SetTextDirectionForTesting(
base::i18n::TextDirection direction) {
frame_->SetTextDirection(direction);
}
void WebLocalFrameImpl::ReplaceMisspelledRange(const WebString& text) {
// If this caret selection has two or more markers, this function replace the
// range covered by the first marker with the specified word as Microsoft Word
// does.
if (GetFrame()->GetWebPluginContainer())
return;
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. see http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSpellCheck);
GetFrame()->GetSpellChecker().ReplaceMisspelledRange(text);
}
void WebLocalFrameImpl::RemoveSpellingMarkers() {
GetFrame()->GetSpellChecker().RemoveSpellingMarkers();
}
void WebLocalFrameImpl::RemoveSpellingMarkersUnderWords(
const WebVector<WebString>& words) {
Vector<String> converted_words;
converted_words.Append(words.data(),
base::checked_cast<wtf_size_t>(words.size()));
GetFrame()->RemoveSpellingMarkersUnderWords(converted_words);
}
bool WebLocalFrameImpl::HasSelection() const {
DCHECK(GetFrame());
WebPluginContainerImpl* plugin_container =
GetFrame()->GetWebPluginContainer();
if (plugin_container)
return plugin_container->Plugin()->HasSelection();
// TODO(editing-dev): The use of UpdateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
return GetFrame()->Selection().ComputeVisibleSelectionInDOMTree().IsRange();
}
WebRange WebLocalFrameImpl::SelectionRange() const {
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
return GetFrame()
->Selection()
.ComputeVisibleSelectionInDOMTree()
.ToNormalizedEphemeralRange();
}
WebString WebLocalFrameImpl::SelectionAsText() const {
DCHECK(GetFrame());
WebPluginContainerImpl* plugin_container =
GetFrame()->GetWebPluginContainer();
if (plugin_container)
return plugin_container->Plugin()->SelectionAsText();
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
String text = GetFrame()->Selection().SelectedText(
TextIteratorBehavior::EmitsObjectReplacementCharacterBehavior());
#if BUILDFLAG(IS_WIN)
ReplaceNewlinesWithWindowsStyleNewlines(text);
#endif
ReplaceNBSPWithSpace(text);
return text;
}
WebString WebLocalFrameImpl::SelectionAsMarkup() const {
WebPluginContainerImpl* plugin_container =
GetFrame()->GetWebPluginContainer();
if (plugin_container)
return plugin_container->Plugin()->SelectionAsMarkup();
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
// Selection normalization and markup generation require clean layout.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
return GetFrame()->Selection().SelectedHTMLForClipboard();
}
void WebLocalFrameImpl::TextSelectionChanged(const WebString& selection_text,
uint32_t offset,
const gfx::Range& range) {
GetFrame()->TextSelectionChanged(selection_text, offset, range);
}
bool WebLocalFrameImpl::SelectAroundCaret(
mojom::blink::SelectionGranularity granularity,
bool should_show_handle,
bool should_show_context_menu) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::selectAroundCaret");
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. see http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
// TODO(1275801): Add mapping between the enums once it becomes possible to
// do so.
blink::TextGranularity text_granularity;
switch (granularity) {
case mojom::blink::SelectionGranularity::kWord:
text_granularity = blink::TextGranularity::kWord;
break;
case mojom::blink::SelectionGranularity::kSentence:
text_granularity = blink::TextGranularity::kSentence;
break;
}
return GetFrame()->Selection().SelectAroundCaret(
text_granularity,
should_show_handle ? HandleVisibility::kVisible
: HandleVisibility::kNotVisible,
should_show_context_menu ? ContextMenuVisibility ::kVisible
: ContextMenuVisibility ::kNotVisible);
}
EphemeralRange WebLocalFrameImpl::GetWordSelectionRangeAroundCaret() const {
TRACE_EVENT0("blink", "WebLocalFrameImpl::getWordSelectionRangeAroundCaret");
return GetFrame()->Selection().GetWordSelectionRangeAroundCaret();
}
void WebLocalFrameImpl::SelectRange(const gfx::Point& base_in_viewport,
const gfx::Point& extent_in_viewport) {
MoveRangeSelection(base_in_viewport, extent_in_viewport);
}
void WebLocalFrameImpl::SelectRange(
const WebRange& web_range,
HandleVisibilityBehavior handle_visibility_behavior,
blink::mojom::SelectionMenuBehavior selection_menu_behavior,
SelectionSetFocusBehavior selection_set_focus_behavior) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::selectRange");
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. see http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
const EphemeralRange& range = web_range.CreateEphemeralRange(GetFrame());
if (range.IsNull())
return;
FrameSelection& selection = GetFrame()->Selection();
const bool show_handles =
handle_visibility_behavior == kShowSelectionHandle ||
(handle_visibility_behavior == kPreserveHandleVisibility &&
selection.IsHandleVisible());
using blink::mojom::SelectionMenuBehavior;
const bool selection_not_set_focus =
selection_set_focus_behavior == kSelectionDoNotSetFocus;
selection.SetSelection(
SelectionInDOMTree::Builder()
.SetBaseAndExtent(range)
.SetAffinity(TextAffinity::kDefault)
.Build(),
SetSelectionOptions::Builder()
.SetShouldShowHandle(show_handles)
.SetShouldShrinkNextTap(selection_menu_behavior ==
SelectionMenuBehavior::kShow)
.SetDoNotSetFocus(selection_not_set_focus)
.Build());
if (selection_menu_behavior == SelectionMenuBehavior::kShow) {
ContextMenuAllowedScope scope;
GetFrame()->GetEventHandler().ShowNonLocatedContextMenu(
nullptr, kMenuSourceAdjustSelection);
}
}
WebString WebLocalFrameImpl::RangeAsText(const WebRange& web_range) {
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. see http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kEditing);
DocumentLifecycle::DisallowTransitionScope disallow_transition(
GetFrame()->GetDocument()->Lifecycle());
return PlainText(
web_range.CreateEphemeralRange(GetFrame()),
TextIteratorBehavior::EmitsObjectReplacementCharacterBehavior());
}
void WebLocalFrameImpl::MoveRangeSelectionExtent(const gfx::Point& point) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::moveRangeSelectionExtent");
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
GetFrame()->Selection().MoveRangeSelectionExtent(
GetFrame()->View()->ViewportToFrame(point));
}
void WebLocalFrameImpl::MoveRangeSelection(
const gfx::Point& base_in_viewport,
const gfx::Point& extent_in_viewport,
WebFrame::TextGranularity granularity) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::moveRangeSelection");
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
blink::TextGranularity blink_granularity = blink::TextGranularity::kCharacter;
if (granularity == WebFrame::kWordGranularity)
blink_granularity = blink::TextGranularity::kWord;
GetFrame()->Selection().MoveRangeSelection(
GetFrame()->View()->ViewportToFrame(base_in_viewport),
GetFrame()->View()->ViewportToFrame(extent_in_viewport),
blink_granularity);
}
void WebLocalFrameImpl::MoveCaretSelection(
const gfx::Point& point_in_viewport) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::moveCaretSelection");
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. see http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
const gfx::Point point_in_contents =
GetFrame()->View()->ViewportToFrame(point_in_viewport);
GetFrame()->Selection().MoveCaretSelection(point_in_contents);
}
bool WebLocalFrameImpl::SetEditableSelectionOffsets(int start, int end) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::setEditableSelectionOffsets");
if (EditContext* edit_context =
GetFrame()->GetInputMethodController().GetActiveEditContext()) {
edit_context->SetSelection(start, end);
return true;
}
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
return GetFrame()->GetInputMethodController().SetEditableSelectionOffsets(
PlainTextRange(start, end));
}
bool WebLocalFrameImpl::AddImeTextSpansToExistingText(
const WebVector<ui::ImeTextSpan>& ime_text_spans,
unsigned text_start,
unsigned text_end) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::AddImeTextSpansToExistingText");
if (!GetFrame()->GetEditor().CanEdit())
return false;
InputMethodController& input_method_controller =
GetFrame()->GetInputMethodController();
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kEditing);
input_method_controller.AddImeTextSpansToExistingText(
ImeTextSpanVectorBuilder::Build(ime_text_spans), text_start, text_end);
return true;
}
bool WebLocalFrameImpl::ClearImeTextSpansByType(ui::ImeTextSpan::Type type,
unsigned text_start,
unsigned text_end) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::ClearImeTextSpansByType");
if (!GetFrame()->GetEditor().CanEdit())
return false;
InputMethodController& input_method_controller =
GetFrame()->GetInputMethodController();
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kEditing);
input_method_controller.ClearImeTextSpansByType(ConvertUiTypeToType(type),
text_start, text_end);
return true;
}
bool WebLocalFrameImpl::SetCompositionFromExistingText(
int composition_start,
int composition_end,
const WebVector<ui::ImeTextSpan>& ime_text_spans) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::setCompositionFromExistingText");
if (EditContext* edit_context =
GetFrame()->GetInputMethodController().GetActiveEditContext()) {
return edit_context->SetCompositionFromExistingText(
composition_start, composition_end, ime_text_spans);
}
if (!GetFrame()->GetEditor().CanEdit())
return false;
InputMethodController& input_method_controller =
GetFrame()->GetInputMethodController();
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kEditing);
input_method_controller.SetCompositionFromExistingText(
ImeTextSpanVectorBuilder::Build(ime_text_spans), composition_start,
composition_end);
return true;
}
void WebLocalFrameImpl::ExtendSelectionAndDelete(int before, int after) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::extendSelectionAndDelete");
if (EditContext* edit_context =
GetFrame()->GetInputMethodController().GetActiveEditContext()) {
edit_context->ExtendSelectionAndDelete(before, after);
return;
}
if (WebPlugin* plugin = FocusedPluginIfInputMethodSupported()) {
plugin->ExtendSelectionAndDelete(before, after);
return;
}
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
GetFrame()->GetInputMethodController().ExtendSelectionAndDelete(before,
after);
}
void WebLocalFrameImpl::ExtendSelectionAndReplace(
int before,
int after,
const WebString& replacement_text) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::extendSelectionAndReplace");
// EditContext and WebPlugin do not support atomic replacement.
if (EditContext* edit_context =
GetFrame()->GetInputMethodController().GetActiveEditContext()) {
edit_context->ExtendSelectionAndDelete(before, after);
edit_context->CommitText(replacement_text, std::vector<ui::ImeTextSpan>(),
blink::WebRange(), 0);
return;
}
if (WebPlugin* plugin = FocusedPluginIfInputMethodSupported()) {
plugin->ExtendSelectionAndDelete(before, after);
plugin->CommitText(replacement_text, std::vector<ui::ImeTextSpan>(),
blink::WebRange(), 0);
return;
}
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kSelection);
GetFrame()->GetInputMethodController().ExtendSelectionAndReplace(
before, after, replacement_text);
}
void WebLocalFrameImpl::DeleteSurroundingText(int before, int after) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::deleteSurroundingText");
if (EditContext* edit_context =
GetFrame()->GetInputMethodController().GetActiveEditContext()) {
edit_context->DeleteSurroundingText(before, after);
return;
}
if (WebPlugin* plugin = FocusedPluginIfInputMethodSupported()) {
plugin->DeleteSurroundingText(before, after);
return;
}
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kEditing);
GetFrame()->GetInputMethodController().DeleteSurroundingText(before, after);
}
void WebLocalFrameImpl::DeleteSurroundingTextInCodePoints(int before,
int after) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::deleteSurroundingTextInCodePoints");
if (WebPlugin* plugin = FocusedPluginIfInputMethodSupported()) {
plugin->DeleteSurroundingTextInCodePoints(before, after);
return;
}
// TODO(editing-dev): The use of UpdateStyleAndLayout
// needs to be audited. See http://crbug.com/590369 for more details.
GetFrame()->GetDocument()->UpdateStyleAndLayout(
DocumentUpdateReason::kEditing);
GetFrame()->GetInputMethodController().DeleteSurroundingTextInCodePoints(
before, after);
}
WebPlugin* WebLocalFrameImpl::FocusedPluginIfInputMethodSupported() {
WebPluginContainerImpl* container = GetFrame()->GetWebPluginContainer();
if (container && container->SupportsInputMethod())
return container->Plugin();
return nullptr;
}
void WebLocalFrameImpl::DispatchBeforePrintEvent(
base::WeakPtr<WebPrintClient> print_client) {
#if DCHECK_IS_ON()
DCHECK(!is_in_printing_) << "DispatchAfterPrintEvent() should have been "
"called after the previous "
"DispatchBeforePrintEvent() call.";
is_in_printing_ = true;
#endif
print_client_ = print_client;
// Disable BackForwardCache when printing API is used for now. When the page
// navigates with BackForwardCache, we currently do not close the printing
// popup properly.
GetFrame()->GetFrameScheduler()->RegisterStickyFeature(
blink::SchedulingPolicy::Feature::kPrinting,
{blink::SchedulingPolicy::DisableBackForwardCache()});
GetFrame()->GetDocument()->SetPrinting(Document::kBeforePrinting);
DispatchPrintEventRecursively(event_type_names::kBeforeprint);
// In case the printing or print preview aborts for any reason, it is
// important not to leave the document in the kBeforePrinting state.
// See: crbug.com/1309595
if (GetFrame())
GetFrame()->GetDocument()->SetPrinting(Document::kNotPrinting);
}
void WebLocalFrameImpl::DispatchAfterPrintEvent() {
#if DCHECK_IS_ON()
DCHECK(is_in_printing_) << "DispatchBeforePrintEvent() should be called "
"before DispatchAfterPrintEvent().";
is_in_printing_ = false;
#endif
print_client_.reset();
if (View())
DispatchPrintEventRecursively(event_type_names::kAfterprint);
}
void WebLocalFrameImpl::DispatchPrintEventRecursively(
const AtomicString& event_type) {
DCHECK(event_type == event_type_names::kBeforeprint ||
event_type == event_type_names::kAfterprint);
HeapVector<Member<Frame>> frames;
for (Frame* frame = frame_; frame; frame = frame->Tree().TraverseNext(frame_))
frames.push_back(frame);
for (auto& frame : frames) {
if (frame->IsRemoteFrame()) {
// TODO(tkent): Support remote frames. crbug.com/455764.
continue;
}
if (!frame->Tree().IsDescendantOf(frame_))
continue;
Event* event =
event_type == event_type_names::kBeforeprint
? static_cast<Event*>(MakeGarbageCollected<BeforePrintEvent>())
: static_cast<Event*>(MakeGarbageCollected<AfterPrintEvent>());
To<LocalFrame>(frame.Get())->DomWindow()->DispatchEvent(*event);
}
}
WebPluginContainerImpl* WebLocalFrameImpl::GetPluginToPrintHelper(
const WebNode& constrain_to_node) {
if (constrain_to_node.IsNull()) {
// If this is a plugin document, check if the plugin supports its own
// printing. If it does, we will delegate all printing to that.
return GetFrame()->GetWebPluginContainer();
}
// We only support printing plugin nodes for now.
return To<WebPluginContainerImpl>(constrain_to_node.PluginContainer());
}
WebPlugin* WebLocalFrameImpl::GetPluginToPrint(
const WebNode& constrain_to_node) {
WebPluginContainerImpl* plugin_container =
GetPluginToPrintHelper(constrain_to_node);
return plugin_container ? plugin_container->Plugin() : nullptr;
}
bool WebLocalFrameImpl::WillPrintSoon() {
return GetFrame()->GetDocument()->WillPrintSoon();
}
uint32_t WebLocalFrameImpl::PrintBegin(const WebPrintParams& print_params,
const WebNode& constrain_to_node) {
WebPluginContainerImpl* plugin_container =
GetPluginToPrintHelper(constrain_to_node);
if (plugin_container && plugin_container->SupportsPaginatedPrint()) {
print_context_ = MakeGarbageCollected<ChromePluginPrintContext>(
GetFrame(), plugin_container);
} else {
print_context_ = MakeGarbageCollected<ChromePrintContext>(GetFrame());
}
print_context_->BeginPrintMode(print_params);
return print_context_->PageCount();
}
void WebLocalFrameImpl::PrintPage(uint32_t page, cc::PaintCanvas* canvas) {
DCHECK(print_context_);
DCHECK(GetFrame());
DCHECK(GetFrame()->GetDocument());
print_context_->SpoolSinglePage(canvas, page);
}
void WebLocalFrameImpl::PrintEnd() {
DCHECK(print_context_);
print_context_->EndPrintMode();
print_context_.Clear();
}
bool WebLocalFrameImpl::GetPrintPresetOptionsForPlugin(
const WebNode& node,
WebPrintPresetOptions* preset_options) {
WebPluginContainerImpl* plugin_container = GetPluginToPrintHelper(node);
if (!plugin_container || !plugin_container->SupportsPaginatedPrint())
return false;
return plugin_container->GetPrintPresetOptionsFromDocument(preset_options);
}
bool WebLocalFrameImpl::CapturePaintPreview(const gfx::Rect& bounds,
cc::PaintCanvas* canvas,
bool include_linked_destinations,
bool skip_accelerated_content) {
bool success = false;
{
// Ignore paint timing while capturing a paint preview as it can change LCP
// see crbug.com/1323073.
IgnorePaintTimingScope scope;
IgnorePaintTimingScope::IncrementIgnoreDepth();
Document::PaintPreviewScope paint_preview(
*GetFrame()->GetDocument(),
skip_accelerated_content
? Document::kPaintingPreviewSkipAcceleratedContent
: Document::kPaintingPreview);
GetFrame()->StartPaintPreview();
PaintPreviewContext* paint_preview_context =
MakeGarbageCollected<PaintPreviewContext>(GetFrame());
success = paint_preview_context->Capture(canvas, bounds,
include_linked_destinations);
GetFrame()->EndPaintPreview();
}
return success;
}
WebPrintPageDescription WebLocalFrameImpl::GetPageDescription(
uint32_t page_index) {
return print_context_->GetPageDescription(page_index);
}
gfx::Size WebLocalFrameImpl::SpoolSizeInPixelsForTesting(
const WebVector<uint32_t>& pages) {
int spool_width = 0;
int spool_height = 0;
for (uint32_t page_index : pages) {
// Make room for the 1px tall page separator.
if (page_index != pages.front())
spool_height++;
WebPrintPageDescription description =
GetFrame()->GetDocument()->GetPageDescription(page_index);
gfx::Size page_size = gfx::ToCeiledSize(description.size);
if (description.orientation == PageOrientation::kUpright) {
spool_width = std::max(spool_width, page_size.width());
spool_height += page_size.height();
} else {
spool_height += page_size.width();
spool_width = std::max(spool_width, page_size.height());
}
}
return gfx::Size(spool_width, spool_height);
}
gfx::Size WebLocalFrameImpl::SpoolSizeInPixelsForTesting(uint32_t page_count) {
WebVector<uint32_t> pages(page_count);
std::iota(pages.begin(), pages.end(), 0);
return SpoolSizeInPixelsForTesting(pages);
}
void WebLocalFrameImpl::PrintPagesForTesting(
cc::PaintCanvas* canvas,
const gfx::Size& spool_size_in_pixels,
const WebVector<uint32_t>* pages) {
DCHECK(print_context_);
print_context_->SpoolPagesWithBoundariesForTesting(
canvas, spool_size_in_pixels, pages);
}
gfx::Rect WebLocalFrameImpl::GetSelectionBoundsRectForTesting() const {
DCHECK(GetFrame()); // Not valid after the Frame is detached.
GetFrame()->View()->UpdateLifecycleToLayoutClean(
DocumentUpdateReason::kSelection);
return HasSelection() ? ToPixelSnappedRect(
GetFrame()->Selection().AbsoluteUnclippedBounds())
: gfx::Rect();
}
gfx::Point WebLocalFrameImpl::GetPositionInViewportForTesting() const {
DCHECK(GetFrame()); // Not valid after the Frame is detached.
LocalFrameView* view = GetFrameView();
return view->ConvertToRootFrame(gfx::Point());
}
// WebLocalFrameImpl public --------------------------------------------------
WebLocalFrame* WebLocalFrame::CreateMainFrame(
WebView* web_view,
WebLocalFrameClient* client,
InterfaceRegistry* interface_registry,
const LocalFrameToken& frame_token,
const DocumentToken& document_token,
std::unique_ptr<WebPolicyContainer> policy_container,
WebFrame* opener,
const WebString& name,
network::mojom::blink::WebSandboxFlags sandbox_flags,
const WebURL& creator_base_url) {
return WebLocalFrameImpl::CreateMainFrame(
web_view, client, interface_registry, frame_token, opener, name,
sandbox_flags, document_token, std::move(policy_container),
creator_base_url);
}
WebLocalFrame* WebLocalFrame::CreateProvisional(
WebLocalFrameClient* client,
InterfaceRegistry* interface_registry,
const LocalFrameToken& frame_token,
WebFrame* previous_frame,
const FramePolicy& frame_policy,
const WebString& name,
WebView* web_view) {
return WebLocalFrameImpl::CreateProvisional(client, interface_registry,
frame_token, previous_frame,
frame_policy, name, web_view);
}
WebLocalFrameImpl* WebLocalFrameImpl::CreateMainFrame(
WebView* web_view,
WebLocalFrameClient* client,
InterfaceRegistry* interface_registry,
const LocalFrameToken& frame_token,
WebFrame* opener,
const WebString& name,
network::mojom::blink::WebSandboxFlags sandbox_flags,
const DocumentToken& document_token,
std::unique_ptr<WebPolicyContainer> policy_container,
const WebURL& creator_base_url) {
auto* frame = MakeGarbageCollected<WebLocalFrameImpl>(
base::PassKey<WebLocalFrameImpl>(),
mojom::blink::TreeScopeType::kDocument, client, interface_registry,
frame_token);
Page& page = *To<WebViewImpl>(web_view)->GetPage();
DCHECK(!page.MainFrame());
// TODO(https://crbug.com/1355751): From the browser process, plumb the
// correct StorageKey for window in main frame. This is not an issue here,
// because the FrameLoader is able to recover a correct StorageKey from the
// origin of the document only.
StorageKey storage_key;
frame->InitializeCoreFrame(
page, nullptr, nullptr, nullptr, FrameInsertType::kInsertInConstructor,
name, opener ? &ToCoreFrame(*opener)->window_agent_factory() : nullptr,
opener, document_token, std::move(policy_container), storage_key,
creator_base_url, sandbox_flags);
return frame;
}
WebLocalFrameImpl* WebLocalFrameImpl::CreateProvisional(
WebLocalFrameClient* client,
blink::InterfaceRegistry* interface_registry,
const LocalFrameToken& frame_token,
WebFrame* previous_web_frame,
const FramePolicy& frame_policy,
const WebString& name,
WebView* web_view) {
DCHECK(client);
Frame* previous_frame = ToCoreFrame(*previous_web_frame);
DCHECK(name.IsEmpty() || name.Equals(previous_frame->Tree().GetName()));
auto* web_frame = MakeGarbageCollected<WebLocalFrameImpl>(
base::PassKey<WebLocalFrameImpl>(),
previous_web_frame->GetTreeScopeType(), client, interface_registry,
frame_token);
network::mojom::blink::WebSandboxFlags sandbox_flags =
network::mojom::blink::WebSandboxFlags::kNone;
PermissionsPolicyFeatureState feature_state;
if (!previous_frame->Owner() || previous_frame->IsFencedFrameRoot()) {
// Provisional main frames need to force sandbox flags. This is necessary
// to inherit sandbox flags when a sandboxed frame does a window.open()
// which triggers a cross-process navigation.
// Fenced frames also need to force special initial sandbox flags that are
// passed via frame_policy.
sandbox_flags = frame_policy.sandbox_flags;
}
// Note: this *always* temporarily sets a frame owner, even for main frames!
// When a core Frame is created with no owner, it attempts to set itself as
// the main frame of the Page. However, this is a provisional frame, and may
// disappear, so Page::m_mainFrame can't be updated just yet.
// Note 2: Becuase the dummy owner is still the owner when the initial empty
// document is created, the initial empty document will not inherit the
// correct sandbox flags. However, since the provisional frame is inivisible
// to the rest of the page, the initial document is also invisible and
// unscriptable. Once the provisional frame gets properly attached and is
// observable, it will have the real FrameOwner, and any subsequent real
// documents will correctly inherit sandbox flags from the owner.
//
// Note: this intentionally initializes the initial document of the
// provisional frame with a random DocumentToken rather than plumbing it
// through from //content. The fact that provisional frames have an initial
// document is a weird implementation detail and this is an attempt to
// minimize its visibility/usefulness.
Page* page_for_provisional_frame = To<WebViewImpl>(web_view)->GetPage();
web_frame->InitializeCoreFrame(
*page_for_provisional_frame, MakeGarbageCollected<DummyFrameOwner>(),
previous_web_frame->Parent(), nullptr, FrameInsertType::kInsertLater,
name, &ToCoreFrame(*previous_web_frame)->window_agent_factory(),
previous_web_frame->Opener(), DocumentToken(),
/*policy_container=*/nullptr, StorageKey(),
/*creator_base_url=*/KURL(), sandbox_flags);
LocalFrame* new_frame = web_frame->GetFrame();
if (previous_frame->GetPage() != page_for_provisional_frame) {
// The previous frame's Page is different from the new frame's page. This
// can only be true when creating a provisional LocalFrame that will do a
// local main frame swap when its navigation commits. To be able to do the
// swap, the provisional frame must have a pointer to the previous Page's
// local main frame, and also be set as the provisional frame of the
// placeholder RemoteFrame of the new Page.
// Note that the new provisional frame is not set as the provisional frame
// of the previous Page's main frame, to avoid triggering the deletion of
// the new Page's provisional frame if/when the previous Page's main frame
// gets deleted. With that, the new Page's provisional main frame's deletion
// can only be triggered by deleting the new Page (when its WebView gets
// deleted).
CHECK(!previous_web_frame->Parent());
CHECK(previous_web_frame->IsWebLocalFrame());
CHECK(page_for_provisional_frame->MainFrame()->IsRemoteFrame());
CHECK(!DynamicTo<RemoteFrame>(page_for_provisional_frame->MainFrame())
->IsRemoteFrameHostRemoteBound());
page_for_provisional_frame->SetPreviousMainFrameForLocalSwap(
DynamicTo<LocalFrame>(ToCoreFrame(*previous_web_frame)));
page_for_provisional_frame->MainFrame()->SetProvisionalFrame(new_frame);
} else {
// This is a normal provisional frame, which will either replace a
// RemoteFrame or a non-main-frame LocalFrame. This makes it possible to
// find the provisional owner frame (the previous frame) when swapping in
// the new frame. This also ensures that detaching the previous frame also
// disposes of the provisional frame.
previous_frame->SetProvisionalFrame(new_frame);
}
new_frame->SetOwner(previous_frame->Owner());
if (auto* remote_frame_owner =
DynamicTo<RemoteFrameOwner>(new_frame->Owner())) {
remote_frame_owner->SetFramePolicy(frame_policy);
}
return web_frame;
}
WebLocalFrameImpl* WebLocalFrameImpl::CreateLocalChild(
mojom::blink::TreeScopeType scope,
WebLocalFrameClient* client,
blink::InterfaceRegistry* interface_registry,
const LocalFrameToken& frame_token) {
auto* frame = MakeGarbageCollected<WebLocalFrameImpl>(
base::PassKey<WebLocalFrameImpl>(), scope, client, interface_registry,
frame_token);
return frame;
}
WebLocalFrameImpl::WebLocalFrameImpl(
base::PassKey<WebLocalFrameImpl>,
mojom::blink::TreeScopeType scope,
WebLocalFrameClient* client,
blink::InterfaceRegistry* interface_registry,
const LocalFrameToken& frame_token)
: WebNavigationControl(scope, frame_token),
client_(client),
local_frame_client_(MakeGarbageCollected<LocalFrameClientImpl>(this)),
autofill_client_(nullptr),
find_in_page_(
MakeGarbageCollected<FindInPage>(*this, interface_registry)),
interface_registry_(interface_registry),
input_method_controller_(*this),
spell_check_panel_host_client_(nullptr),
not_restored_reasons_(
mojom::BackForwardCacheNotRestoredReasonsPtr(nullptr)) {
CHECK(client_);
g_frame_count++;
client_->BindToFrame(this);
}
WebLocalFrameImpl::WebLocalFrameImpl(base::PassKey<WebRemoteFrameImpl>,
mojom::blink::TreeScopeType scope,
WebLocalFrameClient* client,
InterfaceRegistry* interface_registry,
const LocalFrameToken& frame_token)
: WebLocalFrameImpl(base::PassKey<WebLocalFrameImpl>(),
scope,
client,
interface_registry,
frame_token) {}
WebLocalFrameImpl::~WebLocalFrameImpl() {
// The widget for the frame, if any, must have already been closed.
DCHECK(!frame_widget_);
g_frame_count--;
}
void WebLocalFrameImpl::Trace(Visitor* visitor) const {
visitor->Trace(local_frame_client_);
visitor->Trace(find_in_page_);
visitor->Trace(frame_);
visitor->Trace(dev_tools_agent_);
visitor->Trace(frame_widget_);
visitor->Trace(print_context_);
visitor->Trace(input_method_controller_);
visitor->Trace(current_history_item_);
}
void WebLocalFrameImpl::SetCoreFrame(LocalFrame* frame) {
frame_ = frame;
}
void WebLocalFrameImpl::InitializeCoreFrame(
Page& page,
FrameOwner* owner,
WebFrame* parent,
WebFrame* previous_sibling,
FrameInsertType insert_type,
const AtomicString& name,
WindowAgentFactory* window_agent_factory,
WebFrame* opener,
const DocumentToken& document_token,
std::unique_ptr<blink::WebPolicyContainer> policy_container,
const StorageKey& storage_key,
const KURL& creator_base_url,
network::mojom::blink::WebSandboxFlags sandbox_flags) {
InitializeCoreFrameInternal(
page, owner, parent, previous_sibling, insert_type, name,
window_agent_factory, opener, document_token,
PolicyContainer::CreateFromWebPolicyContainer(
std::move(policy_container)),
storage_key, ukm::kInvalidSourceId, creator_base_url, sandbox_flags);
}
void WebLocalFrameImpl::InitializeCoreFrameInternal(
Page& page,
FrameOwner* owner,
WebFrame* parent,
WebFrame* previous_sibling,
FrameInsertType insert_type,
const AtomicString& name,
WindowAgentFactory* window_agent_factory,
WebFrame* opener,
const DocumentToken& document_token,
std::unique_ptr<PolicyContainer> policy_container,
const StorageKey& storage_key,
ukm::SourceId document_ukm_source_id,
const KURL& creator_base_url,
network::mojom::blink::WebSandboxFlags sandbox_flags) {
Frame* parent_frame = parent ? ToCoreFrame(*parent) : nullptr;
Frame* previous_sibling_frame =
previous_sibling ? ToCoreFrame(*previous_sibling) : nullptr;
SetCoreFrame(MakeGarbageCollected<LocalFrame>(
local_frame_client_.Get(), page, owner, parent_frame,
previous_sibling_frame, insert_type, GetLocalFrameToken(),
window_agent_factory, interface_registry_));
frame_->Tree().SetName(name);
// See sandbox inheritance: content/browser/renderer_host/sandbox_flags.md
//
// New documents are either:
// 1. The initial empty document:
// a. In a new iframe.
// b. In a new fencedframe.
// c. In a new popup.
// 2. A document replacing the previous, one via a navigation.
//
// 1.b. will get the special sandbox flags. See:
// https://docs.google.com/document/d/1RO4NkQk_XaEE7vuysM9LJilZYsoOhydfh93sOvrPQxU/edit
// For 1.c., this is used to define sandbox flags for
// the initial empty document in a new popup.
if (frame_->IsMainFrame()) {
DCHECK(!frame_->IsInFencedFrameTree() ||
((sandbox_flags & blink::kFencedFrameForcedSandboxFlags) ==
blink::kFencedFrameForcedSandboxFlags))
<< "An MPArch fencedframe must be configured with its forced sandbox "
<< "flags:" << sandbox_flags;
frame_->SetOpenerSandboxFlags(sandbox_flags);
}
Frame* opener_frame = opener ? ToCoreFrame(*opener) : nullptr;
// We must call init() after frame_ is assigned because it is referenced
// during init().
frame_->Init(opener_frame, document_token, std::move(policy_container),
storage_key, document_ukm_source_id, creator_base_url);
if (!owner) {
// This trace event is needed to detect the main frame of the
// renderer in telemetry metrics. See crbug.com/692112#c11.
TRACE_EVENT_INSTANT1("loading", "markAsMainFrame", TRACE_EVENT_SCOPE_THREAD,
"frame", GetFrameIdForTracing(frame_));
}
}
LocalFrame* WebLocalFrameImpl::CreateChildFrame(
const AtomicString& name,
HTMLFrameOwnerElement* owner_element) {
DCHECK(client_);
TRACE_EVENT0("blink", "WebLocalFrameImpl::createChildframe");
mojom::blink::TreeScopeType scope =
GetFrame()->GetDocument() == owner_element->GetTreeScope()
? mojom::blink::TreeScopeType::kDocument
: mojom::blink::TreeScopeType::kShadow;
WebFrameOwnerProperties owner_properties(
owner_element->BrowsingContextContainerName(),
owner_element->ScrollbarMode(), owner_element->MarginWidth(),
owner_element->MarginHeight(), owner_element->AllowFullscreen(),
owner_element->AllowPaymentRequest(), owner_element->IsDisplayNone(),
owner_element->GetColorScheme());
mojo::PendingAssociatedRemote<mojom::blink::PolicyContainerHost>
policy_container_remote;
mojo::PendingAssociatedReceiver<mojom::blink::PolicyContainerHost>
policy_container_receiver =
policy_container_remote.InitWithNewEndpointAndPassReceiver();
FramePolicy frame_policy = owner_element->GetFramePolicy();
// The initial empty document's policy container is inherited from its parent.
mojom::blink::PolicyContainerPoliciesPtr policy_container_data =
GetFrame()->DomWindow()->GetPolicyContainer()->GetPolicies().Clone();
// The frame sandbox flags and the initial empty document's sandbox flags
// are restricted by the parent document's sandbox flags and the iframe's
// sandbox attribute. It is the union of:
// - The parent's sandbox flags which are contained in
// policy_container_data and were cloned from the parent's document policy
// container above.
// - The iframe's sandbox attribute which is contained in frame_policy, from
// the owner element's frame policy.
policy_container_data->sandbox_flags |= frame_policy.sandbox_flags;
frame_policy.sandbox_flags = policy_container_data->sandbox_flags;
// No URL is associated with this frame, but we can still assign UKM events to
// this identifier.
ukm::SourceId document_ukm_source_id = ukm::NoURLSourceId();
auto complete_initialization = [this, owner_element, &policy_container_remote,
&policy_container_data, &name,
document_ukm_source_id](
WebLocalFrame* new_child_frame,
const DocumentToken& document_token) {
// The initial empty document's credentialless bit is the union of:
// - its parent's credentialless bit.
// - its frame's credentialless attribute.
policy_container_data->is_credentialless |= owner_element->Credentialless();
std::unique_ptr<PolicyContainer> policy_container =
std::make_unique<PolicyContainer>(std::move(policy_container_remote),
std::move(policy_container_data));
KURL creator_base_url(owner_element->GetDocument().BaseURL());
To<WebLocalFrameImpl>(new_child_frame)
->InitializeCoreFrameInternal(
*GetFrame()->GetPage(), owner_element, this, LastChild(),
FrameInsertType::kInsertInConstructor, name,
&GetFrame()->window_agent_factory(), nullptr, document_token,
std::move(policy_container),
GetFrame()->DomWindow()->GetStorageKey(), document_ukm_source_id,
creator_base_url);
};
// FIXME: Using subResourceAttributeName as fallback is not a perfect
// solution. subResourceAttributeName returns just one attribute name. The
// element might not have the attribute, and there might be other attributes
// which can identify the element.
WebLocalFrameImpl* webframe_child =
To<WebLocalFrameImpl>(client_->CreateChildFrame(
scope, name,
owner_element->getAttribute(
owner_element->SubResourceAttributeName()),
std::move(frame_policy), owner_properties, owner_element->OwnerType(),
WebPolicyContainerBindParams{std::move(policy_container_receiver)},
document_ukm_source_id, complete_initialization));
if (!webframe_child)
return nullptr;
DCHECK(webframe_child->Parent());
// If the lambda to complete initialization is not called, this will fail.
DCHECK(webframe_child->GetFrame());
return webframe_child->GetFrame();
}
RemoteFrame* WebLocalFrameImpl::CreateFencedFrame(
HTMLFencedFrameElement* fenced_frame,
mojo::PendingAssociatedReceiver<mojom::blink::FencedFrameOwnerHost>
receiver) {
mojom::blink::FrameReplicationStatePtr initial_replicated_state =
mojom::blink::FrameReplicationState::New();
initial_replicated_state->origin = SecurityOrigin::CreateUniqueOpaque();
RemoteFrameToken frame_token;
base::UnguessableToken devtools_frame_token =
base::UnguessableToken::Create();
auto remote_frame_interfaces =
mojom::blink::RemoteFrameInterfacesFromRenderer::New();
mojo::PendingAssociatedRemote<mojom::blink::RemoteFrameHost>
remote_frame_host = remote_frame_interfaces->frame_host_receiver
.InitWithNewEndpointAndPassRemote();
mojo::PendingAssociatedReceiver<mojom::blink::RemoteFrame>
remote_frame_receiver =
remote_frame_interfaces->frame.InitWithNewEndpointAndPassReceiver();
GetFrame()->GetLocalFrameHostRemote().CreateFencedFrame(
std::move(receiver), std::move(remote_frame_interfaces), frame_token,
devtools_frame_token);
DCHECK(initial_replicated_state->origin->IsOpaque());
WebRemoteFrameImpl* remote_frame =
WebRemoteFrameImpl::CreateForPortalOrFencedFrame(
mojom::blink::TreeScopeType::kDocument, frame_token,
devtools_frame_token, fenced_frame, std::move(remote_frame_host),
std::move(remote_frame_receiver),
std::move(initial_replicated_state));
client_->DidCreateFencedFrame(frame_token);
return remote_frame->GetFrame();
}
void WebLocalFrameImpl::DidChangeContentsSize(const gfx::Size& size) {
if (GetTextFinder() && GetTextFinder()->TotalMatchCount() > 0)
GetTextFinder()->IncreaseMarkerVersion();
}
bool WebLocalFrameImpl::HasDevToolsOverlays() const {
return dev_tools_agent_ && dev_tools_agent_->HasOverlays();
}
void WebLocalFrameImpl::UpdateDevToolsOverlaysPrePaint() {
if (dev_tools_agent_)
dev_tools_agent_->UpdateOverlaysPrePaint();
}
void WebLocalFrameImpl::PaintDevToolsOverlays(GraphicsContext& context) {
if (dev_tools_agent_)
dev_tools_agent_->PaintOverlays(context);
}
void WebLocalFrameImpl::CreateFrameView() {
TRACE_EVENT0("blink", "WebLocalFrameImpl::createFrameView");
DCHECK(GetFrame()); // If frame() doesn't exist, we probably didn't init
// properly.
WebViewImpl* web_view = ViewImpl();
// Check if we're shutting down.
if (!web_view->GetPage())
return;
bool is_main_frame = !Parent();
// TODO(dcheng): Can this be better abstracted away? It's pretty ugly that
// only local roots are special-cased here.
gfx::Size initial_size = (is_main_frame || !frame_widget_)
? web_view->MainFrameSize()
: frame_widget_->Size();
Color base_background_color = web_view->BaseBackgroundColor();
if (!is_main_frame && Parent()->IsWebRemoteFrame())
base_background_color = Color::kTransparent;
GetFrame()->CreateView(initial_size, base_background_color);
if (web_view->ShouldAutoResize() && GetFrame()->IsLocalRoot()) {
GetFrame()->View()->EnableAutoSizeMode(web_view->MinAutoSize(),
web_view->MaxAutoSize());
}
if (frame_widget_)
frame_widget_->DidCreateLocalRootView();
}
WebLocalFrameImpl* WebLocalFrameImpl::FromFrame(LocalFrame* frame) {
if (!frame)
return nullptr;
return FromFrame(*frame);
}
std::string WebLocalFrameImpl::GetNullFrameReasonForBug1139104(
LocalFrame* frame) {
LocalFrameClient* client = frame->Client();
if (!client)
return "WebLocalFrameImpl::client";
if (!client->IsLocalFrameClientImpl())
return "WebLocalFrameImpl::client-not-local";
WebLocalFrame* web_frame = client->GetWebFrame();
if (!web_frame)
return "WebLocalFrameImpl::web_frame";
return "not-null";
}
WebLocalFrameImpl* WebLocalFrameImpl::FromFrame(LocalFrame& frame) {
LocalFrameClient* client = frame.Client();
if (!client || !client->IsLocalFrameClientImpl())
return nullptr;
return To<WebLocalFrameImpl>(client->GetWebFrame());
}
WebViewImpl* WebLocalFrameImpl::ViewImpl() const {
if (!GetFrame())
return nullptr;
return GetFrame()->GetPage()->GetChromeClient().GetWebView();
}
void WebLocalFrameImpl::DidFailLoad(const ResourceError& error,
WebHistoryCommitType web_commit_type) {
if (WebPluginContainerImpl* plugin = GetFrame()->GetWebPluginContainer())
plugin->DidFailLoading(error);
WebDocumentLoader* document_loader = GetDocumentLoader();
DCHECK(document_loader);
GetFrame()->GetLocalFrameHostRemote().DidFailLoadWithError(
document_loader->GetUrl(), error.ErrorCode());
}
void WebLocalFrameImpl::DidFinish() {
if (!Client())
return;
if (WebPluginContainerImpl* plugin = GetFrame()->GetWebPluginContainer())
plugin->DidFinishLoading();
Client()->DidFinishLoad();
}
void WebLocalFrameImpl::DidFinishLoadForPrinting() {
Client()->DidFinishLoadForPrinting();
}
HitTestResult WebLocalFrameImpl::HitTestResultForVisualViewportPos(
const gfx::Point& pos_in_viewport) {
gfx::Point root_frame_point(
GetFrame()->GetPage()->GetVisualViewport().ViewportToRootFrame(
pos_in_viewport));
HitTestLocation location(
GetFrame()->View()->ConvertFromRootFrame(root_frame_point));
HitTestResult result = GetFrame()->GetEventHandler().HitTestResultAtLocation(
location, HitTestRequest::kReadOnly | HitTestRequest::kActive);
result.SetToShadowHostIfInUAShadowRoot();
return result;
}
void WebLocalFrameImpl::SetAutofillClient(WebAutofillClient* autofill_client) {
autofill_client_ = autofill_client;
}
WebAutofillClient* WebLocalFrameImpl::AutofillClient() {
return autofill_client_;
}
void WebLocalFrameImpl::SetContentCaptureClient(
WebContentCaptureClient* content_capture_client) {
content_capture_client_ = content_capture_client;
}
WebContentCaptureClient* WebLocalFrameImpl::ContentCaptureClient() const {
return content_capture_client_;
}
bool WebLocalFrameImpl::IsProvisional() const {
return frame_->IsProvisional();
}
WebLocalFrameImpl* WebLocalFrameImpl::LocalRoot() {
DCHECK(GetFrame());
auto* result = FromFrame(GetFrame()->LocalFrameRoot());
DCHECK(result);
return result;
}
WebFrame* WebLocalFrameImpl::FindFrameByName(const WebString& name) {
return WebFrame::FromCoreFrame(GetFrame()->Tree().FindFrameByName(name));
}
void WebLocalFrameImpl::SetEmbeddingToken(
const base::UnguessableToken& embedding_token) {
frame_->SetEmbeddingToken(embedding_token);
}
bool WebLocalFrameImpl::IsInFencedFrameTree() const {
bool result = frame_->IsInFencedFrameTree();
DCHECK(!result || blink::features::IsFencedFramesEnabled());
return result;
}
const std::optional<base::UnguessableToken>&
WebLocalFrameImpl::GetEmbeddingToken() const {
return frame_->GetEmbeddingToken();
}
void WebLocalFrameImpl::SendPings(const WebURL& destination_url) {
DCHECK(GetFrame());
if (Node* node = ContextMenuNodeInner()) {
Element* anchor = node->EnclosingLinkEventParentOrSelf();
if (auto* html_anchor = DynamicTo<HTMLAnchorElement>(anchor))
html_anchor->SendPings(destination_url);
}
}
bool WebLocalFrameImpl::DispatchBeforeUnloadEvent(bool is_reload) {
if (!GetFrame())
return true;
return GetFrame()->Loader().ShouldClose(is_reload);
}
void WebLocalFrameImpl::CommitNavigation(
std::unique_ptr<WebNavigationParams> navigation_params,
std::unique_ptr<WebDocumentLoader::ExtraData> extra_data) {
DCHECK(GetFrame());
DCHECK(!navigation_params->url.ProtocolIs("javascript"));
if (navigation_params->is_synchronous_commit_for_bug_778318) {
DCHECK(WebDocumentLoader::WillLoadUrlAsEmpty(navigation_params->url));
navigation_params->storage_key = GetFrame()->DomWindow()->GetStorageKey();
navigation_params->document_ukm_source_id =
GetFrame()->DomWindow()->UkmSourceID();
// This corresponds to step 8 of
// https://html.spec.whatwg.org/multipage/browsers.html#creating-a-new-browsing-context.
// Most of these steps are handled in the caller
// (RenderFrameImpl::SynchronouslyCommitAboutBlankForBug778318) but the
// caller doesn't have access to the core frame (LocalFrame).
// The actual agent is determined downstream, but here we need to request
// whether an origin-keyed agent is needed. Since this case is only
// for about:blank navigations this reduces to copying the agent flag from
// the current document.
navigation_params->origin_agent_cluster =
GetFrame()->GetDocument()->GetAgent().IsOriginKeyedForInheritance();
KURL url = navigation_params->url;
if (navigation_params->is_synchronous_commit_for_bug_778318 &&
// Explicitly check for about:blank or about:srcdoc to prevent things
// like about:mumble propagating the base url.
(url.IsAboutBlankURL() || url.IsAboutSrcdocURL())) {
navigation_params->fallback_base_url =
GetFrame()->GetDocument()->BaseURL();
}
}
if (GetTextFinder())
GetTextFinder()->ClearActiveFindMatch();
GetFrame()->Loader().CommitNavigation(std::move(navigation_params),
std::move(extra_data));
}
blink::mojom::CommitResult WebLocalFrameImpl::CommitSameDocumentNavigation(
const WebURL& url,
WebFrameLoadType web_frame_load_type,
const WebHistoryItem& item,
bool is_client_redirect,
bool has_transient_user_activation,
const WebSecurityOrigin& initiator_origin,
bool is_browser_initiated,
std::optional<scheduler::TaskAttributionId>
soft_navigation_heuristics_task_id) {
DCHECK(GetFrame());
DCHECK(!url.ProtocolIs("javascript"));
HistoryItem* history_item = item;
return GetFrame()->Loader().GetDocumentLoader()->CommitSameDocumentNavigation(
url, web_frame_load_type, history_item,
is_client_redirect ? ClientRedirectPolicy::kClientRedirect
: ClientRedirectPolicy::kNotClientRedirect,
has_transient_user_activation, initiator_origin.Get(),
/*is_synchronously_committed=*/false, /*source_element=*/nullptr,
mojom::blink::TriggeringEventInfo::kNotFromEvent, is_browser_initiated,
soft_navigation_heuristics_task_id);
}
bool WebLocalFrameImpl::IsLoading() const {
if (!GetFrame() || !GetFrame()->GetDocument())
return false;
return GetFrame()->GetDocument()->IsInitialEmptyDocument() ||
GetFrame()->Loader().HasProvisionalNavigation() ||
!GetFrame()->GetDocument()->LoadEventFinished();
}
bool WebLocalFrameImpl::IsNavigationScheduledWithin(
base::TimeDelta interval) const {
if (!GetFrame())
return false;
return GetFrame()->Loader().HasProvisionalNavigation() ||
GetFrame()->GetDocument()->IsHttpRefreshScheduledWithin(interval);
}
void WebLocalFrameImpl::SetIsNotOnInitialEmptyDocument() {
DCHECK(GetFrame());
GetFrame()->GetDocument()->OverrideIsInitialEmptyDocument();
GetFrame()->Loader().SetIsNotOnInitialEmptyDocument();
}
bool WebLocalFrameImpl::IsOnInitialEmptyDocument() {
DCHECK(GetFrame());
return GetFrame()->GetDocument()->IsInitialEmptyDocument();
}
void WebLocalFrameImpl::BlinkFeatureUsageReport(
blink::mojom::WebFeature feature) {
UseCounter::Count(GetFrame()->GetDocument(), feature);
}
void WebLocalFrameImpl::DidDropNavigation() {
GetFrame()->Loader().DidDropNavigation();
}
void WebLocalFrameImpl::DownloadURL(
const WebURLRequest& request,
network::mojom::blink::RedirectMode cross_origin_redirect_behavior,
CrossVariantMojoRemote<mojom::blink::BlobURLTokenInterfaceBase>
blob_url_token) {
GetFrame()->DownloadURL(request.ToResourceRequest(),
cross_origin_redirect_behavior,
std::move(blob_url_token));
}
void WebLocalFrameImpl::MaybeStartOutermostMainFrameNavigation(
const WebVector<WebURL>& urls) const {
Vector<KURL> kurls;
std::move(urls.begin(), urls.end(), std::back_inserter(kurls));
GetFrame()->MaybeStartOutermostMainFrameNavigation(std::move(kurls));
}
bool WebLocalFrameImpl::WillStartNavigation(const WebNavigationInfo& info) {
DCHECK(!info.url_request.IsNull());
DCHECK(!info.url_request.Url().ProtocolIs("javascript"));
return GetFrame()->Loader().WillStartNavigation(info);
}
void WebLocalFrameImpl::SendOrientationChangeEvent() {
// Speculative fix for https://crbug.com/1143380.
// TODO(https://crbug.com/838348): It's a logic bug that this function is
// being called when either the LocalFrame or LocalDOMWindow are null, but
// there is a bug where the browser can inadvertently detach the main frame of
// a WebView that is still active.
if (!GetFrame() || !GetFrame()->DomWindow())
return;
// Screen Orientation API
CoreInitializer::GetInstance().NotifyOrientationChanged(*GetFrame());
// Legacy window.orientation API
if (RuntimeEnabledFeatures::OrientationEventEnabled())
GetFrame()->DomWindow()->SendOrientationChangeEvent();
}
WebNode WebLocalFrameImpl::ContextMenuNode() const {
return ContextMenuNodeInner();
}
WebNode WebLocalFrameImpl::ContextMenuImageNode() const {
return ContextMenuImageNodeInner();
}
void WebLocalFrameImpl::WillBeDetached() {
if (frame_->IsMainFrame())
ViewImpl()->DidDetachLocalMainFrame();
if (dev_tools_agent_)
dev_tools_agent_->WillBeDestroyed();
if (find_in_page_)
find_in_page_->Dispose();
if (print_client_)
print_client_->WillBeDestroyed();
for (auto& observer : observers_)
observer.WebLocalFrameDetached();
}
void WebLocalFrameImpl::WillDetachParent() {
// Do not expect string scoping results from any frames that got detached
// in the middle of the operation.
if (GetTextFinder() && GetTextFinder()->ScopingInProgress()) {
// There is a possibility that the frame being detached was the only
// pending one. We need to make sure final replies can be sent.
GetTextFinder()->FlushCurrentScoping();
GetTextFinder()->CancelPendingScopingEffort();
}
}
void WebLocalFrameImpl::CreateFrameWidgetInternal(
base::PassKey<WebLocalFrame> pass_key,
CrossVariantMojoAssociatedRemote<mojom::blink::FrameWidgetHostInterfaceBase>
mojo_frame_widget_host,
CrossVariantMojoAssociatedReceiver<mojom::blink::FrameWidgetInterfaceBase>
mojo_frame_widget,
CrossVariantMojoAssociatedRemote<mojom::blink::WidgetHostInterfaceBase>
mojo_widget_host,
CrossVariantMojoAssociatedReceiver<mojom::blink::WidgetInterfaceBase>
mojo_widget,
const viz::FrameSinkId& frame_sink_id,
bool is_for_nested_main_frame,
bool is_for_scalable_page,
bool hidden) {
DCHECK(!frame_widget_);
DCHECK(frame_->IsLocalRoot());
bool is_for_child_local_root = Parent();
// Check that if this is for a child local root |is_for_nested_main_frame|
// is false.
DCHECK(!is_for_child_local_root || !is_for_nested_main_frame);
bool never_composited = ViewImpl()->widgets_never_composited();
if (g_create_web_frame_widget) {
// It is safe to cast to WebFrameWidgetImpl because the only concrete
// subclass of WebFrameWidget that is allowed is WebFrameWidgetImpl. This
// is enforced via a private constructor (and friend class) on
// WebFrameWidget.
frame_widget_ =
static_cast<WebFrameWidgetImpl*>(g_create_web_frame_widget->Run(
std::move(pass_key), std::move(mojo_frame_widget_host),
std::move(mojo_frame_widget), std::move(mojo_widget_host),
std::move(mojo_widget),
Scheduler()->GetAgentGroupScheduler()->DefaultTaskRunner(),
frame_sink_id, hidden, never_composited, is_for_child_local_root,
is_for_nested_main_frame, is_for_scalable_page));
} else {
frame_widget_ = MakeGarbageCollected<WebFrameWidgetImpl>(
std::move(pass_key), std::move(mojo_frame_widget_host),
std::move(mojo_frame_widget), std::move(mojo_widget_host),
std::move(mojo_widget),
Scheduler()->GetAgentGroupScheduler()->DefaultTaskRunner(),
frame_sink_id, hidden, never_composited, is_for_child_local_root,
is_for_nested_main_frame, is_for_scalable_page);
}
frame_widget_->BindLocalRoot(*this);
// If this is for a main frame grab the associated WebViewImpl and
// assign this widget as the main frame widget.
// Note: this can't DCHECK that the view's main frame points to
// |this|, as provisional frames violate this precondition.
if (!is_for_child_local_root) {
DCHECK(ViewImpl());
ViewImpl()->SetMainFrameViewWidget(frame_widget_);
}
}
WebFrameWidget* WebLocalFrameImpl::FrameWidget() const {
return frame_widget_.Get();
}
void WebLocalFrameImpl::CopyImageAtForTesting(
const gfx::Point& pos_in_viewport) {
GetFrame()->CopyImageAtViewportPoint(pos_in_viewport);
}
void WebLocalFrameImpl::ShowContextMenuFromExternal(
const UntrustworthyContextMenuParams& params,
CrossVariantMojoAssociatedRemote<
mojom::blink::ContextMenuClientInterfaceBase> context_menu_client) {
GetFrame()->GetLocalFrameHostRemote().ShowContextMenu(
std::move(context_menu_client), params);
}
void WebLocalFrameImpl::ShowContextMenu(
mojo::PendingAssociatedRemote<mojom::blink::ContextMenuClient> client,
const blink::ContextMenuData& data,
const std::optional<gfx::Point>& host_context_menu_location) {
UntrustworthyContextMenuParams params =
blink::ContextMenuParamsBuilder::Build(data);
if (host_context_menu_location.has_value()) {
// If the context menu request came from the browser, it came with a
// position that was stored on blink::WebFrameWidgetImpl and is relative to
// the WindowScreenRect.
params.x = host_context_menu_location.value().x();
params.y = host_context_menu_location.value().y();
} else {
// If the context menu request came from the renderer, the position in
// |params| is real, but they come in blink viewport coordinates, which
// include the device scale factor, but not emulation scale. Here we convert
// them to DIP coordinates relative to the WindowScreenRect.
// TODO(crbug.com/1093904): This essentially is a floor of the coordinates.
// Determine if rounding is more appropriate.
gfx::Rect position_in_dips =
LocalRootFrameWidget()->BlinkSpaceToEnclosedDIPs(
gfx::Rect(params.x, params.y, 0, 0));
const float scale = LocalRootFrameWidget()->GetEmulatorScale();
params.x = position_in_dips.x() * scale;
params.y = position_in_dips.y() * scale;
}
// Serializing a GURL longer than kMaxURLChars will fail, so don't do
// it. We replace it with an empty GURL so the appropriate items are disabled
// in the context menu.
// TODO(jcivelli): http://crbug.com/45160 This prevents us from saving large
// data encoded images. We should have a way to save them.
if (params.src_url.spec().size() > url::kMaxURLChars)
params.src_url = GURL();
params.selection_rect =
LocalRootFrameWidget()->BlinkSpaceToEnclosedDIPs(data.selection_rect);
if (!GetFrame())
return;
GetFrame()->GetLocalFrameHostRemote().ShowContextMenu(std::move(client),
params);
if (Client())
Client()->UpdateContextMenuDataForTesting(data, host_context_menu_location);
}
bool WebLocalFrameImpl::IsAllowedToDownload() const {
if (!GetFrame())
return true;
return (GetFrame()->Loader().PendingEffectiveSandboxFlags() &
network::mojom::blink::WebSandboxFlags::kDownloads) ==
network::mojom::blink::WebSandboxFlags::kNone;
}
bool WebLocalFrameImpl::IsCrossOriginToOutermostMainFrame() const {
return GetFrame()->IsCrossOriginToOutermostMainFrame();
}
void WebLocalFrameImpl::UsageCountChromeLoadTimes(const WebString& metric) {
WebFeature feature = WebFeature::kChromeLoadTimesUnknown;
if (metric == "requestTime") {
feature = WebFeature::kChromeLoadTimesRequestTime;
} else if (metric == "startLoadTime") {
feature = WebFeature::kChromeLoadTimesStartLoadTime;
} else if (metric == "commitLoadTime") {
feature = WebFeature::kChromeLoadTimesCommitLoadTime;
} else if (metric == "finishDocumentLoadTime") {
feature = WebFeature::kChromeLoadTimesFinishDocumentLoadTime;
} else if (metric == "finishLoadTime") {
feature = WebFeature::kChromeLoadTimesFinishLoadTime;
} else if (metric == "firstPaintTime") {
feature = WebFeature::kChromeLoadTimesFirstPaintTime;
} else if (metric == "firstPaintAfterLoadTime") {
feature = WebFeature::kChromeLoadTimesFirstPaintAfterLoadTime;
} else if (metric == "navigationType") {
feature = WebFeature::kChromeLoadTimesNavigationType;
} else if (metric == "wasFetchedViaSpdy") {
feature = WebFeature::kChromeLoadTimesWasFetchedViaSpdy;
} else if (metric == "wasNpnNegotiated") {
feature = WebFeature::kChromeLoadTimesWasNpnNegotiated;
} else if (metric == "npnNegotiatedProtocol") {
feature = WebFeature::kChromeLoadTimesNpnNegotiatedProtocol;
} else if (metric == "wasAlternateProtocolAvailable") {
feature = WebFeature::kChromeLoadTimesWasAlternateProtocolAvailable;
} else if (metric == "connectionInfo") {
feature = WebFeature::kChromeLoadTimesConnectionInfo;
}
Deprecation::CountDeprecation(GetFrame()->DomWindow(), feature);
}
void WebLocalFrameImpl::UsageCountChromeCSI(const WebString& metric) {
CHECK(GetFrame());
WebFeature feature = WebFeature::kChromeCSIUnknown;
if (metric == "onloadT") {
feature = WebFeature::kChromeCSIOnloadT;
} else if (metric == "pageT") {
feature = WebFeature::kChromeCSIPageT;
} else if (metric == "startE") {
feature = WebFeature::kChromeCSIStartE;
} else if (metric == "tran") {
feature = WebFeature::kChromeCSITran;
}
GetFrame()->DomWindow()->CountUse(feature);
}
FrameScheduler* WebLocalFrameImpl::Scheduler() const {
return GetFrame()->GetFrameScheduler();
}
scheduler::WebAgentGroupScheduler* WebLocalFrameImpl::GetAgentGroupScheduler()
const {
return &ViewImpl()->GetWebAgentGroupScheduler();
}
scoped_refptr<base::SingleThreadTaskRunner> WebLocalFrameImpl::GetTaskRunner(
TaskType task_type) {
return GetFrame()->GetTaskRunner(task_type);
}
WebInputMethodController* WebLocalFrameImpl::GetInputMethodController() {
return &input_method_controller_;
}
bool WebLocalFrameImpl::ShouldSuppressKeyboardForFocusedElement() {
if (!autofill_client_)
return false;
DCHECK(GetFrame()->GetDocument());
auto* focused_form_control_element = DynamicTo<HTMLFormControlElement>(
GetFrame()->GetDocument()->FocusedElement());
return focused_form_control_element &&
autofill_client_->ShouldSuppressKeyboard(focused_form_control_element);
}
void WebLocalFrameImpl::AddMessageToConsoleImpl(
const WebConsoleMessage& message,
bool discard_duplicates) {
DCHECK(GetFrame());
GetFrame()->GetDocument()->AddConsoleMessage(
MakeGarbageCollected<ConsoleMessage>(message, GetFrame()),
discard_duplicates);
}
// This is only triggered by test_runner.cc
void WebLocalFrameImpl::AddInspectorIssueImpl(
mojom::blink::InspectorIssueCode code) {
DCHECK(GetFrame());
auto info = mojom::blink::InspectorIssueInfo::New(
code, mojom::blink::InspectorIssueDetails::New());
GetFrame()->AddInspectorIssue(
AuditsIssue(ConvertInspectorIssueToProtocolFormat(
InspectorIssue::Create(std::move(info)))));
}
void WebLocalFrameImpl::AddGenericIssueImpl(
mojom::blink::GenericIssueErrorType error_type,
int violating_node_id) {
DCHECK(GetFrame());
AuditsIssue::ReportGenericIssue(GetFrame(), error_type, violating_node_id);
}
void WebLocalFrameImpl::AddGenericIssueImpl(
mojom::blink::GenericIssueErrorType error_type,
int violating_node_id,
const WebString& violating_node_attribute) {
DCHECK(GetFrame());
AuditsIssue::ReportGenericIssue(GetFrame(), error_type, violating_node_id,
violating_node_attribute);
}
void WebLocalFrameImpl::SetTextCheckClient(
WebTextCheckClient* text_check_client) {
text_check_client_ = text_check_client;
}
void WebLocalFrameImpl::SetSpellCheckPanelHostClient(
WebSpellCheckPanelHostClient* spell_check_panel_host_client) {
spell_check_panel_host_client_ = spell_check_panel_host_client;
}
WebFrameWidgetImpl* WebLocalFrameImpl::LocalRootFrameWidget() {
CHECK(LocalRoot());
return LocalRoot()->FrameWidgetImpl();
}
Node* WebLocalFrameImpl::ContextMenuNodeInner() const {
if (!ViewImpl() || !ViewImpl()->GetPage())
return nullptr;
return ViewImpl()
->GetPage()
->GetContextMenuController()
.ContextMenuNodeForFrame(GetFrame());
}
Node* WebLocalFrameImpl::ContextMenuImageNodeInner() const {
if (!ViewImpl() || !ViewImpl()->GetPage())
return nullptr;
return ViewImpl()
->GetPage()
->GetContextMenuController()
.ContextMenuImageNodeForFrame(GetFrame());
}
void WebLocalFrameImpl::WaitForDebuggerWhenShown() {
DCHECK(frame_->IsLocalRoot());
DevToolsAgentImpl()->WaitForDebuggerWhenShown();
}
void WebLocalFrameImpl::SetDevToolsAgentImpl(WebDevToolsAgentImpl* agent) {
DCHECK(!dev_tools_agent_);
dev_tools_agent_ = agent;
}
WebDevToolsAgentImpl* WebLocalFrameImpl::DevToolsAgentImpl() {
if (!frame_->IsLocalRoot())
return nullptr;
if (!dev_tools_agent_)
dev_tools_agent_ = WebDevToolsAgentImpl::CreateForFrame(this);
return dev_tools_agent_.Get();
}
void WebLocalFrameImpl::WasHidden() {
if (frame_)
frame_->WasHidden();
}
void WebLocalFrameImpl::WasShown() {
if (frame_)
frame_->WasShown();
}
void WebLocalFrameImpl::SetAllowsCrossBrowsingInstanceFrameLookup() {
DCHECK(GetFrame());
// Allow the frame's security origin to access other SecurityOrigins
// that match everything except the agent cluster check. This is needed
// for embedders that hand out frame references outside of a browsing
// instance, for example extensions and webview tag.
auto* window = GetFrame()->DomWindow();
window->GetMutableSecurityOrigin()->GrantCrossAgentClusterAccess();
}
WebHistoryItem WebLocalFrameImpl::GetCurrentHistoryItem() const {
return WebHistoryItem(current_history_item_);
}
void WebLocalFrameImpl::SetLocalStorageArea(
CrossVariantMojoRemote<mojom::StorageAreaInterfaceBase>
local_storage_area) {
CoreInitializer::GetInstance().SetLocalStorageArea(
*GetFrame(), std::move(local_storage_area));
}
void WebLocalFrameImpl::SetSessionStorageArea(
CrossVariantMojoRemote<mojom::StorageAreaInterfaceBase>
session_storage_area) {
CoreInitializer::GetInstance().SetSessionStorageArea(
*GetFrame(), std::move(session_storage_area));
}
void WebLocalFrameImpl::SetNotRestoredReasons(
const mojom::BackForwardCacheNotRestoredReasonsPtr& not_restored_reasons) {
GetFrame()->SetNotRestoredReasons(
ConvertNotRestoredReasons(not_restored_reasons));
}
const mojom::blink::BackForwardCacheNotRestoredReasonsPtr&
WebLocalFrameImpl::GetNotRestoredReasons() {
return GetFrame()->GetNotRestoredReasons();
}
mojom::blink::BackForwardCacheNotRestoredReasonsPtr
WebLocalFrameImpl::ConvertNotRestoredReasons(
const mojom::BackForwardCacheNotRestoredReasonsPtr& reasons_to_copy) {
mojom::blink::BackForwardCacheNotRestoredReasonsPtr not_restored_reasons;
if (!reasons_to_copy.is_null()) {
not_restored_reasons =
mojom::blink::BackForwardCacheNotRestoredReasons::New();
if (reasons_to_copy->id) {
not_restored_reasons->id = reasons_to_copy->id.value().c_str();
}
if (reasons_to_copy->name) {
not_restored_reasons->name = reasons_to_copy->name.value().c_str();
}
if (reasons_to_copy->src) {
not_restored_reasons->src = reasons_to_copy->src.value().c_str();
}
for (const auto& reason_to_copy : reasons_to_copy->reasons) {
mojom::blink::BFCacheBlockingDetailedReasonPtr reason =
mojom::blink::BFCacheBlockingDetailedReason::New();
reason->name = WTF::String(reason_to_copy->name);
if (reason_to_copy->source) {
CHECK_GT(reason_to_copy->source->line_number, 0U);
CHECK_GT(reason_to_copy->source->column_number, 0U);
mojom::blink::ScriptSourceLocationPtr source_location =
mojom::blink::ScriptSourceLocation::New(
KURL(reason_to_copy->source->url),
WTF::String(reason_to_copy->source->function_name),
reason_to_copy->source->line_number,
reason_to_copy->source->column_number);
reason->source = std::move(source_location);
}
not_restored_reasons->reasons.push_back(std::move(reason));
}
if (reasons_to_copy->same_origin_details) {
auto details = mojom::blink::SameOriginBfcacheNotRestoredDetails::New();
details->url = KURL(reasons_to_copy->same_origin_details->url);
for (const auto& child : reasons_to_copy->same_origin_details->children) {
details->children.push_back(ConvertNotRestoredReasons(child));
}
not_restored_reasons->same_origin_details = std::move(details);
}
}
return not_restored_reasons;
}
void WebLocalFrameImpl::SetLCPPHint(
const mojom::LCPCriticalPathPredictorNavigationTimeHintPtr& hint) {
LocalFrame* frame = GetFrame();
if (!frame) {
return;
}
LCPCriticalPathPredictor* lcpp = frame->GetLCPP();
if (!lcpp) {
return;
}
lcpp->Reset();
if (!hint) {
return;
}
lcpp->set_lcp_element_locators(hint->lcp_element_locators);
HashSet<KURL> lcp_influencer_scripts;
for (auto& url : hint->lcp_influencer_scripts) {
lcp_influencer_scripts.insert(KURL(url));
}
lcpp->set_lcp_influencer_scripts(std::move(lcp_influencer_scripts));
Vector<KURL> fetched_fonts;
fetched_fonts.reserve(
base::checked_cast<wtf_size_t>(hint->fetched_fonts.size()));
for (const auto& url : hint->fetched_fonts) {
fetched_fonts.emplace_back(url);
}
lcpp->set_fetched_fonts(std::move(fetched_fonts));
Vector<url::Origin> preconnect_origins;
preconnect_origins.reserve(
base::checked_cast<wtf_size_t>(hint->preconnect_origins.size()));
for (const auto& origin_url : hint->preconnect_origins) {
preconnect_origins.emplace_back(url::Origin::Create(origin_url));
}
lcpp->set_preconnected_origins(preconnect_origins);
Vector<KURL> unused_preloads;
unused_preloads.reserve(
base::checked_cast<wtf_size_t>(hint->unused_preloads.size()));
for (const auto& url : hint->unused_preloads) {
unused_preloads.emplace_back(url);
}
lcpp->set_unused_preloads(std::move(unused_preloads));
}
void WebLocalFrameImpl::AddHitTestOnTouchStartCallback(
base::RepeatingCallback<void(const blink::WebHitTestResult&)> callback) {
TouchStartEventListener* touch_start_event_listener =
MakeGarbageCollected<TouchStartEventListener>(std::move(callback));
AddEventListenerOptionsResolved options;
options.setPassive(true);
options.SetPassiveSpecified(true);
options.setCapture(true);
GetFrame()->DomWindow()->addEventListener(
event_type_names::kTouchstart, touch_start_event_listener, &options);
}
void WebLocalFrameImpl::BlockParserForTesting() {
// Avoid blocking for MHTML tests since MHTML archives are loaded
// synchronously during commit. WebFrameTestProxy only has a chance to act at
// DidCommit after that's happened.
if (GetFrame()->Loader().GetDocumentLoader()->Archive()) {
return;
}
GetFrame()->Loader().GetDocumentLoader()->BlockParser();
}
void WebLocalFrameImpl::ResumeParserForTesting() {
if (GetFrame()->Loader().GetDocumentLoader()->Archive()) {
return;
}
GetFrame()->Loader().GetDocumentLoader()->ResumeParser();
}
void WebLocalFrameImpl::FlushInputForTesting(base::OnceClosure done_callback) {
frame_widget_->FlushInputForTesting(std::move(done_callback));
}
void WebLocalFrameImpl::SetTargetToCurrentHistoryItem(const WebString& target) {
current_history_item_->SetTarget(target);
}
void WebLocalFrameImpl::UpdateCurrentHistoryItem() {
current_history_item_ = WebHistoryItem(
GetFrame()->Loader().GetDocumentLoader()->GetHistoryItem());
}
PageState WebLocalFrameImpl::CurrentHistoryItemToPageState() {
return current_history_item_->ToPageState();
}
void WebLocalFrameImpl::ScrollFocusedEditableElementIntoView() {
if (has_scrolled_focused_editable_node_into_rect_ && autofill_client_) {
autofill_client_->DidCompleteFocusChangeInFrame();
return;
}
WebFrameWidgetImpl* local_root_frame_widget = LocalRootFrameWidget();
if (!local_root_frame_widget->ScrollFocusedEditableElementIntoView())
return;
has_scrolled_focused_editable_node_into_rect_ = true;
if (!local_root_frame_widget->HasPendingPageScaleAnimation() &&
autofill_client_) {
autofill_client_->DidCompleteFocusChangeInFrame();
}
}
void WebLocalFrameImpl::ResetHasScrolledFocusedEditableIntoView() {
has_scrolled_focused_editable_node_into_rect_ = false;
}
void WebLocalFrameImpl::AddObserver(WebLocalFrameObserver* observer) {
// Ensure that the frame is attached.
DCHECK(GetFrame());
observers_.AddObserver(observer);
}
void WebLocalFrameImpl::RemoveObserver(WebLocalFrameObserver* observer) {
observers_.RemoveObserver(observer);
}
void WebLocalFrameImpl::WillSendSubmitEvent(const WebFormElement& form) {
for (auto& observer : observers_)
observer.WillSendSubmitEvent(form);
}
} // namespace blink