blob: 2e50c68a6599d9d5ad9fea3f5e57586f40e16fd6 [file] [log] [blame]
/*
* 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/feature_policy/feature_policy.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 {
using namespace HTMLNames;
Frame::~Frame() {
InstanceCounters::DecrementCounter(InstanceCounters::kFrameCounter);
DCHECK(!owner_);
DCHECK_EQ(lifecycle_.GetState(), FrameLifecycle::kDetached);
}
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_);
}
void Frame::Detach(FrameDetachType type) {
DCHECK(client_);
detach_stack_ = base::debug::StackTrace();
// By the time this method is called, the subclasses should have already
// advanced to the Detaching state.
DCHECK_EQ(lifecycle_.GetState(), FrameLifecycle::kDetaching);
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 owner_ && owner_->IsLocal() ? ToHTMLFrameOwnerElement(owner_)
: nullptr;
}
static ChromeClient& GetEmptyChromeClient() {
DEFINE_STATIC_LOCAL(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 (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();
}
void Frame::NotifyUserActivation() {
ToLocalFrame(this)->Client()->NotifyUserActivation();
NotifyUserActivationInLocalTree();
}
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;
}
bool Frame::ConsumeTransientUserActivation(
UserActivationUpdateSource update_source) {
if (update_source == UserActivationUpdateSource::kRenderer)
ToLocalFrame(this)->Client()->ConsumeUserActivation();
return ConsumeTransientUserActivationInLocalTree();
}
// static
std::unique_ptr<UserGestureIndicator> Frame::NotifyUserActivation(
LocalFrame* frame,
UserGestureToken::Status status) {
if (frame)
frame->NotifyUserActivation();
return std::make_unique<UserGestureIndicator>(status);
}
// static
std::unique_ptr<UserGestureIndicator> Frame::NotifyUserActivation(
LocalFrame* frame,
UserGestureToken* token) {
if (frame)
frame->NotifyUserActivation();
return std::make_unique<UserGestureIndicator>(token);
}
// static
bool Frame::HasTransientUserActivation(LocalFrame* frame,
bool checkIfMainThread) {
if (RuntimeEnabledFeatures::UserActivationV2Enabled()) {
return frame ? frame->HasTransientUserActivation() : false;
}
return checkIfMainThread
? UserGestureIndicator::ProcessingUserGestureThreadSafe()
: UserGestureIndicator::ProcessingUserGesture();
}
// static
bool Frame::ConsumeTransientUserActivation(
LocalFrame* frame,
bool checkIfMainThread,
UserActivationUpdateSource update_source) {
if (RuntimeEnabledFeatures::UserActivationV2Enabled()) {
return frame ? frame->ConsumeTransientUserActivation(update_source) : false;
}
return checkIfMainThread
? UserGestureIndicator::ConsumeUserGestureThreadSafe()
: UserGestureIndicator::ConsumeUserGesture();
}
bool Frame::IsFeatureEnabled(mojom::FeaturePolicyFeature feature,
ReportOptions report_on_failure) const {
FeaturePolicy* feature_policy = GetSecurityContext()->GetFeaturePolicy();
// The policy should always be initialized before checking it to ensure we
// properly inherit the parent policy.
DCHECK(feature_policy);
if (feature_policy->IsFeatureEnabled(feature))
return true;
if (report_on_failure == ReportOptions::kReportOnFailure)
ReportFeaturePolicyViolation(feature);
return false;
}
void Frame::SetOwner(FrameOwner* owner) {
owner_ = owner;
UpdateInertIfPossible();
UpdateInheritedEffectiveTouchActionIfPossible();
}
void Frame::UpdateInertIfPossible() {
if (owner_ && owner_->IsLocal()) {
ToHTMLFrameOwnerElement(owner_)->UpdateDistributionForFlatTreeTraversal();
if (ToHTMLFrameOwnerElement(owner_)->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),
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