blob: cede1f6fdc214e7a23e2c0824e00bb9d48176ff0 [file] [log] [blame]
// Copyright 2023 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_PDF_TEST_PDF_VIEWER_STREAM_MANAGER_H_
#define CHROME_BROWSER_PDF_TEST_PDF_VIEWER_STREAM_MANAGER_H_
#include "base/containers/flat_set.h"
#include "base/functional/callback_forward.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/pdf/pdf_viewer_stream_manager.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/web_contents_user_data.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
class NavigationHandle;
class RenderFrameHost;
class WebContents;
} // namespace content
namespace pdf {
class TestPdfViewerStreamManager : public PdfViewerStreamManager {
public:
// Prefer using this over the constructor so that this instance is used for
// PDF loads.
static TestPdfViewerStreamManager* CreateForWebContents(
content::WebContents* web_contents);
explicit TestPdfViewerStreamManager(content::WebContents* contents);
TestPdfViewerStreamManager(const TestPdfViewerStreamManager&) = delete;
TestPdfViewerStreamManager& operator=(const TestPdfViewerStreamManager&) =
delete;
~TestPdfViewerStreamManager() override;
// WebContentsObserver overrides.
void DidFinishNavigation(
content::NavigationHandle* navigation_handle) override;
// PdfViewerStreamManager overrides.
void NavigateToPdfExtensionUrl(
content::FrameTreeNodeId extension_host_frame_tree_node_id,
StreamInfo* stream_info,
content::SiteInstance* site_instance,
content::GlobalRenderFrameHostId global_id) override;
// Delays the PDF extension from navigating to the PDF extension URL. There
// are two navigations for the PDF extension frame: a navigation to
// about:blank and a navigation to the PDF extension URL. This delays the
// latter navigation.
void DelayNextPdfExtensionNavigation();
// Waits until the PDF extension frame finishes its first navigation to
// about:blank, but not the navigation to the PDF extension URL. The test will
// hang if `embedder_host` is not navigating to a PDF.
void WaitUntilPdfExtensionNavigationStarted(
content::RenderFrameHost* embedder_host);
// Resumes the PDF extension frame navigation to the PDF extension URL. Must
// be used in conjunction with `DelayNextPdfExtensionNavigation()` and
// `WaitUntilPdfExtensionNavigationStarted()`.
void ResumePdfExtensionNavigation(content::RenderFrameHost* embedder_host);
// Waits until the PDF has finished loading. Returns true if the PDF loads
// successfully, false otherwise. The test will hang if `embedder_host` is not
// a PDF, or if the PDF frames never finish navigating.
[[nodiscard]] testing::AssertionResult WaitUntilPdfLoaded(
content::RenderFrameHost* embedder_host);
// Same as `WaitUntilPdfLoaded()`, but allows additional subframes under the
// PDF embedder host. There are some special cases where the PDF embedder may
// have additional subframes. See crbug.com/40671023.
[[nodiscard]] testing::AssertionResult WaitUntilPdfLoadedAllowMultipleFrames(
content::RenderFrameHost* embedder_host);
// Same as `WaitUntilPdfLoaded()`, but the first child of the primary main
// frame should be the embedder. This is a common case where an HTML page only
// embeds a single PDF.
[[nodiscard]] testing::AssertionResult WaitUntilPdfLoadedInFirstChild();
private:
// Gathers all the necessary navigation params and navigates to the PDF
// extension URL. `global_id` should be the ID for the intermediate
// about:blank host.
void GetParamsAndNavigateToPdfExtensionUrl(
content::GlobalRenderFrameHostId global_id);
// Waits for all PDF frames in a single PDF load to finish navigating.
void WaitUntilPdfNavigationFinished(content::RenderFrameHost* embedder_host);
// Indicates whether to delay the next PDF extension navigation to the PDF
// extension URL.
bool delay_next_pdf_extension_load_ = false;
// Used only if `WaitUntilPdfExtensionNavigationStarted()` was used. Resumes
// the PDF load.
base::OnceClosure on_first_pdf_extension_navigation_finished_;
// Used only if `ResumePdfExtensionNavigation()` was used. Resumes the PDF
// extension load.
base::OnceClosure on_resume_pdf_extension_navigation_;
// Used once the PDF finished loading. Resumes the test.
base::OnceClosure on_pdf_loaded_;
// Needed to avoid use-after-free in callbacks.
base::WeakPtrFactory<TestPdfViewerStreamManager> weak_factory_{this};
};
// While a `TestPdfViewerStreamManagerFactory` instance exists, it will
// automatically set itself as the global factory override. All PDF navigations
// will automatically use a `TestPdfViewerStreamManager` instance created from
// this factory.
class TestPdfViewerStreamManagerFactory
: public PdfViewerStreamManager::Factory {
public:
TestPdfViewerStreamManagerFactory();
TestPdfViewerStreamManagerFactory(const TestPdfViewerStreamManagerFactory&) =
delete;
TestPdfViewerStreamManagerFactory& operator=(
const TestPdfViewerStreamManagerFactory&) = delete;
~TestPdfViewerStreamManagerFactory() override;
// Return value is always non-nullptr. A `TestPdfViewerStreamManager` for
// `contents` must have been created by `this`, or else a crash occurs.
TestPdfViewerStreamManager* GetTestPdfViewerStreamManager(
content::WebContents* contents);
// PdfViewerStreamManager::Factory overrides.
// Use `CreatePdfViewerStreamManager()` directly to create a test PDF stream
// manager if the test does not block during navigation. If the test does
// block during navigation, then the test PDF stream manager instance should
// already be created automatically on navigation.
void CreatePdfViewerStreamManager(content::WebContents* contents) override;
private:
// Tracks managers this factory has created. It's safe to track raw pointers,
// since the pointers are only for comparison and aren't dereferenced.
base::flat_set<raw_ptr<PdfViewerStreamManager, CtnExperimental>> managers_;
};
} // namespace pdf
#endif // CHROME_BROWSER_PDF_TEST_PDF_VIEWER_STREAM_MANAGER_H_