blob: c3edcb3b1f4e8e0a2303bb1ed5ece66771507e0b [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 "core/frame/Frame.h"
#include <memory>
#include "bindings/core/v8/WindowProxyManager.h"
#include "core/dom/DocumentType.h"
#include "core/dom/UserGestureIndicator.h"
#include "core/dom/events/Event.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/frame/Settings.h"
#include "core/frame/UseCounter.h"
#include "core/html/HTMLFrameElementBase.h"
#include "core/input/EventHandler.h"
#include "core/layout/LayoutEmbeddedContent.h"
#include "core/loader/EmptyClients.h"
#include "core/loader/NavigationScheduler.h"
#include "core/page/FocusController.h"
#include "core/page/Page.h"
#include "core/probe/CoreProbes.h"
#include "platform/InstanceCounters.h"
#include "platform/feature_policy/FeaturePolicy.h"
#include "platform/loader/fetch/ResourceError.h"
#include "platform/wtf/Assertions.h"
#include "public/web/WebFrameClient.h"
#include "public/web/WebRemoteFrameClient.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_);
// 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;
// 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_) {
// Ocassionally, provisional frames need to be detached, but it shouldn't
// affect the frame tree structure. Make sure the frame owner's content
// frame actually refers to this frame before clearing it.
// TODO(dcheng): https://crbug.com/578349 tracks the cleanup for this once
// it's no longer needed.
if (owner_->ContentFrame() == this)
owner_->ClearContentFrame();
owner_ = nullptr;
}
}
Page* Frame::GetPage() const {
return page_;
}
bool Frame::IsMainFrame() const {
return !Tree().Parent();
}
bool Frame::IsLocalRoot() const {
if (IsRemoteFrame())
return false;
if (!Tree().Parent())
return true;
return Tree().Parent()->IsRemoteFrame();
}
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();
}
// TODO(mustaq): Should be merged with NotifyUserActivation() below but
// not sure why this one doesn't update frame clients. Could be related to
// crbug.com/775930 .
void Frame::UpdateUserActivationInFrameTree() {
user_activation_state_.Activate();
if (Frame* parent = Tree().Parent())
parent->UpdateUserActivationInFrameTree();
}
void Frame::NotifyUserActivation() {
bool had_gesture = HasBeenActivated();
if (RuntimeEnabledFeatures::UserActivationV2Enabled() || !had_gesture)
UpdateUserActivationInFrameTree();
if (IsLocalFrame())
ToLocalFrame(this)->Client()->SetHasReceivedUserGesture(had_gesture);
}
bool Frame::ConsumeTransientUserActivation() {
for (Frame* parent = Tree().Parent(); parent;
parent = parent->Tree().Parent()) {
parent->user_activation_state_.ConsumeIfActive();
}
for (Frame* child = Tree().FirstChild(); child;
child = child->Tree().TraverseNext(this)) {
child->user_activation_state_.ConsumeIfActive();
}
return user_activation_state_.ConsumeIfActive();
}
// static
std::unique_ptr<UserGestureIndicator> Frame::NotifyUserActivation(
Frame* frame,
UserGestureToken::Status status) {
if (frame)
frame->NotifyUserActivation();
return std::make_unique<UserGestureIndicator>(status);
}
// static
bool Frame::HasTransientUserActivation(Frame* frame, bool checkIfMainThread) {
if (RuntimeEnabledFeatures::UserActivationV2Enabled()) {
return frame ? frame->HasTransientUserActivation() : false;
}
return checkIfMainThread
? UserGestureIndicator::ProcessingUserGestureThreadSafe()
: UserGestureIndicator::ProcessingUserGesture();
}
// static
bool Frame::ConsumeTransientUserActivation(Frame* frame,
bool checkIfMainThread) {
if (RuntimeEnabledFeatures::UserActivationV2Enabled()) {
return frame ? frame->ConsumeTransientUserActivation() : false;
}
return checkIfMainThread
? UserGestureIndicator::ConsumeUserGestureThreadSafe()
: UserGestureIndicator::ConsumeUserGesture();
}
bool Frame::IsFeatureEnabled(FeaturePolicyFeature feature) 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);
// Otherwise, check policy.
return feature_policy->IsFeatureEnabled(feature);
}
void Frame::SetOwner(FrameOwner* owner) {
owner_ = owner;
UpdateInertIfPossible();
}
void Frame::UpdateInertIfPossible() {
if (owner_ && owner_->IsLocal()) {
ToHTMLFrameOwnerElement(owner_)->UpdateDistribution();
if (ToHTMLFrameOwnerElement(owner_)->IsInert())
SetIsInert(true);
}
}
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()) {
InstanceCounters::IncrementCounter(InstanceCounters::kFrameCounter);
if (owner_)
owner_->SetContentFrame(*this);
else
page_->SetMainFrame(this);
}
STATIC_ASSERT_ENUM(FrameDetachType::kRemove,
WebFrameClient::DetachType::kRemove);
STATIC_ASSERT_ENUM(FrameDetachType::kSwap, WebFrameClient::DetachType::kSwap);
STATIC_ASSERT_ENUM(FrameDetachType::kRemove,
WebRemoteFrameClient::DetachType::kRemove);
STATIC_ASSERT_ENUM(FrameDetachType::kSwap,
WebRemoteFrameClient::DetachType::kSwap);
} // namespace blink