1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/offline_pages/core/snapshot_controller.h"
6 
7 #include "base/bind.h"
8 #include "base/check_op.h"
9 #include "base/location.h"
10 #include "base/time/time.h"
11 #include "components/offline_pages/core/offline_page_feature.h"
12 
13 namespace {
14 // Default delay, in milliseconds, between the main document parsed event and
15 // snapshot. Note: this snapshot might not occur if the OnLoad event and
16 // OnLoad delay elapses first to trigger a final snapshot.
17 const int64_t kDefaultDelayAfterDocumentAvailableMs = 7000;
18 
19 // Default delay, in milliseconds, between the main document OnLoad event and
20 // snapshot.
21 const int64_t kDelayAfterDocumentOnLoadCompletedMsForeground = 1000;
22 
23 // Delay for testing to keep polling times reasonable.
24 const int64_t kDelayForTests = 0;
25 
26 }  // namespace
27 
28 namespace offline_pages {
29 
SnapshotController(const scoped_refptr<base::SingleThreadTaskRunner> & task_runner,SnapshotController::Client * client)30 SnapshotController::SnapshotController(
31     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
32     SnapshotController::Client* client)
33     : task_runner_(task_runner),
34       client_(client),
35       state_(State::READY),
36       delay_after_document_available_ms_(kDefaultDelayAfterDocumentAvailableMs),
37       delay_after_document_on_load_completed_ms_(
38           kDelayAfterDocumentOnLoadCompletedMsForeground) {
39   if (offline_pages::ShouldUseTestingSnapshotDelay()) {
40     delay_after_document_available_ms_ = kDelayForTests;
41     delay_after_document_on_load_completed_ms_ = kDelayForTests;
42   }
43 }
44 
~SnapshotController()45 SnapshotController::~SnapshotController() {}
46 
Reset()47 void SnapshotController::Reset() {
48   // Cancel potentially delayed tasks that relate to the previous 'session'.
49   weak_ptr_factory_.InvalidateWeakPtrs();
50   state_ = State::READY;
51   current_page_quality_ = PageQuality::POOR;
52 }
53 
Stop()54 void SnapshotController::Stop() {
55   state_ = State::STOPPED;
56 }
57 
PendingSnapshotCompleted()58 void SnapshotController::PendingSnapshotCompleted() {
59   // Unless the controller is "stopped", enable the subsequent snapshots.
60   // Stopped state prevents any further snapshots form being started.
61   if (state_ == State::STOPPED)
62     return;
63   state_ = State::READY;
64 }
65 
DocumentAvailableInMainFrame()66 void SnapshotController::DocumentAvailableInMainFrame() {
67   DCHECK_EQ(PageQuality::POOR, current_page_quality_);
68   // Post a delayed task to snapshot.
69   task_runner_->PostDelayedTask(
70       FROM_HERE,
71       base::BindOnce(&SnapshotController::MaybeStartSnapshot,
72                      weak_ptr_factory_.GetWeakPtr(),
73                      PageQuality::FAIR_AND_IMPROVING),
74       base::TimeDelta::FromMilliseconds(delay_after_document_available_ms_));
75 }
76 
DocumentOnLoadCompletedInMainFrame()77 void SnapshotController::DocumentOnLoadCompletedInMainFrame() {
78   // Post a delayed task to snapshot and then stop this controller.
79   task_runner_->PostDelayedTask(
80       FROM_HERE,
81       base::BindOnce(&SnapshotController::MaybeStartSnapshotThenStop,
82                      weak_ptr_factory_.GetWeakPtr()),
83       base::TimeDelta::FromMilliseconds(
84           delay_after_document_on_load_completed_ms_));
85 }
86 
MaybeStartSnapshot(PageQuality updated_page_quality)87 void SnapshotController::MaybeStartSnapshot(PageQuality updated_page_quality) {
88   if (state_ != State::READY)
89     return;
90   DCHECK_LT(current_page_quality_, updated_page_quality);
91   current_page_quality_ = updated_page_quality;
92   state_ = State::SNAPSHOT_PENDING;
93   client_->StartSnapshot();
94 }
95 
MaybeStartSnapshotThenStop()96 void SnapshotController::MaybeStartSnapshotThenStop() {
97   MaybeStartSnapshot(PageQuality::HIGH);
98   Stop();
99 }
100 
GetDelayAfterDocumentAvailableForTest()101 int64_t SnapshotController::GetDelayAfterDocumentAvailableForTest() {
102   return delay_after_document_available_ms_;
103 }
104 
GetDelayAfterDocumentOnLoadCompletedForTest()105 int64_t SnapshotController::GetDelayAfterDocumentOnLoadCompletedForTest() {
106   return delay_after_document_on_load_completed_ms_;
107 }
108 
109 }  // namespace offline_pages
110