Make sure webrtc::VideoSource is released when WebRtcVideoTrackAdapter is destroyed.
[chromium-blink-merge.git] / components / dom_distiller / core / task_tracker.cc
blob316c679c5fd4c31881ad4eb4c71396d55d24918c
1 // Copyright 2013 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.
5 #include "components/dom_distiller/core/task_tracker.h"
7 #include "base/auto_reset.h"
8 #include "base/message_loop/message_loop.h"
9 #include "components/dom_distiller/core/distilled_content_store.h"
10 #include "components/dom_distiller/core/proto/distilled_article.pb.h"
11 #include "components/dom_distiller/core/proto/distilled_page.pb.h"
13 namespace dom_distiller {
15 ViewerHandle::ViewerHandle(CancelCallback callback)
16 : cancel_callback_(callback) {}
18 ViewerHandle::~ViewerHandle() {
19 if (!cancel_callback_.is_null()) {
20 cancel_callback_.Run();
24 TaskTracker::TaskTracker(const ArticleEntry& entry,
25 CancelCallback callback,
26 DistilledContentStore* content_store)
27 : cancel_callback_(callback),
28 content_store_(content_store),
29 blob_fetcher_running_(false),
30 entry_(entry),
31 distilled_article_(),
32 content_ready_(false),
33 destruction_allowed_(true),
34 weak_ptr_factory_(this) {}
36 TaskTracker::~TaskTracker() {
37 DCHECK(destruction_allowed_);
38 DCHECK(viewers_.empty());
41 void TaskTracker::StartDistiller(DistillerFactory* factory,
42 scoped_ptr<DistillerPage> distiller_page) {
43 if (distiller_) {
44 return;
46 if (entry_.pages_size() == 0) {
47 return;
49 GURL url(entry_.pages(0).url());
50 DCHECK(url.is_valid());
52 distiller_ = factory->CreateDistiller();
53 distiller_->DistillPage(url,
54 distiller_page.Pass(),
55 base::Bind(&TaskTracker::OnDistillerFinished,
56 weak_ptr_factory_.GetWeakPtr()),
57 base::Bind(&TaskTracker::OnArticleDistillationUpdated,
58 weak_ptr_factory_.GetWeakPtr()));
61 void TaskTracker::StartBlobFetcher() {
62 if (content_store_) {
63 content_store_->LoadContent(entry_,
64 base::Bind(&TaskTracker::OnBlobFetched,
65 weak_ptr_factory_.GetWeakPtr()));
69 void TaskTracker::AddSaveCallback(const SaveCallback& callback) {
70 DCHECK(!callback.is_null());
71 save_callbacks_.push_back(callback);
72 if (content_ready_) {
73 // Distillation for this task has already completed, and so it can be
74 // immediately saved.
75 ScheduleSaveCallbacks(true);
79 scoped_ptr<ViewerHandle> TaskTracker::AddViewer(ViewRequestDelegate* delegate) {
80 viewers_.push_back(delegate);
81 if (content_ready_) {
82 // Distillation for this task has already completed, and so the delegate can
83 // be immediately told of the result.
84 base::MessageLoop::current()->PostTask(
85 FROM_HERE,
86 base::Bind(&TaskTracker::NotifyViewer,
87 weak_ptr_factory_.GetWeakPtr(),
88 delegate));
90 return scoped_ptr<ViewerHandle>(new ViewerHandle(base::Bind(
91 &TaskTracker::RemoveViewer, weak_ptr_factory_.GetWeakPtr(), delegate)));
94 const std::string& TaskTracker::GetEntryId() const { return entry_.entry_id(); }
96 bool TaskTracker::HasEntryId(const std::string& entry_id) const {
97 return entry_.entry_id() == entry_id;
100 bool TaskTracker::HasUrl(const GURL& url) const {
101 for (int i = 0; i < entry_.pages_size(); ++i) {
102 if (entry_.pages(i).url() == url.spec()) {
103 return true;
106 return false;
109 void TaskTracker::RemoveViewer(ViewRequestDelegate* delegate) {
110 viewers_.erase(std::remove(viewers_.begin(), viewers_.end(), delegate));
111 if (viewers_.empty()) {
112 MaybeCancel();
116 void TaskTracker::MaybeCancel() {
117 if (!save_callbacks_.empty() || !viewers_.empty()) {
118 // There's still work to be done.
119 return;
122 CancelPendingSources();
124 base::AutoReset<bool> dont_delete_this_in_callback(&destruction_allowed_,
125 false);
126 cancel_callback_.Run(this);
129 void TaskTracker::CancelSaveCallbacks() { ScheduleSaveCallbacks(false); }
131 void TaskTracker::ScheduleSaveCallbacks(bool distillation_succeeded) {
132 base::MessageLoop::current()->PostTask(
133 FROM_HERE,
134 base::Bind(&TaskTracker::DoSaveCallbacks,
135 weak_ptr_factory_.GetWeakPtr(),
136 distillation_succeeded));
139 void TaskTracker::OnDistillerFinished(
140 scoped_ptr<DistilledArticleProto> distilled_article) {
141 if (content_ready_) {
142 return;
145 DistilledArticleReady(distilled_article.Pass());
146 if (content_ready_) {
147 AddDistilledContentToStore(*distilled_article_);
150 ContentSourceFinished();
153 void TaskTracker::CancelPendingSources() {
154 base::MessageLoop::current()->DeleteSoon(FROM_HERE, distiller_.release());
157 void TaskTracker::OnBlobFetched(
158 bool success,
159 scoped_ptr<DistilledArticleProto> distilled_article) {
160 blob_fetcher_running_ = false;
162 if (content_ready_) {
163 return;
166 DistilledArticleReady(distilled_article.Pass());
168 ContentSourceFinished();
171 bool TaskTracker::IsAnySourceRunning() const {
172 return distiller_ || blob_fetcher_running_;
175 void TaskTracker::ContentSourceFinished() {
176 if (content_ready_) {
177 CancelPendingSources();
178 } else if (!IsAnySourceRunning()) {
179 distilled_article_.reset(new DistilledArticleProto());
180 NotifyViewersAndCallbacks();
184 void TaskTracker::DistilledArticleReady(
185 scoped_ptr<DistilledArticleProto> distilled_article) {
186 DCHECK(!content_ready_);
188 if (distilled_article->pages_size() == 0) {
189 return;
192 content_ready_ = true;
194 distilled_article_ = distilled_article.Pass();
195 entry_.set_title(distilled_article_->title());
196 entry_.clear_pages();
197 for (int i = 0; i < distilled_article_->pages_size(); ++i) {
198 sync_pb::ArticlePage* page = entry_.add_pages();
199 page->set_url(distilled_article_->pages(i).url());
202 NotifyViewersAndCallbacks();
205 void TaskTracker::NotifyViewersAndCallbacks() {
206 for (size_t i = 0; i < viewers_.size(); ++i) {
207 NotifyViewer(viewers_[i]);
210 // Already inside a callback run SaveCallbacks directly.
211 DoSaveCallbacks(content_ready_);
214 void TaskTracker::NotifyViewer(ViewRequestDelegate* delegate) {
215 delegate->OnArticleReady(distilled_article_.get());
218 void TaskTracker::DoSaveCallbacks(bool success) {
219 if (!save_callbacks_.empty()) {
220 for (size_t i = 0; i < save_callbacks_.size(); ++i) {
221 DCHECK(!save_callbacks_[i].is_null());
222 save_callbacks_[i].Run(
223 entry_, distilled_article_.get(), success);
226 save_callbacks_.clear();
227 MaybeCancel();
231 void TaskTracker::OnArticleDistillationUpdated(
232 const ArticleDistillationUpdate& article_update) {
233 for (size_t i = 0; i < viewers_.size(); ++i) {
234 viewers_[i]->OnArticleUpdated(article_update);
238 void TaskTracker::AddDistilledContentToStore(
239 const DistilledArticleProto& content) {
240 if (content_store_) {
241 content_store_->SaveContent(
242 entry_, content, DistilledContentStore::SaveCallback());
247 } // namespace dom_distiller