1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
// 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 CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_TRANSITIONS_NAVIGATION_ENTRY_SCREENSHOT_CACHE_H_
#define CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_TRANSITIONS_NAVIGATION_ENTRY_SCREENSHOT_CACHE_H_
#include "base/containers/flat_set.h"
#include "base/functional/callback_forward.h"
#include "base/memory/safe_ref.h"
#include "content/browser/renderer_host/navigation_controller_impl.h"
#include "content/browser/renderer_host/navigation_transitions/navigation_entry_screenshot_manager.h"
#include "content/common/content_export.h"
namespace content {
class NavigationEntry;
class NavigationEntryScreenshot;
class NavigationEntryScreenshotManager;
// This interface limits the access of the `NavigationEntryScreenshotManager` to
// the `NavigationEntryScreenshotCache`: we do not want the manager to
// accidentally perform any "Set" or "Take" operations on the cache. This is
// because the manager is owned by the `BrowserContext` who has access across
// the tabs, and we do not want any tab specific pixel data leaked across tabs.
class NavigationEntryScreenshotCacheEvictor {
public:
virtual ~NavigationEntryScreenshotCacheEvictor() = default;
// Starting from the most distant entry of the last committed entry, erase the
// screenshots from entries until either the memory watermark is below the
// budget, or until no screenshots are tracked in this cache (this cache is
// empty).
virtual void EvictScreenshotsUntilUnderBudgetOrEmpty() = 0;
// Deletes all the tracked screenshots in this cache, and notifies the global
// manager to stop tracking this cache.
enum class PurgeReason { kMemoryPressure, kInvisible };
virtual void Purge(PurgeReason reason) = 0;
virtual bool IsEmpty() const = 0;
// Returns the time when this cache's tab was last visible or null if it is
// currently visible.
virtual std::optional<base::TimeTicks> GetLastVisibleTime() const = 0;
};
// `NavigationEntryScreenshotCache` tracks `NavigationEntryScreenshot`s per
// `FrameTree`. It is owned by the `NavigationController` of the primary
// `FrameTree` of a `WebContents`.
class CONTENT_EXPORT NavigationEntryScreenshotCache
: public NavigationEntryScreenshotCacheEvictor {
public:
using CompressedCallback = base::OnceCallback<void(int nav_entry_index)>;
static void SetCompressedCallbackForTesting(CompressedCallback callback);
explicit NavigationEntryScreenshotCache(
base::SafeRef<NavigationEntryScreenshotManager> manager,
NavigationControllerImpl* nav_controller);
NavigationEntryScreenshotCache(const NavigationEntryScreenshotCache&) =
delete;
NavigationEntryScreenshotCache& operator=(
const NavigationEntryScreenshotCache&) = delete;
~NavigationEntryScreenshotCache() override;
// Used to assign a `NavigationEntryScreenshot` to a `NavigationEntry`, which
// will own it. Also tracks the screenshot within this cache and notifies the
// `NavigationEntryScreenshotManager` of size changes in case eviction is
// needed.
void SetScreenshot(base::WeakPtr<NavigationRequest> navigation_request,
std::unique_ptr<NavigationEntryScreenshot> screenshot,
bool is_copied_from_embedder);
// Removes the `NavigationEntryScreenshot` from `NavigationEntry` and
// transfers ownership to the caller, updating the relevant tracking in the
// `NavigationEntryScreenshotManager`. The transfer of ownership is necessary
// so that eviction does not occur while a screenshot is in use for an
// animation. The caller is responsible for making sure `navigation_entry`
// has a screenshot.
std::unique_ptr<NavigationEntryScreenshot> RemoveScreenshot(
NavigationEntry* navigation_entry);
// Called by the `NavigationScreenshot` when the hosting navigation entry is
// deleted.
void OnNavigationEntryGone(NavigationTransitionData::UniqueId screenshot_id);
// Called by `NavigationScreenshot` when the cached screenshot has been
// compressed.
void OnScreenshotCompressed(NavigationTransitionData::UniqueId screenshot_id,
size_t new_size);
// Called when a navigation request has finished.
void OnNavigationFinished(const NavigationRequest& navigation_request);
// Called when the visibility of the cache changes.
void SetVisible(bool visible);
// `NavigationEntryScreenshotCacheEvictor`:
//
// The cost of `EvictScreenshotsUntilUnderBudgetOrEmpty` and
// `PurgeForMemoryPressure` is linear with respect to the number of navigation
// entries in the primary `NavigationController`. This is because for each
// navigation entry's ID this cache tracks, we need to query
// `NavigationController` using
// `NavigationControllerImpl::GetEntryWithUniqueID`, which performs a linear
// scan on all the navigation entries.
void EvictScreenshotsUntilUnderBudgetOrEmpty() override;
void Purge(PurgeReason reason) override;
bool IsEmpty() const override;
std::optional<base::TimeTicks> GetLastVisibleTime() const override;
private:
void SetScreenshotInternal(
std::unique_ptr<NavigationEntryScreenshot> screenshot,
bool is_copied_from_embedder);
// Helper function to differentiate between purge because of memory pressure
// and purge called by the destructor.
void PurgeInternal(std::optional<PurgeReason> reason);
// Tracks the unique IDs of the navigation entries, for which we have captured
// screenshots, and the screenshot size in bytes.
base::flat_map<NavigationTransitionData::UniqueId, size_t>
cached_screenshots_;
// Tracks the set of screenshots for ongoing navigations. These screenshots
// are either added to `cached_screenshots_` or discarded when the navigation
// finishes.
struct PendingScreenshot {
PendingScreenshot();
PendingScreenshot(std::unique_ptr<NavigationEntryScreenshot> screenshot,
bool is_copied_from_embedder);
~PendingScreenshot();
PendingScreenshot(PendingScreenshot&& other);
PendingScreenshot& operator=(PendingScreenshot&& other);
std::unique_ptr<NavigationEntryScreenshot> screenshot;
bool is_copied_from_embedder;
};
base::flat_map<int64_t, PendingScreenshot> pending_screenshots_;
// The per-BrowserContext manager that manages the eviction. Guaranteed to
// outlive `this`.
base::SafeRef<NavigationEntryScreenshotManager> manager_;
// The `NavigationController` that owns `this`. Guaranteed to outlive `this`.
// We need the controller for cache eviction to query all the
// `NavigationEntry`. See the impl for `EvictScreenshotsUntilInBudgetOrEmpty`.
const raw_ptr<NavigationControllerImpl> nav_controller_;
// The last time this cache was visible or null if its currently visible.
std::optional<base::TimeTicks> last_visible_timestamp_;
};
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_NAVIGATION_TRANSITIONS_NAVIGATION_ENTRY_SCREENSHOT_CACHE_H_
|