blob: 74039800b92ea180c81a351ebcfe335ef738df9b [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_PREDICTORS_LOADING_PREDICTOR_TAB_HELPER_H_
#define CHROME_BROWSER_PREDICTORS_LOADING_PREDICTOR_TAB_HELPER_H_
#include <optional>
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_refptr.h"
#include "base/types/id_type.h"
#include "chrome/browser/predictors/resource_prefetch_predictor.h"
#include "content/public/browser/document_user_data.h"
#include "content/public/browser/navigation_handle_user_data.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
namespace content {
class NavigationHandle;
} // namespace content
namespace optimization_guide {
class OptimizationGuideDecider;
enum class OptimizationGuideDecision;
class OptimizationMetadata;
} // namespace optimization_guide
namespace predictors {
using NavigationId = base::IdType64<content::NavigationHandle>;
class LoadingPredictor;
// Observes various page load events from the navigation start to onload
// completed and notifies the LoadingPredictor associated with the current
// profile.
//
// All methods must be called from the UI thread.
class LoadingPredictorTabHelper
: public content::WebContentsObserver,
public content::WebContentsUserData<LoadingPredictorTabHelper> {
public:
LoadingPredictorTabHelper(const LoadingPredictorTabHelper&) = delete;
LoadingPredictorTabHelper& operator=(const LoadingPredictorTabHelper&) =
delete;
~LoadingPredictorTabHelper() override;
// content::WebContentsObserver implementation
void DidStartNavigation(
content::NavigationHandle* navigation_handle) override;
void DidRedirectNavigation(
content::NavigationHandle* navigation_handle) override;
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
void ResourceLoadComplete(
content::RenderFrameHost* render_frame_host,
const content::GlobalRequestID& request_id,
const blink::mojom::ResourceLoadInfo& resource_load_info) override;
void DidLoadResourceFromMemoryCache(
content::RenderFrameHost* render_frame_host,
const GURL& url,
const std::string& mime_type,
network::mojom::RequestDestination request_destination) override;
void DocumentOnLoadCompletedInPrimaryMainFrame() override;
void SetLoadingPredictorForTesting(
base::WeakPtr<LoadingPredictor> predictor) {
predictor_ = predictor;
}
bool IsPrepareForPageloadCalledForTesting() const {
return is_prepare_for_pageload_called_for_testing_;
}
private:
// The PageData stores the state needed for each page. It is primarily owned
// by the DocumentPageDataHolder or NavigationPageDataHolder, depending on
// whether the navigation has committed or not. The PageData is RefCounted
// because it is passed to a callback that might outlive the holders, and the
// holders still need to access the PageData after passing it to the callback.
class DocumentPageDataHolder;
class NavigationPageDataHolder;
class PageData : public base::RefCounted<PageData> {
public:
PageData();
static PageData* GetForNavigationHandle(
content::NavigationHandle& navigation_handle);
static PageData& CreateForNavigationHandle(
content::NavigationHandle& navigation_handle);
static PageData* GetForDocument(
content::RenderFrameHost& render_frame_host);
static void TransferFromNavigationHandleToDocument(
content::NavigationHandle& navigation_handle,
content::RenderFrameHost& render_frame_host);
// Uniquely identifies this navigation.
NavigationId navigation_id_;
// True if the navigation has committed.
bool has_committed_ = false;
bool has_local_preconnect_predictions_for_current_navigation_ = false;
// The optimization guide prediction for the current navigation.
std::optional<OptimizationGuidePrediction>
last_optimization_guide_prediction_;
// Stores weak ptrs to the document and navigation page data holders, in
// order to determine the current state of the navigation.
base::WeakPtr<DocumentPageDataHolder> document_page_data_holder_;
base::WeakPtr<NavigationPageDataHolder> navigation_page_data_holder_;
base::WeakPtr<LoadingPredictor> predictor_;
private:
friend class base::RefCounted<PageData>;
~PageData();
};
// The DocumentPageDataHolder is used to store the state after the navigation
// has committed.
class DocumentPageDataHolder
: public content::DocumentUserData<DocumentPageDataHolder> {
public:
explicit DocumentPageDataHolder(
content::RenderFrameHost* render_frame_host);
~DocumentPageDataHolder() override;
DOCUMENT_USER_DATA_KEY_DECL();
scoped_refptr<PageData> page_data_;
base::WeakPtrFactory<DocumentPageDataHolder> weak_factory_{this};
};
// The NavigationPageDataHolder is used to store the PageData while a
// navigation is still in progress, and has not yet committed.
class NavigationPageDataHolder
: public content::NavigationHandleUserData<NavigationPageDataHolder> {
public:
explicit NavigationPageDataHolder(
content::NavigationHandle& navigation_handle);
~NavigationPageDataHolder() override;
NAVIGATION_HANDLE_USER_DATA_KEY_DECL();
scoped_refptr<PageData> page_data_;
base::SafeRef<content::NavigationHandle> navigation_handle_;
base::WeakPtrFactory<NavigationPageDataHolder> weak_factory_{this};
};
explicit LoadingPredictorTabHelper(content::WebContents* web_contents);
friend class content::WebContentsUserData<LoadingPredictorTabHelper>;
// Callback invoked when |optimization_guide_decider_| has the information
// required to decide if it has remote predictions for the page load.
void OnOptimizationGuideDecision(
scoped_refptr<PageData> page_helper,
const std::optional<url::Origin>& initiator_origin,
const GURL& main_frame_url,
bool should_add_preconnects_to_prediction,
optimization_guide::OptimizationGuideDecision decision,
const optimization_guide::OptimizationMetadata& metadata);
// Calls LoadingPredictor::PrepareForPageLoad doing prefetch and/or
// preconnect. This is called asynchronously after main resource fetching if
// kLCPPPrefetchSubresourceAsync is enabled.
void PrepareForPageLoad(scoped_refptr<PageData> page_data,
const std::optional<url::Origin> initiator_origin,
const GURL main_frame_url,
bool should_consult_optimization_guide);
bool is_prepare_for_pageload_called_for_testing_ = false;
// Owned by profile.
base::WeakPtr<LoadingPredictor> predictor_;
// The optimization guide decider to consult for remote predictions.
raw_ptr<optimization_guide::OptimizationGuideDecider>
optimization_guide_decider_ = nullptr;
// Used to get a weak pointer to |this|.
base::WeakPtrFactory<LoadingPredictorTabHelper> weak_ptr_factory_{this};
WEB_CONTENTS_USER_DATA_KEY_DECL();
};
} // namespace predictors
#endif // CHROME_BROWSER_PREDICTORS_LOADING_PREDICTOR_TAB_HELPER_H_