summaryrefslogtreecommitdiff
path: root/chromium/components/offline_pages/core/snapshot_controller.cc
blob: 27bb798c8e14a7120b1277ae312999276bcffb04 (plain)
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/offline_pages/core/snapshot_controller.h"

#include "base/bind.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "components/offline_pages/core/offline_page_feature.h"

namespace {
const bool kDocumentAvailableTriggersSnapshot = true;

// Default delay, in milliseconds, between the main document parsed event and
// snapshot. Note: this snapshot might not occur if the OnLoad event and
// OnLoad delay elapses first to trigger a final snapshot.
const int64_t kDefaultDelayAfterDocumentAvailableMs = 7000;

// Default delay, in milliseconds, between the main document OnLoad event and
// snapshot.
const int64_t kDelayAfterDocumentOnLoadCompletedMsForeground = 1000;
const int64_t kDelayAfterDocumentOnLoadCompletedMsBackground = 2000;

// Default delay, in milliseconds, between renovations finishing and
// taking a snapshot. Allows for page to update in response to the
// renovations.
const int64_t kDelayAfterRenovationsCompletedMs = 2000;

// Delay for testing to keep polling times reasonable.
const int64_t kDelayForTests = 0;

}  // namespace

namespace offline_pages {

// static
std::unique_ptr<SnapshotController>
SnapshotController::CreateForForegroundOfflining(
    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
    SnapshotController::Client* client) {
  return std::unique_ptr<SnapshotController>(new SnapshotController(
      task_runner, client, kDefaultDelayAfterDocumentAvailableMs,
      kDelayAfterDocumentOnLoadCompletedMsForeground,
      kDelayAfterRenovationsCompletedMs, kDocumentAvailableTriggersSnapshot,
      false));
}

// static
std::unique_ptr<SnapshotController>
SnapshotController::CreateForBackgroundOfflining(
    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
    SnapshotController::Client* client,
    bool renovations_enabled) {
  return std::unique_ptr<SnapshotController>(new SnapshotController(
      task_runner, client, kDefaultDelayAfterDocumentAvailableMs,
      kDelayAfterDocumentOnLoadCompletedMsBackground,
      kDelayAfterRenovationsCompletedMs, !kDocumentAvailableTriggersSnapshot,
      renovations_enabled));
}

SnapshotController::SnapshotController(
    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
    SnapshotController::Client* client,
    int64_t delay_after_document_available_ms,
    int64_t delay_after_document_on_load_completed_ms,
    int64_t delay_after_renovations_completed_ms,
    bool document_available_triggers_snapshot,
    bool renovations_enabled)
    : task_runner_(task_runner),
      client_(client),
      state_(State::READY),
      delay_after_document_available_ms_(delay_after_document_available_ms),
      delay_after_document_on_load_completed_ms_(
          delay_after_document_on_load_completed_ms),
      delay_after_renovations_completed_ms_(
          delay_after_renovations_completed_ms),
      document_available_triggers_snapshot_(
          document_available_triggers_snapshot),
      renovations_enabled_(renovations_enabled),
      weak_ptr_factory_(this) {
  if (offline_pages::ShouldUseTestingSnapshotDelay()) {
    delay_after_document_available_ms_ = kDelayForTests;
    delay_after_document_on_load_completed_ms_ = kDelayForTests;
    delay_after_renovations_completed_ms_ = kDelayForTests;
  }
}

SnapshotController::~SnapshotController() {}

void SnapshotController::Reset() {
  // Cancel potentially delayed tasks that relate to the previous 'session'.
  weak_ptr_factory_.InvalidateWeakPtrs();
  state_ = State::READY;
  current_page_quality_ = PageQuality::POOR;
}

void SnapshotController::Stop() {
  state_ = State::STOPPED;
}

void SnapshotController::PendingSnapshotCompleted() {
  // Unless the controller is "stopped", enable the subsequent snapshots.
  // Stopped state prevents any further snapshots form being started.
  if (state_ == State::STOPPED)
    return;
  state_ = State::READY;
}

void SnapshotController::RenovationsCompleted() {
  if (renovations_enabled_) {
    task_runner_->PostDelayedTask(
        FROM_HERE,
        base::Bind(&SnapshotController::MaybeStartSnapshotThenStop,
                   weak_ptr_factory_.GetWeakPtr()),
        base::TimeDelta::FromMilliseconds(
            delay_after_renovations_completed_ms_));
  }
}

void SnapshotController::DocumentAvailableInMainFrame() {
  if (document_available_triggers_snapshot_) {
    DCHECK_EQ(PageQuality::POOR, current_page_quality_);
    // Post a delayed task to snapshot.
    task_runner_->PostDelayedTask(
        FROM_HERE,
        base::Bind(&SnapshotController::MaybeStartSnapshot,
                   weak_ptr_factory_.GetWeakPtr(),
                   PageQuality::FAIR_AND_IMPROVING),
        base::TimeDelta::FromMilliseconds(delay_after_document_available_ms_));
  }
}

void SnapshotController::DocumentOnLoadCompletedInMainFrame() {
  if (renovations_enabled_) {
    // Run renovations. After renovations complete, a snapshot will be
    // triggered after a delay.
    client_->RunRenovations();
  } else {
    // Post a delayed task to snapshot and then stop this controller.
    task_runner_->PostDelayedTask(
        FROM_HERE,
        base::Bind(&SnapshotController::MaybeStartSnapshotThenStop,
                   weak_ptr_factory_.GetWeakPtr()),
        base::TimeDelta::FromMilliseconds(
            delay_after_document_on_load_completed_ms_));
  }
}

void SnapshotController::MaybeStartSnapshot(PageQuality updated_page_quality) {
  if (state_ != State::READY)
    return;
  DCHECK_LT(current_page_quality_, updated_page_quality);
  current_page_quality_ = updated_page_quality;
  state_ = State::SNAPSHOT_PENDING;
  client_->StartSnapshot();
}

void SnapshotController::MaybeStartSnapshotThenStop() {
  MaybeStartSnapshot(PageQuality::HIGH);
  Stop();
}

int64_t SnapshotController::GetDelayAfterDocumentAvailableForTest() {
  return delay_after_document_available_ms_;
}

int64_t SnapshotController::GetDelayAfterDocumentOnLoadCompletedForTest() {
  return delay_after_document_on_load_completed_ms_;
}

int64_t SnapshotController::GetDelayAfterRenovationsCompletedForTest() {
  return delay_after_renovations_completed_ms_;
}

}  // namespace offline_pages