| /* |
| * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org> |
| * 1999 Lars Knoll <knoll@kde.org> |
| * 1999 Antti Koivisto <koivisto@kde.org> |
| * 2000 Simon Hausmann <hausmann@kde.org> |
| * 2000 Stefan Schimanski <1Stein@gmx.de> |
| * 2001 George Staikos <staikos@kde.org> |
| * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All |
| * rights reserved. |
| * Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com> |
| * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) |
| * Copyright (C) 2008 Eric Seidel <eric@webkit.org> |
| * Copyright (C) 2008 Google Inc. |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Library General Public |
| * License as published by the Free Software Foundation; either |
| * version 2 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Library General Public License for more details. |
| * |
| * You should have received a copy of the GNU Library General Public License |
| * along with this library; see the file COPYING.LIB. If not, write to |
| * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
| * Boston, MA 02110-1301, USA. |
| */ |
| |
| #include "third_party/blink/renderer/core/frame/frame.h" |
| |
| #include <memory> |
| |
| #include "third_party/blink/public/web/web_local_frame_client.h" |
| #include "third_party/blink/public/web/web_remote_frame_client.h" |
| #include "third_party/blink/renderer/bindings/core/v8/window_proxy_manager.h" |
| #include "third_party/blink/renderer/core/dom/document_type.h" |
| #include "third_party/blink/renderer/core/dom/events/event.h" |
| #include "third_party/blink/renderer/core/dom/node_computed_style.h" |
| #include "third_party/blink/renderer/core/dom/user_gesture_indicator.h" |
| #include "third_party/blink/renderer/core/frame/local_dom_window.h" |
| #include "third_party/blink/renderer/core/frame/settings.h" |
| #include "third_party/blink/renderer/core/frame/use_counter.h" |
| #include "third_party/blink/renderer/core/html/html_frame_element_base.h" |
| #include "third_party/blink/renderer/core/input/event_handler.h" |
| #include "third_party/blink/renderer/core/layout/layout_embedded_content.h" |
| #include "third_party/blink/renderer/core/loader/empty_clients.h" |
| #include "third_party/blink/renderer/core/loader/navigation_scheduler.h" |
| #include "third_party/blink/renderer/core/page/focus_controller.h" |
| #include "third_party/blink/renderer/core/page/page.h" |
| #include "third_party/blink/renderer/core/probe/core_probes.h" |
| #include "third_party/blink/renderer/platform/instance_counters.h" |
| #include "third_party/blink/renderer/platform/loader/fetch/resource_error.h" |
| #include "third_party/blink/renderer/platform/wtf/assertions.h" |
| |
| namespace blink { |
| |
| Frame::~Frame() { |
| InstanceCounters::DecrementCounter(InstanceCounters::kFrameCounter); |
| DCHECK(!owner_); |
| DCHECK(IsDetached()); |
| } |
| |
| void Frame::Trace(blink::Visitor* visitor) { |
| visitor->Trace(tree_node_); |
| visitor->Trace(page_); |
| visitor->Trace(owner_); |
| visitor->Trace(window_proxy_manager_); |
| visitor->Trace(dom_window_); |
| visitor->Trace(client_); |
| visitor->Trace(navigation_rate_limiter_); |
| } |
| |
| void Frame::Detach(FrameDetachType type) { |
| DCHECK(client_); |
| // Detach() can be re-entered, so this can't simply DCHECK(IsAttached()). |
| DCHECK(!IsDetached()); |
| lifecycle_.AdvanceTo(FrameLifecycle::kDetaching); |
| |
| DetachImpl(type); |
| |
| if (GetPage()) |
| GetPage()->GetFocusController().FrameDetached(this); |
| |
| // Due to re-entrancy, |this| could have completed detaching already. |
| // TODO(dcheng): This DCHECK is not always true. See https://crbug.com/838348. |
| DCHECK(IsDetached() == !client_); |
| if (!client_) |
| return; |
| |
| detach_stack_ = base::debug::StackTrace(); |
| client_->SetOpener(nullptr); |
| // After this, we must no longer talk to the client since this clears |
| // its owning reference back to our owning LocalFrame. |
| client_->Detached(type); |
| client_ = nullptr; |
| // Mark the frame as detached once |client_| is null, as most of the frame has |
| // been torn down at this point. |
| // TODO(dcheng): Once https://crbug.com/820782 is fixed, Frame::Client() will |
| // also assert that it is only accessed when the frame is not detached. |
| lifecycle_.AdvanceTo(FrameLifecycle::kDetached); |
| // TODO(dcheng): This currently needs to happen after calling |
| // FrameClient::Detached() to make it easier for FrameClient::Detached() |
| // implementations to detect provisional frames and avoid removing them from |
| // the frame tree. https://crbug.com/578349. |
| DisconnectOwnerElement(); |
| page_ = nullptr; |
| } |
| |
| void Frame::DisconnectOwnerElement() { |
| if (!owner_) |
| return; |
| |
| // TODO(https://crbug.com/578349): If this is a provisional frame, the frame |
| // owner doesn't actually point to this frame, so don't clear it. Note that |
| // this can't use IsProvisional() because the |client_| is null already. |
| if (owner_->ContentFrame() == this) |
| owner_->ClearContentFrame(); |
| |
| owner_ = nullptr; |
| } |
| |
| Page* Frame::GetPage() const { |
| return page_; |
| } |
| |
| bool Frame::IsMainFrame() const { |
| return !Tree().Parent(); |
| } |
| |
| HTMLFrameOwnerElement* Frame::DeprecatedLocalOwner() const { |
| return DynamicTo<HTMLFrameOwnerElement>(owner_.Get()); |
| } |
| |
| static ChromeClient& GetEmptyChromeClient() { |
| DEFINE_STATIC_LOCAL(Persistent<EmptyChromeClient>, client, |
| (EmptyChromeClient::Create())); |
| return *client; |
| } |
| |
| ChromeClient& Frame::GetChromeClient() const { |
| if (Page* page = this->GetPage()) |
| return page->GetChromeClient(); |
| return GetEmptyChromeClient(); |
| } |
| |
| Frame* Frame::FindUnsafeParentScrollPropagationBoundary() { |
| Frame* current_frame = this; |
| Frame* ancestor_frame = Tree().Parent(); |
| |
| while (ancestor_frame) { |
| if (!ancestor_frame->GetSecurityContext()->GetSecurityOrigin()->CanAccess( |
| GetSecurityContext()->GetSecurityOrigin())) |
| return current_frame; |
| current_frame = ancestor_frame; |
| ancestor_frame = ancestor_frame->Tree().Parent(); |
| } |
| return nullptr; |
| } |
| |
| LayoutEmbeddedContent* Frame::OwnerLayoutObject() const { |
| if (!DeprecatedLocalOwner()) |
| return nullptr; |
| return DeprecatedLocalOwner()->GetLayoutEmbeddedContent(); |
| } |
| |
| Settings* Frame::GetSettings() const { |
| if (GetPage()) |
| return &GetPage()->GetSettings(); |
| return nullptr; |
| } |
| |
| WindowProxy* Frame::GetWindowProxy(DOMWrapperWorld& world) { |
| return window_proxy_manager_->GetWindowProxy(world); |
| } |
| |
| void Frame::DidChangeVisibilityState() { |
| HeapVector<Member<Frame>> child_frames; |
| for (Frame* child = Tree().FirstChild(); child; |
| child = child->Tree().NextSibling()) |
| child_frames.push_back(child); |
| for (wtf_size_t i = 0; i < child_frames.size(); ++i) |
| child_frames[i]->DidChangeVisibilityState(); |
| } |
| |
| void Frame::NotifyUserActivationInLocalTree() { |
| for (Frame* node = this; node; node = node->Tree().Parent()) |
| node->user_activation_state_.Activate(); |
| |
| // See FrameTreeNode::NotifyUserActivation() for details about this block. |
| auto* local_frame = DynamicTo<LocalFrame>(this); |
| if (local_frame && RuntimeEnabledFeatures::UserActivationV2Enabled() && |
| RuntimeEnabledFeatures::UserActivationSameOriginVisibilityEnabled()) { |
| const SecurityOrigin* security_origin = |
| local_frame->GetSecurityContext()->GetSecurityOrigin(); |
| |
| Frame& root = Tree().Top(); |
| for (Frame* node = &root; node; node = node->Tree().TraverseNext(&root)) { |
| auto* local_frame_node = DynamicTo<LocalFrame>(node); |
| if (local_frame_node && |
| security_origin->CanAccess( |
| local_frame_node->GetSecurityContext()->GetSecurityOrigin())) { |
| node->user_activation_state_.Activate(); |
| } |
| } |
| } |
| } |
| |
| bool Frame::ConsumeTransientUserActivationInLocalTree() { |
| bool was_active = user_activation_state_.IsActive(); |
| |
| // Note that consumption "touches" the whole frame tree, to guarantee that a |
| // malicious subframe can't embed sub-subframes in a way that could allow |
| // multiple consumptions per user activation. |
| Frame& root = Tree().Top(); |
| for (Frame* node = &root; node; node = node->Tree().TraverseNext(&root)) |
| node->user_activation_state_.ConsumeIfActive(); |
| |
| return was_active; |
| } |
| |
| void Frame::ClearUserActivationInLocalTree() { |
| for (Frame* node = this; node; node = node->Tree().TraverseNext(this)) |
| node->user_activation_state_.Clear(); |
| } |
| |
| void Frame::SetOwner(FrameOwner* owner) { |
| owner_ = owner; |
| UpdateInertIfPossible(); |
| UpdateInheritedEffectiveTouchActionIfPossible(); |
| } |
| |
| void Frame::UpdateInertIfPossible() { |
| if (auto* frame_owner_element = |
| DynamicTo<HTMLFrameOwnerElement>(owner_.Get())) { |
| frame_owner_element->UpdateDistributionForFlatTreeTraversal(); |
| if (frame_owner_element->IsInert()) |
| SetIsInert(true); |
| } |
| } |
| |
| void Frame::UpdateInheritedEffectiveTouchActionIfPossible() { |
| if (owner_) { |
| Frame* owner_frame = owner_->ContentFrame(); |
| if (owner_frame) { |
| SetInheritedEffectiveTouchAction( |
| owner_frame->InheritedEffectiveTouchAction()); |
| } |
| } |
| } |
| |
| const CString& Frame::ToTraceValue() { |
| // token's ToString() is latin1. |
| if (!trace_value_) |
| trace_value_ = CString(devtools_frame_token_.ToString().c_str()); |
| return trace_value_.value(); |
| } |
| |
| Frame::Frame(FrameClient* client, |
| Page& page, |
| FrameOwner* owner, |
| WindowProxyManager* window_proxy_manager) |
| : tree_node_(this), |
| page_(&page), |
| owner_(owner), |
| client_(client), |
| window_proxy_manager_(window_proxy_manager), |
| navigation_rate_limiter_(*this), |
| is_loading_(false), |
| devtools_frame_token_(client->GetDevToolsFrameToken()), |
| create_stack_(base::debug::StackTrace()) { |
| InstanceCounters::IncrementCounter(InstanceCounters::kFrameCounter); |
| |
| if (owner_) |
| owner_->SetContentFrame(*this); |
| else |
| page_->SetMainFrame(this); |
| } |
| |
| STATIC_ASSERT_ENUM(FrameDetachType::kRemove, |
| WebLocalFrameClient::DetachType::kRemove); |
| STATIC_ASSERT_ENUM(FrameDetachType::kSwap, |
| WebLocalFrameClient::DetachType::kSwap); |
| STATIC_ASSERT_ENUM(FrameDetachType::kRemove, |
| WebRemoteFrameClient::DetachType::kRemove); |
| STATIC_ASSERT_ENUM(FrameDetachType::kSwap, |
| WebRemoteFrameClient::DetachType::kSwap); |
| |
| } // namespace blink |