| // 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_ |