Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 1 | // Copyright 2022 The Chromium Authors |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 5 | #include "content/browser/preloading/prerenderer_impl.h" |
| 6 | |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 7 | #include <algorithm> |
Andrew Rayskiy | f6599036 | 2024-02-27 18:43:24 | [diff] [blame] | 8 | #include <vector> |
| 9 | |
Tom Sepez | 3e42510 | 2025-07-23 12:16:20 | [diff] [blame] | 10 | #include "base/compiler_specific.h" |
Liviu Tinta | 44e732aa | 2024-05-28 15:52:36 | [diff] [blame] | 11 | #include "base/feature_list.h" |
Lei Zhang | ab09dd84 | 2025-05-17 08:06:48 | [diff] [blame] | 12 | #include "base/strings/stringprintf.h" |
Liviu Tinta | 44e732aa | 2024-05-28 15:52:36 | [diff] [blame] | 13 | #include "content/browser/preloading/prefetch/no_vary_search_helper.h" |
kenoss | 9d57ee7b | 2024-06-03 01:36:43 | [diff] [blame] | 14 | #include "content/browser/preloading/prefetch/prefetch_document_manager.h" |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 15 | #include "content/browser/preloading/preloading.h" |
Adithya Srinivasan | 38e0c40 | 2023-07-19 16:12:58 | [diff] [blame] | 16 | #include "content/browser/preloading/preloading_attempt_impl.h" |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 17 | #include "content/browser/preloading/preloading_data_impl.h" |
Kouhei Ueno | 6329375 | 2023-11-14 07:41:50 | [diff] [blame] | 18 | #include "content/browser/preloading/preloading_trigger_type_impl.h" |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 19 | #include "content/browser/preloading/prerender/prerender_attributes.h" |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 20 | #include "content/browser/preloading/prerender/prerender_features.h" |
Samar Chehade-Lepleux | ce1baf2 | 2023-05-16 09:50:09 | [diff] [blame] | 21 | #include "content/browser/preloading/prerender/prerender_final_status.h" |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 22 | #include "content/browser/preloading/prerender/prerender_host_registry.h" |
| 23 | #include "content/browser/preloading/prerender/prerender_metrics.h" |
| 24 | #include "content/browser/preloading/prerender/prerender_navigation_utils.h" |
| 25 | #include "content/browser/preloading/prerender/prerender_new_tab_handle.h" |
Takashi Nakayama | 9eb7988f | 2025-06-25 06:14:00 | [diff] [blame] | 26 | #include "content/browser/preloading/speculation_rules/speculation_rules_util.h" |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 27 | #include "content/browser/renderer_host/render_frame_host_delegate.h" |
Domenic Denicola | ff44ecf | 2023-11-10 05:20:41 | [diff] [blame] | 28 | #include "content/public/browser/preloading_trigger_type.h" |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 29 | #include "content/public/browser/web_contents.h" |
Liviu Tinta | 44e732aa | 2024-05-28 15:52:36 | [diff] [blame] | 30 | #include "third_party/blink/public/common/features.h" |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 31 | |
| 32 | namespace content { |
| 33 | |
Lingqi Chi | 844e05d4 | 2025-07-23 02:50:50 | [diff] [blame] | 34 | namespace { |
| 35 | PreloadingType ConvertSpeculationActionToPreloadingType( |
| 36 | blink::mojom::SpeculationAction action) { |
| 37 | switch (action) { |
| 38 | case blink::mojom::SpeculationAction::kPrerender: |
| 39 | return PreloadingType::kPrerender; |
| 40 | case blink::mojom::SpeculationAction::kPrerenderUntilScript: |
| 41 | return PreloadingType::kPrerenderUntilScript; |
| 42 | case blink::mojom::SpeculationAction::kPrefetch: |
| 43 | case blink::mojom::SpeculationAction::kPrefetchWithSubresources: |
| 44 | NOTREACHED(); |
| 45 | } |
| 46 | } |
| 47 | |
Lingqi Chi | bc88ab5 | 2025-07-24 00:54:14 | [diff] [blame] | 48 | bool ShouldPauseJavaScriptExecution(blink::mojom::SpeculationAction action) { |
| 49 | switch (action) { |
| 50 | case blink::mojom::SpeculationAction::kPrerender: |
| 51 | return false; |
| 52 | case blink::mojom::SpeculationAction::kPrerenderUntilScript: |
| 53 | return true; |
| 54 | case blink::mojom::SpeculationAction::kPrefetch: |
| 55 | case blink::mojom::SpeculationAction::kPrefetchWithSubresources: |
| 56 | NOTREACHED(); |
| 57 | } |
| 58 | } |
| 59 | |
Lingqi Chi | 844e05d4 | 2025-07-23 02:50:50 | [diff] [blame] | 60 | } // namespace |
| 61 | |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 62 | struct PrerendererImpl::PrerenderInfo { |
Domenic Denicola | ff44ecf | 2023-11-10 05:20:41 | [diff] [blame] | 63 | blink::mojom::SpeculationInjectionType injection_type; |
Taiyo Mizuhashi | 5470a52 | 2023-08-21 05:05:56 | [diff] [blame] | 64 | blink::mojom::SpeculationEagerness eagerness; |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 65 | bool is_target_blank; |
Avi Drissman | dcc8e68 | 2024-09-04 14:14:48 | [diff] [blame] | 66 | FrameTreeNodeId prerender_host_id; |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 67 | GURL url; |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 68 | |
| 69 | PrerenderInfo() = default; |
| 70 | explicit PrerenderInfo( |
| 71 | const blink::mojom::SpeculationCandidatePtr& candidate); |
| 72 | |
| 73 | static bool PrerenderInfoComparator(const PrerenderInfo& p1, |
| 74 | const PrerenderInfo& p2); |
| 75 | |
| 76 | bool operator<(const PrerenderInfo& p) const { |
| 77 | return PrerenderInfoComparator(*this, p); |
| 78 | } |
| 79 | |
| 80 | bool operator==(const PrerenderInfo& p) const { |
| 81 | return !PrerenderInfoComparator(*this, p) && |
| 82 | !PrerenderInfoComparator(p, *this); |
| 83 | } |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 84 | }; |
| 85 | |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 86 | bool PrerendererImpl::PrerenderInfo::PrerenderInfoComparator( |
| 87 | const PrerenderInfo& p1, |
| 88 | const PrerenderInfo& p2) { |
| 89 | if (p1.url != p2.url) { |
| 90 | return p1.url < p2.url; |
| 91 | } |
| 92 | |
| 93 | return p1.is_target_blank < p2.is_target_blank; |
| 94 | } |
| 95 | |
| 96 | // `prerender_host_id` is not provided by `SpeculationCandidatePtr`, so |
| 97 | // FrameTreeNodeId() is assigned instead. The value should be updated once it is |
| 98 | // available. |
| 99 | PrerendererImpl::PrerenderInfo::PrerenderInfo( |
| 100 | const blink::mojom::SpeculationCandidatePtr& candidate) |
| 101 | : injection_type(candidate->injection_type), |
| 102 | eagerness(candidate->eagerness), |
| 103 | is_target_blank(candidate->target_browsing_context_name_hint == |
| 104 | blink::mojom::SpeculationTargetHint::kBlank), |
| 105 | url(candidate->url) {} |
| 106 | |
Johann | a9fe85f | 2023-01-17 10:15:43 | [diff] [blame] | 107 | PrerendererImpl::PrerendererImpl(RenderFrameHost& render_frame_host) |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 108 | : WebContentsObserver(WebContents::FromRenderFrameHost(&render_frame_host)), |
| 109 | render_frame_host_(render_frame_host) { |
Johann | a9fe85f | 2023-01-17 10:15:43 | [diff] [blame] | 110 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 111 | auto& rfhi = static_cast<RenderFrameHostImpl&>(render_frame_host); |
| 112 | registry_ = rfhi.delegate()->GetPrerenderHostRegistry()->GetWeakPtr(); |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 113 | if (registry_) { |
| 114 | observation_.Observe(registry_.get()); |
| 115 | } |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 116 | ResetReceivedPrerendersCountForMetrics(); |
Yoichi Osato | fed56ff8 | 2024-02-29 01:13:45 | [diff] [blame] | 117 | if (base::FeatureList::IsEnabled( |
| 118 | blink::features::kLCPTimingPredictorPrerender2)) { |
| 119 | blocked_ = true; |
| 120 | } |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 121 | } |
lingqi | 2abab047 | 2023-04-19 05:56:33 | [diff] [blame] | 122 | |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 123 | PrerendererImpl::~PrerendererImpl() { |
Johann | a9fe85f | 2023-01-17 10:15:43 | [diff] [blame] | 124 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Samar Chehade-Lepleux | ce1baf2 | 2023-05-16 09:50:09 | [diff] [blame] | 125 | CancelStartedPrerenders(); |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 126 | RecordReceivedPrerendersCountToMetrics(); |
| 127 | ResetReceivedPrerendersCountForMetrics(); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 128 | } |
| 129 | |
| 130 | void PrerendererImpl::PrimaryPageChanged(Page& page) { |
| 131 | // Listen to the change of the primary page. Since only the primary page can |
| 132 | // trigger speculationrules, the change of the primary page indicates that the |
| 133 | // trigger associated with this host is destroyed, so the browser should |
| 134 | // cancel the prerenders that are initiated by it. |
| 135 | // We cannot do it in the destructor only, because DocumentService can be |
| 136 | // deleted asynchronously, but we want to make sure to cancel prerendering |
| 137 | // before the next primary page swaps in so that the next page can trigger a |
| 138 | // new prerender without hitting the max number of running prerenders. |
Johann | a9fe85f | 2023-01-17 10:15:43 | [diff] [blame] | 139 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Samar Chehade-Lepleux | ce1baf2 | 2023-05-16 09:50:09 | [diff] [blame] | 140 | CancelStartedPrerenders(); |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 141 | RecordReceivedPrerendersCountToMetrics(); |
| 142 | ResetReceivedPrerendersCountForMetrics(); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | // TODO(isaboori) Part of the logic in |ProcessCandidatesForPrerender| method is |
| 146 | // about making preloading decisions and could be moved to PreloadingDecider |
| 147 | // class. |
| 148 | void PrerendererImpl::ProcessCandidatesForPrerender( |
| 149 | const std::vector<blink::mojom::SpeculationCandidatePtr>& candidates) { |
| 150 | if (!registry_) |
| 151 | return; |
| 152 | |
| 153 | // Extract only the candidates which apply to prerender, and sort them by URL |
| 154 | // so we can efficiently compare them to `started_prerenders_`. |
Taiyo Mizuhashi | f277ece | 2024-01-12 17:29:28 | [diff] [blame] | 155 | std::vector<std::pair<size_t, blink::mojom::SpeculationCandidatePtr>> |
| 156 | prerender_candidates; |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 157 | for (const auto& candidate : candidates) { |
Lingqi Chi | 844e05d4 | 2025-07-23 02:50:50 | [diff] [blame] | 158 | if (candidate->action == blink::mojom::SpeculationAction::kPrerender || |
| 159 | candidate->action == |
| 160 | blink::mojom::SpeculationAction::kPrerenderUntilScript) { |
Taiyo Mizuhashi | f277ece | 2024-01-12 17:29:28 | [diff] [blame] | 161 | prerender_candidates.emplace_back(prerender_candidates.size(), |
| 162 | candidate.Clone()); |
| 163 | } |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 164 | } |
Taiyo Mizuhashi | f277ece | 2024-01-12 17:29:28 | [diff] [blame] | 165 | |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 166 | std::ranges::stable_sort( |
| 167 | prerender_candidates, std::less<>(), |
| 168 | [](const auto& p) { return PrerenderInfo(p.second); }); |
Taiyo Mizuhashi | f277ece | 2024-01-12 17:29:28 | [diff] [blame] | 169 | std::vector<std::pair<size_t, blink::mojom::SpeculationCandidatePtr>> |
| 170 | candidates_to_start; |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 171 | |
| 172 | // Collects the host ids corresponding to the URLs that are removed from the |
| 173 | // speculation rules. These hosts are cancelled later. |
Avi Drissman | dcc8e68 | 2024-09-04 14:14:48 | [diff] [blame] | 174 | std::vector<FrameTreeNodeId> removed_prerender_rules; |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 175 | |
| 176 | // Compare the sorted candidate and started prerender lists to one another. |
| 177 | // Since they are sorted, we process the lexicographically earlier of the two |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 178 | // PrerenderInfos pointed at by the iterators, and compare the range of |
| 179 | // entries in each that match that PrerenderInfo. |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 180 | // |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 181 | // PrerenderInfos which are present in the prerender list but not the |
| 182 | // candidate list can no longer proceed and are cancelled. |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 183 | // |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 184 | // PrerenderInfos which are present in the candidate list but not the |
| 185 | // prerender list could be started and are gathered in `candidates_to_start`. |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 186 | auto candidate_it = prerender_candidates.begin(); |
| 187 | auto started_it = started_prerenders_.begin(); |
| 188 | while (candidate_it != prerender_candidates.end() || |
| 189 | started_it != started_prerenders_.end()) { |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 190 | // Select the lesser of the two PrerenderInfos to diff. |
| 191 | PrerenderInfo prerender_info; |
| 192 | if (started_it == started_prerenders_.end()) { |
| 193 | prerender_info = PrerenderInfo(candidate_it->second); |
| 194 | } else if (candidate_it == prerender_candidates.end()) { |
| 195 | prerender_info = *started_it; |
| 196 | } else { |
| 197 | prerender_info = |
| 198 | std::min(PrerenderInfo(candidate_it->second), *started_it); |
| 199 | } |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 200 | |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 201 | // Select the ranges from both that match the PrerenderInfo in question. |
Peter Kasting | 1557e5f | 2025-01-28 01:14:08 | [diff] [blame] | 202 | auto equal_prerender_end = std::ranges::find_if( |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 203 | started_it, started_prerenders_.end(), |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 204 | [&](const auto& started) { return started != prerender_info; }); |
Tom Sepez | 3e42510 | 2025-07-23 12:16:20 | [diff] [blame] | 205 | base::span<PrerenderInfo> UNSAFE_TODO( |
| 206 | matching_prerenders(started_it, equal_prerender_end)); |
Peter Kasting | 1557e5f | 2025-01-28 01:14:08 | [diff] [blame] | 207 | auto equal_candidate_end = std::ranges::find_if( |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 208 | candidate_it, prerender_candidates.end(), [&](const auto& candidate) { |
| 209 | return PrerenderInfo(candidate.second) != prerender_info; |
| 210 | }); |
Taiyo Mizuhashi | f277ece | 2024-01-12 17:29:28 | [diff] [blame] | 211 | base::span<std::pair<size_t, blink::mojom::SpeculationCandidatePtr>> |
Tom Sepez | 3e42510 | 2025-07-23 12:16:20 | [diff] [blame] | 212 | UNSAFE_TODO(matching_candidates(candidate_it, equal_candidate_end)); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 213 | |
| 214 | // Decide what started prerenders to cancel. |
| 215 | for (PrerenderInfo& prerender : matching_prerenders) { |
Avi Drissman | dcc8e68 | 2024-09-04 14:14:48 | [diff] [blame] | 216 | if (prerender.prerender_host_id.is_null()) { |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 217 | continue; |
Avi Drissman | dcc8e68 | 2024-09-04 14:14:48 | [diff] [blame] | 218 | } |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 219 | // TODO(jbroman): This doesn't currently care about other aspects, like |
| 220 | // the referrer. This doesn't presently matter, but in the future we might |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 221 | // want to cancel if there are candidates which match by PrerenderInfo but |
| 222 | // none of which permit this prerender. |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 223 | if (matching_candidates.empty()) { |
| 224 | removed_prerender_rules.push_back(prerender.prerender_host_id); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 225 | } |
| 226 | } |
| 227 | |
| 228 | // Decide what new candidates to start. |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 229 | // For now, start one candidate per target hint for a URL only if there are |
| 230 | // no matching prerenders. We could be cleverer in the future. |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 231 | if (matching_prerenders.empty()) { |
Peter Kasting | 1b56352f | 2024-11-17 20:47:33 | [diff] [blame] | 232 | CHECK(!matching_candidates.empty()); |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 233 | |
| 234 | std::set<PrerenderInfo> processed_prerender_info; |
| 235 | |
| 236 | for (auto& matching_candidate : matching_candidates) { |
| 237 | PrerenderInfo matching_candidate_prerender_info = |
| 238 | PrerenderInfo(matching_candidate.second); |
| 239 | if (processed_prerender_info |
| 240 | .insert(std::move(matching_candidate_prerender_info)) |
| 241 | .second) { |
| 242 | candidates_to_start.push_back(std::move(matching_candidate)); |
| 243 | } |
| 244 | } |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 245 | } |
| 246 | |
| 247 | // Advance the iterators past all matching entries. |
| 248 | candidate_it = equal_candidate_end; |
| 249 | started_it = equal_prerender_end; |
| 250 | } |
| 251 | |
kenoss | 087ae23 | 2024-12-10 05:06:04 | [diff] [blame] | 252 | std::vector<GURL> urls; |
| 253 | for (auto ftn_id : removed_prerender_rules) { |
| 254 | if (PrerenderHost* prerender_host = |
| 255 | registry_->FindNonReservedHostById(ftn_id)) { |
| 256 | urls.push_back(prerender_host->GetInitialUrl()); |
| 257 | } |
| 258 | } |
Avi Drissman | dcc8e68 | 2024-09-04 14:14:48 | [diff] [blame] | 259 | std::set<FrameTreeNodeId> canceled_prerender_rules_set = |
| 260 | registry_->CancelHosts( |
| 261 | removed_prerender_rules, |
| 262 | PrerenderCancellationReason( |
| 263 | PrerenderFinalStatus::kSpeculationRuleRemoved)); |
kenoss | 087ae23 | 2024-12-10 05:06:04 | [diff] [blame] | 264 | if (base::FeatureList::IsEnabled( |
| 265 | features::kPrerender2FallbackPrefetchSpecRules)) { |
| 266 | WebContents* web_contents = |
| 267 | WebContents::FromRenderFrameHost(&render_frame_host_.get()); |
| 268 | auto* prefetch_document_manager = |
| 269 | content::PrefetchDocumentManager::GetOrCreateForCurrentDocument( |
| 270 | web_contents->GetPrimaryMainFrame()); |
| 271 | for (const auto& url : urls) { |
| 272 | prefetch_document_manager->ResetPrefetchAheadOfPrerenderIfExist(url); |
| 273 | } |
| 274 | } |
Lingqi Chi | 47f6000 | 2022-12-13 05:29:08 | [diff] [blame] | 275 | |
Taiyo Mizuhashi | a4ac7d2 | 2024-08-13 23:53:31 | [diff] [blame] | 276 | // Canceled prerenders by kSpeculationRuleRemoved should have already been |
| 277 | // removed from `started_prerenders_` via `OnCancel`. |
Hiroki Nakagawa | 8821cd88 | 2024-08-01 08:19:46 | [diff] [blame] | 278 | CHECK(std::find_if(started_prerenders_.begin(), started_prerenders_.end(), |
| 279 | [&](const PrerenderInfo& x) { |
Taiyo Mizuhashi | a4ac7d2 | 2024-08-13 23:53:31 | [diff] [blame] | 280 | return base::Contains(canceled_prerender_rules_set, |
Hiroki Nakagawa | 8821cd88 | 2024-08-01 08:19:46 | [diff] [blame] | 281 | x.prerender_host_id); |
| 282 | }) == started_prerenders_.end()); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 283 | |
Taiyo Mizuhashi | f277ece | 2024-01-12 17:29:28 | [diff] [blame] | 284 | // Actually start the candidates in their original order once the diffing is |
| 285 | // done. |
Peter Kasting | 1557e5f | 2025-01-28 01:14:08 | [diff] [blame] | 286 | std::ranges::sort(candidates_to_start, std::less<>(), |
| 287 | [](const auto& p) { return p.first; }); |
Taiyo Mizuhashi | f277ece | 2024-01-12 17:29:28 | [diff] [blame] | 288 | for (const auto& [_, candidate] : candidates_to_start) { |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 289 | PreloadingTriggerType trigger_type = |
| 290 | PreloadingTriggerTypeFromSpeculationInjectionType( |
| 291 | candidate->injection_type); |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 292 | // Immediate candidates are enacted by the same predictor that creates them. |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 293 | PreloadingPredictor enacting_predictor = |
| 294 | GetPredictorForPreloadingTriggerType(trigger_type); |
Kevin McNee | 842eb0a | 2024-04-11 20:14:16 | [diff] [blame] | 295 | MaybePrerender(candidate, enacting_predictor, PreloadingConfidence{100}); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 296 | } |
| 297 | } |
| 298 | |
Yoichi Osato | fed56ff8 | 2024-02-29 01:13:45 | [diff] [blame] | 299 | void PrerendererImpl::OnLCPPredicted() { |
| 300 | blocked_ = false; |
Kevin McNee | 842eb0a | 2024-04-11 20:14:16 | [diff] [blame] | 301 | for (auto& [candidate, enacting_predictor, confidence] : |
| 302 | std::move(blocked_candidates_)) { |
| 303 | MaybePrerender(candidate, enacting_predictor, confidence); |
Yoichi Osato | fed56ff8 | 2024-02-29 01:13:45 | [diff] [blame] | 304 | } |
| 305 | } |
| 306 | |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 307 | bool PrerendererImpl::MaybePrerender( |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 308 | const blink::mojom::SpeculationCandidatePtr& candidate, |
Kevin McNee | 842eb0a | 2024-04-11 20:14:16 | [diff] [blame] | 309 | const PreloadingPredictor& enacting_predictor, |
| 310 | PreloadingConfidence confidence) { |
Lingqi Chi | 844e05d4 | 2025-07-23 02:50:50 | [diff] [blame] | 311 | // Check actions. Only Prerender and PrerenderUntilScript are allowed. |
| 312 | switch (candidate->action) { |
| 313 | case blink::mojom::SpeculationAction::kPrerender: |
| 314 | case blink::mojom::SpeculationAction::kPrerenderUntilScript: |
| 315 | break; |
| 316 | default: |
| 317 | NOTREACHED(); |
| 318 | } |
Hiroki Nakagawa | 3f1fa5a9 | 2024-08-16 15:44:12 | [diff] [blame] | 319 | |
| 320 | // Prerendering is not allowed in fenced frames. |
| 321 | if (render_frame_host_->IsNestedWithinFencedFrame()) { |
| 322 | render_frame_host_->AddMessageToConsole( |
| 323 | blink::mojom::ConsoleMessageLevel::kWarning, |
| 324 | "The SpeculationRules API does not support prerendering in fenced " |
| 325 | "frames."); |
| 326 | return false; |
| 327 | } |
| 328 | |
Yoichi Osato | 32361d1 | 2024-10-30 04:56:55 | [diff] [blame] | 329 | WebContents* web_contents = |
| 330 | WebContents::FromRenderFrameHost(&render_frame_host_.get()); |
| 331 | static_cast<PreloadingDataImpl*>( |
| 332 | PreloadingData::GetOrCreateForWebContents(web_contents)) |
| 333 | ->SetHasSpeculationRulesPrerender(); |
Yoichi Osato | fed56ff8 | 2024-02-29 01:13:45 | [diff] [blame] | 334 | if (blocked_) { |
Kevin McNee | 842eb0a | 2024-04-11 20:14:16 | [diff] [blame] | 335 | blocked_candidates_.emplace_back(candidate->Clone(), enacting_predictor, |
| 336 | confidence); |
Yoichi Osato | fed56ff8 | 2024-02-29 01:13:45 | [diff] [blame] | 337 | return false; |
| 338 | } |
Takashi Toyoshima | 27e8bb9b | 2023-06-27 10:03:05 | [diff] [blame] | 339 | |
| 340 | // Prerendering frames should not trigger any prerender request. |
| 341 | CHECK(!render_frame_host_->IsInLifecycleState( |
| 342 | RenderFrameHost::LifecycleState::kPrerendering)); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 343 | |
| 344 | if (!registry_) |
| 345 | return false; |
| 346 | |
| 347 | auto& rfhi = static_cast<RenderFrameHostImpl&>(render_frame_host_.get()); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 348 | |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 349 | // `prerender_host_id` is not available yet. |
| 350 | PrerenderInfo prerender_info(candidate); |
| 351 | |
Peter Kasting | 1557e5f | 2025-01-28 01:14:08 | [diff] [blame] | 352 | auto [begin, end] = std::ranges::equal_range( |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 353 | started_prerenders_.begin(), started_prerenders_.end(), prerender_info, |
| 354 | PrerenderInfo::PrerenderInfoComparator); |
| 355 | // cannot currently start a second prerender with the same URL and target_hint |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 356 | if (begin != end) { |
| 357 | return false; |
| 358 | } |
| 359 | |
| 360 | GetContentClient()->browser()->LogWebFeatureForCurrentPage( |
| 361 | &rfhi, blink::mojom::WebFeature::kSpeculationRulesPrerender); |
Yoichi Osato | b60bb01 | 2024-05-23 00:58:23 | [diff] [blame] | 362 | |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 363 | IncrementReceivedPrerendersCountForMetrics( |
Kouhei Ueno | 6329375 | 2023-11-14 07:41:50 | [diff] [blame] | 364 | PreloadingTriggerTypeFromSpeculationInjectionType( |
| 365 | candidate->injection_type), |
| 366 | candidate->eagerness); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 367 | |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 368 | // TODO(crbug.com/40168192): Remove it after supporting cross-site |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 369 | // prerender. |
Hiroki Nakagawa | 1500e7a | 2023-01-31 07:44:55 | [diff] [blame] | 370 | if (!prerender_navigation_utils::IsSameSite(candidate->url, |
| 371 | rfhi.GetLastCommittedOrigin())) { |
| 372 | rfhi.AddMessageToConsole( |
| 373 | blink::mojom::ConsoleMessageLevel::kWarning, |
| 374 | base::StringPrintf( |
| 375 | "The SpeculationRules API does not support cross-site prerender " |
Hiroki Nakagawa | ae693cc | 2023-06-12 08:34:15 | [diff] [blame] | 376 | "yet (initiator origin: %s, prerender origin: %s). " |
Hiroki Nakagawa | 1500e7a | 2023-01-31 07:44:55 | [diff] [blame] | 377 | "https://crbug.com/1176054 tracks cross-site support.", |
| 378 | rfhi.GetLastCommittedOrigin().Serialize().c_str(), |
| 379 | url::Origin::Create(candidate->url).Serialize().c_str())); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 380 | } |
| 381 | |
Rulong Chen(陈汝龙) | bf12169c | 2024-12-16 05:38:16 | [diff] [blame] | 382 | std::optional<net::HttpNoVarySearchData> no_vary_search_hint; |
Hiroki Nakagawa | d176addb | 2025-03-07 07:04:15 | [diff] [blame] | 383 | if (candidate->no_vary_search_hint) { |
Rulong Chen(陈汝龙) | bf12169c | 2024-12-16 05:38:16 | [diff] [blame] | 384 | no_vary_search_hint = no_vary_search::ParseHttpNoVarySearchDataFromMojom( |
| 385 | candidate->no_vary_search_hint); |
Liviu Tinta | 44e732aa | 2024-05-28 15:52:36 | [diff] [blame] | 386 | } |
| 387 | |
Takashi Nakayama | 9eb7988f | 2025-06-25 06:14:00 | [diff] [blame] | 388 | const bool should_warm_up_compositor = base::FeatureList::IsEnabled( |
| 389 | IsImmediateSpeculationEagerness(candidate->eagerness) |
| 390 | ? features::kPrerender2WarmUpCompositorForImmediate |
| 391 | : features::kPrerender2WarmUpCompositorForNonImmediate); |
Taiyo Mizuhashi | abe1fc5 | 2025-06-23 04:00:19 | [diff] [blame] | 392 | |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 393 | PrerenderAttributes attributes( |
Kouhei Ueno | 6329375 | 2023-11-14 07:41:50 | [diff] [blame] | 394 | candidate->url, |
| 395 | PreloadingTriggerTypeFromSpeculationInjectionType( |
| 396 | candidate->injection_type), |
Hiroki Nakagawa | 134ada6 | 2023-10-16 10:50:26 | [diff] [blame] | 397 | /*embedder_histogram_suffix=*/"", |
Hiroki Nakagawa | eeecc56e | 2025-03-27 02:57:30 | [diff] [blame] | 398 | SpeculationRulesParams(candidate->target_browsing_context_name_hint, |
Hiroki Nakagawa | c91e3622 | 2025-05-02 11:00:27 | [diff] [blame] | 399 | candidate->eagerness, |
| 400 | SpeculationRulesTags(candidate->tags)), |
Hiroki Nakagawa | eeecc56e | 2025-03-27 02:57:30 | [diff] [blame] | 401 | Referrer{*candidate->referrer}, no_vary_search_hint, &rfhi, |
| 402 | web_contents->GetWeakPtr(), ui::PAGE_TRANSITION_LINK, |
Taiyo Mizuhashi | abe1fc5 | 2025-06-23 04:00:19 | [diff] [blame] | 403 | should_warm_up_compositor, |
Lingqi Chi | a2efa8c | 2024-11-08 10:20:29 | [diff] [blame] | 404 | /*should_prepare_paint_tree=*/false, |
Lingqi Chi | bc88ab5 | 2025-07-24 00:54:14 | [diff] [blame] | 405 | ShouldPauseJavaScriptExecution(candidate->action), |
Arthur Sonzogni | fd1e08d | 2024-03-05 15:59:36 | [diff] [blame] | 406 | /*url_match_predicate=*/{}, |
| 407 | /*prerender_navigation_handle_callback=*/{}, |
kenoss | c3f9a2c | 2025-03-06 15:35:51 | [diff] [blame] | 408 | PreloadPipelineInfoImpl::Create( |
Lingqi Chi | 844e05d4 | 2025-07-23 02:50:50 | [diff] [blame] | 409 | /*planned_max_preloading_type=*/ |
| 410 | ConvertSpeculationActionToPreloadingType(candidate->action)), |
Jiacheng Guo | ea20d39 | 2025-07-07 01:08:14 | [diff] [blame] | 411 | /*allow_reuse=*/false); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 412 | |
Kouhei Ueno | a234a8e | 2023-11-15 05:24:42 | [diff] [blame] | 413 | PreloadingTriggerType trigger_type = |
| 414 | PreloadingTriggerTypeFromSpeculationInjectionType( |
| 415 | candidate->injection_type); |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 416 | PreloadingPredictor creating_predictor = |
Kouhei Ueno | a234a8e | 2023-11-15 05:24:42 | [diff] [blame] | 417 | GetPredictorForPreloadingTriggerType(trigger_type); |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 418 | prerender_info.prerender_host_id = [&] { |
Alison Gale | 47d1537d | 2024-04-19 21:31:46 | [diff] [blame] | 419 | // TODO(crbug.com/40235424): Handle the case where multiple speculation |
| 420 | // rules have the same URL but its `target_browsing_context_name_hint` is |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 421 | // different. In the current implementation, only the first rule is |
| 422 | // triggered. |
| 423 | switch (candidate->target_browsing_context_name_hint) { |
| 424 | case blink::mojom::SpeculationTargetHint::kBlank: { |
| 425 | if (base::FeatureList::IsEnabled( |
| 426 | blink::features::kPrerender2InNewTab)) { |
Robert Lin | 3354b29 | 2025-03-17 02:19:57 | [diff] [blame] | 427 | GetContentClient()->browser()->LogWebFeatureForCurrentPage( |
| 428 | &rfhi, |
| 429 | blink::mojom::WebFeature::kSpeculationRulesTargetHintBlank); |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 430 | // For the prerender-in-new-tab, PreloadingAttempt will be managed by |
| 431 | // a prerender WebContents to be created later. |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 432 | return registry_->CreateAndStartHostForNewTab( |
Kevin McNee | 842eb0a | 2024-04-11 20:14:16 | [diff] [blame] | 433 | attributes, creating_predictor, enacting_predictor, confidence); |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 434 | } |
| 435 | // Handle the rule as kNoHint if the prerender-in-new-tab is not |
| 436 | // enabled. |
| 437 | [[fallthrough]]; |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 438 | } |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 439 | case blink::mojom::SpeculationTargetHint::kNoHint: |
| 440 | case blink::mojom::SpeculationTargetHint::kSelf: { |
kenoss | 9d57ee7b | 2024-06-03 01:36:43 | [diff] [blame] | 441 | if (base::FeatureList::IsEnabled( |
| 442 | features::kPrerender2FallbackPrefetchSpecRules)) { |
| 443 | auto* prefetch_document_manager = |
| 444 | content::PrefetchDocumentManager::GetOrCreateForCurrentDocument( |
| 445 | web_contents->GetPrimaryMainFrame()); |
| 446 | prefetch_document_manager->PrefetchAheadOfPrerender( |
kenoss | 3bd73b8 | 2024-10-10 20:33:49 | [diff] [blame] | 447 | attributes.preload_pipeline_info, candidate.Clone(), |
| 448 | enacting_predictor); |
kenoss | 9d57ee7b | 2024-06-03 01:36:43 | [diff] [blame] | 449 | } |
| 450 | |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 451 | // Create new PreloadingAttempt and pass all the values corresponding to |
| 452 | // this prerendering attempt. |
| 453 | auto* preloading_data = |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 454 | PreloadingDataImpl::GetOrCreateForWebContents(web_contents); |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 455 | PreloadingURLMatchCallback same_url_matcher = |
| 456 | PreloadingData::GetSameURLMatcher(candidate->url); |
kenoss | 9d57ee7b | 2024-06-03 01:36:43 | [diff] [blame] | 457 | |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 458 | auto* preloading_attempt = static_cast<PreloadingAttemptImpl*>( |
| 459 | preloading_data->AddPreloadingAttempt( |
Kevin McNee | 98e068a | 2024-04-09 20:12:34 | [diff] [blame] | 460 | creating_predictor, enacting_predictor, |
Lingqi Chi | 844e05d4 | 2025-07-23 02:50:50 | [diff] [blame] | 461 | ConvertSpeculationActionToPreloadingType(candidate->action), |
| 462 | std::move(same_url_matcher), |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 463 | web_contents->GetPrimaryMainFrame()->GetPageUkmSourceId())); |
| 464 | preloading_attempt->SetSpeculationEagerness(candidate->eagerness); |
| 465 | return registry_->CreateAndStartHost(attributes, preloading_attempt); |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 466 | } |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 467 | } |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 468 | }(); |
| 469 | |
Hiroki Nakagawa | 8821cd88 | 2024-08-01 08:19:46 | [diff] [blame] | 470 | // An existing prerender may be canceled to start a new prerender, and |
| 471 | // `started_prerenders_` may be modified through this cancellation. Therefore, |
| 472 | // it is needed to re-calculate the right place here on `started_prerenders_` |
| 473 | // for new candidates. |
Peter Kasting | 1557e5f | 2025-01-28 01:14:08 | [diff] [blame] | 474 | end = std::ranges::upper_bound(started_prerenders_.begin(), |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 475 | started_prerenders_.end(), prerender_info, |
| 476 | PrerenderInfo::PrerenderInfoComparator); |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 477 | |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 478 | started_prerenders_.insert(end, std::move(prerender_info)); |
Taiyo Mizuhashi | 3a4c3d4 | 2023-11-09 10:27:14 | [diff] [blame] | 479 | |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 480 | return true; |
| 481 | } |
| 482 | |
| 483 | bool PrerendererImpl::ShouldWaitForPrerenderResult(const GURL& url) { |
HuanPo Lin | c8111d5 | 2025-06-23 06:19:44 | [diff] [blame] | 484 | // This function is used to check whetehr a prerender is started to avoid |
| 485 | // starting prefetch in OnPointerDown, OnPointerHover or other heuristic |
| 486 | // methods which don't take target_hint into consideration. So unlike other |
| 487 | // functions in this file, this part uses `url` only instead of |
| 488 | // `PrerenderInfo` which consists of target_hint information. |
Peter Kasting | 1557e5f | 2025-01-28 01:14:08 | [diff] [blame] | 489 | auto [begin, end] = std::ranges::equal_range( |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 490 | started_prerenders_.begin(), started_prerenders_.end(), url, |
| 491 | std::less<>(), &PrerenderInfo::url); |
| 492 | for (auto it = begin; it != end; ++it) { |
Avi Drissman | dcc8e68 | 2024-09-04 14:14:48 | [diff] [blame] | 493 | if (it->prerender_host_id.is_null()) { |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 494 | return false; |
| 495 | } |
| 496 | } |
| 497 | return begin != end; |
| 498 | } |
| 499 | |
Avi Drissman | dcc8e68 | 2024-09-04 14:14:48 | [diff] [blame] | 500 | void PrerendererImpl::OnCancel(FrameTreeNodeId host_frame_tree_node_id, |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 501 | const PrerenderCancellationReason& reason) { |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 502 | switch (reason.final_status()) { |
Alison Gale | 770f3fc | 2024-04-27 00:39:58 | [diff] [blame] | 503 | // TODO(crbug.com/40275452): Support other final status cases. |
Taiyo Mizuhashi | 352f6d6 | 2024-06-24 06:22:59 | [diff] [blame] | 504 | case PrerenderFinalStatus::kTimeoutBackgrounded: |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 505 | case PrerenderFinalStatus::kMaxNumOfRunningNonImmediatePrerendersExceeded: |
Taiyo Mizuhashi | 5694b82 | 2023-09-26 16:10:30 | [diff] [blame] | 506 | case PrerenderFinalStatus::kSpeculationRuleRemoved: { |
| 507 | auto erasing_prerender_it = std::find_if( |
| 508 | started_prerenders_.begin(), started_prerenders_.end(), |
| 509 | [&](const PrerenderInfo& prerender_info) { |
| 510 | return prerender_info.prerender_host_id == host_frame_tree_node_id; |
| 511 | }); |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 512 | |
Taiyo Mizuhashi | 5694b82 | 2023-09-26 16:10:30 | [diff] [blame] | 513 | if (erasing_prerender_it != started_prerenders_.end()) { |
| 514 | auto url = erasing_prerender_it->url; |
| 515 | started_prerenders_.erase(erasing_prerender_it); |
| 516 | |
| 517 | // Notify PreloadingDecider. |
| 518 | prerender_cancellation_callback_.Run(url); |
| 519 | } |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 520 | break; |
Taiyo Mizuhashi | 5694b82 | 2023-09-26 16:10:30 | [diff] [blame] | 521 | } |
Taiyo Mizuhashi | 295ccbdf | 2023-09-13 09:17:02 | [diff] [blame] | 522 | default: |
| 523 | break; |
| 524 | } |
| 525 | } |
| 526 | |
| 527 | void PrerendererImpl::OnRegistryDestroyed() { |
| 528 | observation_.Reset(); |
| 529 | } |
| 530 | |
| 531 | void PrerendererImpl::SetPrerenderCancellationCallback( |
| 532 | PrerenderCancellationCallback callback) { |
| 533 | prerender_cancellation_callback_ = std::move(callback); |
| 534 | } |
| 535 | |
Samar Chehade-Lepleux | ce1baf2 | 2023-05-16 09:50:09 | [diff] [blame] | 536 | void PrerendererImpl::CancelStartedPrerenders() { |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 537 | if (registry_) { |
Avi Drissman | dcc8e68 | 2024-09-04 14:14:48 | [diff] [blame] | 538 | std::vector<FrameTreeNodeId> started_prerender_ids; |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 539 | for (auto& prerender_info : started_prerenders_) { |
| 540 | started_prerender_ids.push_back(prerender_info.prerender_host_id); |
| 541 | } |
Samar Chehade-Lepleux | ce1baf2 | 2023-05-16 09:50:09 | [diff] [blame] | 542 | registry_->CancelHosts( |
| 543 | started_prerender_ids, |
| 544 | PrerenderCancellationReason(PrerenderFinalStatus::kTriggerDestroyed)); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 545 | } |
| 546 | |
| 547 | started_prerenders_.clear(); |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 548 | } |
| 549 | |
kenoss | 4858a80 | 2024-10-11 06:50:56 | [diff] [blame] | 550 | void PrerendererImpl::CancelStartedPrerendersForTesting() { |
| 551 | CancelStartedPrerenders(); |
| 552 | } |
| 553 | |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 554 | void PrerendererImpl::ResetReceivedPrerendersCountForMetrics() { |
Taiyo Mizuhashi | 5470a52 | 2023-08-21 05:05:56 | [diff] [blame] | 555 | for (auto trigger_type : |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 556 | {PreloadingTriggerType::kSpeculationRule, |
| 557 | PreloadingTriggerType::kSpeculationRuleFromIsolatedWorld}) { |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 558 | received_prerenders_by_eagerness_[trigger_type].fill({}); |
| 559 | } |
| 560 | } |
Taiyo Mizuhashi | 5470a52 | 2023-08-21 05:05:56 | [diff] [blame] | 561 | |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 562 | void PrerendererImpl::IncrementReceivedPrerendersCountForMetrics( |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 563 | PreloadingTriggerType trigger_type, |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 564 | blink::mojom::SpeculationEagerness eagerness) { |
| 565 | received_prerenders_by_eagerness_[trigger_type] |
| 566 | [static_cast<size_t>(eagerness)]++; |
| 567 | } |
| 568 | |
| 569 | void PrerendererImpl::RecordReceivedPrerendersCountToMetrics() { |
| 570 | for (auto trigger_type : |
Kouhei Ueno | 3f37992b | 2023-11-09 23:29:02 | [diff] [blame] | 571 | {PreloadingTriggerType::kSpeculationRule, |
| 572 | PreloadingTriggerType::kSpeculationRuleFromIsolatedWorld}) { |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 573 | int conservative = |
| 574 | received_prerenders_by_eagerness_[trigger_type][static_cast<size_t>( |
| 575 | blink::mojom::SpeculationEagerness::kConservative)]; |
| 576 | int moderate = |
| 577 | received_prerenders_by_eagerness_[trigger_type][static_cast<size_t>( |
| 578 | blink::mojom::SpeculationEagerness::kModerate)]; |
Takashi Nakayama | 9eb7988f | 2025-06-25 06:14:00 | [diff] [blame] | 579 | int eager = |
| 580 | received_prerenders_by_eagerness_[trigger_type][static_cast<size_t>( |
| 581 | blink::mojom::SpeculationEagerness::kEager)]; |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 582 | int immediate = |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 583 | received_prerenders_by_eagerness_[trigger_type][static_cast<size_t>( |
Takashi Nakayama | 978f0a15 | 2025-06-17 08:26:25 | [diff] [blame] | 584 | blink::mojom::SpeculationEagerness::kImmediate)]; |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 585 | |
| 586 | // This will record zero when |
| 587 | // 1) there are no started prerenders eventually. Also noted that if |
Taiyo Mizuhashi | 5470a52 | 2023-08-21 05:05:56 | [diff] [blame] | 588 | // there is no rule set, PreloadingDecider won't be created (which means |
| 589 | // PrerenderImpl also won't be created), so it cannot be reached this |
| 590 | // code path at the first place. |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 591 | // 2) when the corresponding RFH lives but is inactive (such as the case in |
| 592 | // BFCache) after once PrimaryPageChanged was called and the recorded |
| 593 | // number was reset (As long as PreloadingDecider (which has the same |
Taiyo Mizuhashi | 5470a52 | 2023-08-21 05:05:56 | [diff] [blame] | 594 | // lifetime with a document) that owns this (PrerenderImpl) lives, this |
Taiyo Mizuhashi | 93c5f07d | 2023-10-06 05:01:35 | [diff] [blame] | 595 | // function will be called per PrimaryPageChanged). |
Taiyo Mizuhashi | 5470a52 | 2023-08-21 05:05:56 | [diff] [blame] | 596 | // |
| 597 | // Avoids recording these cases uniformly. |
Takashi Nakayama | 9eb7988f | 2025-06-25 06:14:00 | [diff] [blame] | 598 | if (conservative + moderate + eager + immediate == 0) { |
Taiyo Mizuhashi | 5470a52 | 2023-08-21 05:05:56 | [diff] [blame] | 599 | continue; |
| 600 | } |
| 601 | |
| 602 | // Record per single eagerness. |
| 603 | RecordReceivedPrerendersPerPrimaryPageChangedCount( |
| 604 | conservative, trigger_type, "Conservative"); |
| 605 | RecordReceivedPrerendersPerPrimaryPageChangedCount(moderate, trigger_type, |
| 606 | "Moderate"); |
Takashi Nakayama | b12a506 | 2025-08-04 04:44:11 | [diff] [blame] | 607 | RecordReceivedPrerendersPerPrimaryPageChangedCount(eager, trigger_type, |
| 608 | "Eager2"); |
| 609 | RecordReceivedPrerendersPerPrimaryPageChangedCount(immediate, trigger_type, |
| 610 | "Immediate2"); |
Taiyo Mizuhashi | 5470a52 | 2023-08-21 05:05:56 | [diff] [blame] | 611 | } |
| 612 | } |
| 613 | |
Iman Saboori | 31bed87 | 2022-12-09 15:41:31 | [diff] [blame] | 614 | } // namespace content |