15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved. 25d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// found in the LICENSE file. 45d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/dom_distiller/content/dom_distiller_viewer_source.h" 65d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <sstream> 85d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <string> 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <vector> 105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/ref_counted_memory.h" 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/scoped_ptr.h" 135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/message_loop/message_loop.h" 141320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/metrics/user_metrics.h" 15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "base/strings/utf_string_conversions.h" 16116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/dom_distiller/core/distilled_page_prefs.h" 17116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "components/dom_distiller/core/dom_distiller_service.h" 185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "components/dom_distiller/core/task_tracker.h" 19a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "components/dom_distiller/core/url_constants.h" 20a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "components/dom_distiller/core/viewer.h" 21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/navigation_details.h" 22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/navigation_entry.h" 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/render_frame_host.h" 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "content/public/browser/render_view_host.h" 251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "content/public/browser/user_metrics.h" 26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/web_contents.h" 27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "content/public/browser/web_contents_observer.h" 28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/base/url_util.h" 295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/url_request/url_request.h" 305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 31a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)namespace dom_distiller { 325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Handles receiving data asynchronously for a specific entry, and passing 34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// it along to the data callback for the data source. Lifetime matches that of 35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)// the current main frame's page in the Viewer instance. 36a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)class DomDistillerViewerSource::RequestViewerHandle 37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) : public ViewRequestDelegate, 38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch public content::WebContentsObserver, 39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch public DistilledPagePrefs::Observer { 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public: 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) explicit RequestViewerHandle( 42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) content::WebContents* web_contents, 43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& expected_scheme, 44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& expected_request_path, 45116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const content::URLDataSource::GotDataCallback& callback, 46116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DistilledPagePrefs* distilled_page_prefs); 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual ~RequestViewerHandle(); 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 49116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // ViewRequestDelegate implementation: 50a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch virtual void OnArticleReady( 51a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch const DistilledArticleProto* article_proto) OVERRIDE; 525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 53a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch virtual void OnArticleUpdated( 54a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch ArticleDistillationUpdate article_update) OVERRIDE; 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void TakeViewerHandle(scoped_ptr<ViewerHandle> viewer_handle); 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 58116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // content::WebContentsObserver implementation: 59cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) virtual void DidNavigateMainFrame( 60cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const content::LoadCommittedDetails& details, 61cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const content::FrameNavigateParams& params) OVERRIDE; 62cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE; 63cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) virtual void WebContentsDestroyed() OVERRIDE; 64116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch virtual void DidFinishLoad(content::RenderFrameHost* render_frame_host, 65116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const GURL& validated_url) OVERRIDE; 66cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) private: 68cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Sends JavaScript to the attached Viewer, buffering data if the viewer isn't 69cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // ready. 70cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void SendJavaScript(const std::string& buffer); 71cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 72cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Cancels the current view request. Once called, no updates will be 73cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // propagated to the view, and the request to DomDistillerService will be 74cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // cancelled. 75cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) void Cancel(); 76cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 77116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // DistilledPagePrefs::Observer implementation: 786e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) virtual void OnChangeFontFamily( 796e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DistilledPagePrefs::FontFamily new_font_family) OVERRIDE; 80116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch virtual void OnChangeTheme(DistilledPagePrefs::Theme new_theme) OVERRIDE; 81116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The handle to the view request towards the DomDistillerService. It 835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // needs to be kept around to ensure the distillation request finishes. 845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<ViewerHandle> viewer_handle_; 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 86cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The scheme hosting the current view request; 87cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string expected_scheme_; 88cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 89cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // The query path for the current view request. 90cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string expected_request_path_; 91cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 92cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Holds the callback to where the data retrieved is sent back. 935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) content::URLDataSource::GotDataCallback callback_; 94cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Number of pages of the distilled article content that have been rendered by 96cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // the viewer. 97cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) int page_count_; 98cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 99116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch // Interface for accessing preferences for distilled pages. 100116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DistilledPagePrefs* distilled_page_prefs_; 101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Whether the page is sufficiently initialized to handle updates from the 103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // distiller. 104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) bool waiting_for_page_ready_; 105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Temporary store of pending JavaScript if the page isn't ready to receive 107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // data from distillation. 108cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string buffer_; 1095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}; 1105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)DomDistillerViewerSource::RequestViewerHandle::RequestViewerHandle( 112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) content::WebContents* web_contents, 113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& expected_scheme, 114cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& expected_request_path, 115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const content::URLDataSource::GotDataCallback& callback, 116116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DistilledPagePrefs* distilled_page_prefs) 117116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch : expected_scheme_(expected_scheme), 118cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) expected_request_path_(expected_request_path), 119cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) callback_(callback), 120cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) page_count_(0), 121116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch distilled_page_prefs_(distilled_page_prefs), 122cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) waiting_for_page_ready_(true) { 123116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch content::WebContentsObserver::Observe(web_contents); 124116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch distilled_page_prefs_->AddObserver(this); 125a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 127a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochDomDistillerViewerSource::RequestViewerHandle::~RequestViewerHandle() { 128116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch distilled_page_prefs_->RemoveObserver(this); 129cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 130cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 131cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::SendJavaScript( 132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string& buffer) { 133cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (waiting_for_page_ready_) { 134cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) buffer_ += buffer; 135cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 136116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (web_contents()) { 137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch web_contents()->GetMainFrame()->ExecuteJavaScript( 138cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::UTF8ToUTF16(buffer)); 139cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 140cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 141cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 142cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 143cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::DidNavigateMainFrame( 144cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const content::LoadCommittedDetails& details, 145cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const content::FrameNavigateParams& params) { 146cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const GURL& navigation = details.entry->GetURL(); 147cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (details.is_in_page || ( 148cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) navigation.SchemeIs(expected_scheme_.c_str()) && 149cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) expected_request_path_ == navigation.query())) { 150cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // In-page navigations, as well as the main view request can be ignored. 151cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 152cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 153cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 154cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Cancel(); 155cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 156cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 157cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 158cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::RenderProcessGone( 159cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::TerminationStatus status) { 160cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Cancel(); 161cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 162cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 163cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::WebContentsDestroyed() { 164cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) Cancel(); 165cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 166cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 167cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::Cancel() { 168cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // No need to listen for notifications. 169cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) content::WebContentsObserver::Observe(NULL); 170cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 171cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // Schedule the Viewer for deletion. Ensures distillation is cancelled, and 172cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // any pending data stored in |buffer_| is released. 173cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) base::MessageLoop::current()->DeleteSoon(FROM_HERE, this); 174cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)} 175cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) 176cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::DidFinishLoad( 177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch content::RenderFrameHost* render_frame_host, 178116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const GURL& validated_url) { 179116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if (render_frame_host->GetParent()) { 180cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 181cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 182cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) waiting_for_page_ready_ = false; 183cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (buffer_.empty()) { 184cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 185cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 186116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(buffer_)); 187cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) buffer_.clear(); 188a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 190a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::OnArticleReady( 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const DistilledArticleProto* article_proto) { 192cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (page_count_ == 0) { 193cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // This is a single-page article. 1946e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) std::string unsafe_page_html = 1956e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) viewer::GetUnsafeArticleHtml( 1966e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) article_proto, 1976e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) distilled_page_prefs_->GetTheme(), 1986e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) distilled_page_prefs_->GetFontFamily()); 199cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); 200cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else if (page_count_ == article_proto->pages_size()) { 201cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // We may still be showing the "Loading" indicator. 202cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SendJavaScript(viewer::GetToggleLoadingIndicatorJs(true)); 203cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 204cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // It's possible that we didn't get some incremental updates from the 205cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // distiller. Ensure all remaining pages are flushed to the viewer. 206cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (;page_count_ < article_proto->pages_size(); page_count_++) { 207cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const DistilledPageProto& page = article_proto->pages(page_count_); 208cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SendJavaScript( 209cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) viewer::GetUnsafeIncrementalDistilledPageJs( 210cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) &page, 211cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) page_count_ == article_proto->pages_size())); 212cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 213cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 214cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // No need to hold on to the ViewerHandle now that distillation is complete. 215cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) viewer_handle_.reset(); 2165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::OnArticleUpdated( 219a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) ArticleDistillationUpdate article_update) { 220cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) for (;page_count_ < static_cast<int>(article_update.GetPagesSize()); 221cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) page_count_++) { 222cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const DistilledPageProto& page = 223cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) article_update.GetDistilledPage(page_count_); 224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (page_count_ == 0) { 225cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // This is the first page, so send Viewer page scaffolding too. 226116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch std::string unsafe_page_html = viewer::GetUnsafePartialArticleHtml( 2276e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) &page, 2286e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) distilled_page_prefs_->GetTheme(), 2296e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) distilled_page_prefs_->GetFontFamily()); 230cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) callback_.Run(base::RefCountedString::TakeString(&unsafe_page_html)); 231cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } else { 232cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) SendJavaScript( 233cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) viewer::GetUnsafeIncrementalDistilledPageJs(&page, false)); 234cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 235cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 236a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 237a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 238a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::TakeViewerHandle( 2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<ViewerHandle> viewer_handle) { 2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) viewer_handle_ = viewer_handle.Pass(); 2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 243116680a4aac90f2aa7413d9095a592090648e557Ben Murdochvoid DomDistillerViewerSource::RequestViewerHandle::OnChangeTheme( 244116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch DistilledPagePrefs::Theme new_theme) { 245116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch SendJavaScript(viewer::GetDistilledPageThemeJs(new_theme)); 246116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 247116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 2486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)void DomDistillerViewerSource::RequestViewerHandle::OnChangeFontFamily( 2496e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) DistilledPagePrefs::FontFamily new_font) { 2506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) SendJavaScript(viewer::GetDistilledPageFontFamilyJs(new_font)); 2516e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)} 2526e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) 2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)DomDistillerViewerSource::DomDistillerViewerSource( 254a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) DomDistillerServiceInterface* dom_distiller_service, 2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& scheme) 256a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch : scheme_(scheme), dom_distiller_service_(dom_distiller_service) { 257a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 259a02191e04bc25c4935f804f2c080ae28663d096dBen MurdochDomDistillerViewerSource::~DomDistillerViewerSource() { 260a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string DomDistillerViewerSource::GetSource() const { 2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return scheme_ + "://"; 2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DomDistillerViewerSource::StartDataRequest( 2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& path, 2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int render_process_id, 2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int render_frame_id, 2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const content::URLDataSource::GotDataCallback& callback) { 2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) content::RenderFrameHost* render_frame_host = 2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) content::RenderFrameHost::FromID(render_process_id, render_frame_id); 2735b892326406927b709cdaf6c384d4ababf456332Ben Murdoch if (!render_frame_host) return; 2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) content::RenderViewHost* render_view_host = 2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) render_frame_host->GetRenderViewHost(); 2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DCHECK(render_view_host); 2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CHECK_EQ(0, render_view_host->GetEnabledBindings()); 2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 279cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (kViewerCssPath == path) { 280a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::string css = viewer::GetCss(); 2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) callback.Run(base::RefCountedString::TakeString(&css)); 2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return; 2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 284cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (kViewerJsPath == path) { 285cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) std::string js = viewer::GetJavaScript(); 286cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) callback.Run(base::RefCountedString::TakeString(&js)); 287cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return; 288cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 2891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci if (kViewerViewOriginalPath == path) { 2901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci content::RecordAction(base::UserMetricsAction("DomDistiller_ViewOriginal")); 2911320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci callback.Run(NULL); 2921320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci return; 2931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci } 294cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) content::WebContents* web_contents = 2955b892326406927b709cdaf6c384d4ababf456332Ben Murdoch content::WebContents::FromRenderFrameHost(render_frame_host); 296cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) DCHECK(web_contents); 297cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // An empty |path| is invalid, but guard against it. If not empty, assume 298cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) // |path| starts with '?', which is stripped away. 299cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) const std::string path_after_query_separator = 300cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) path.size() > 0 ? path.substr(1) : ""; 301cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) RequestViewerHandle* request_viewer_handle = new RequestViewerHandle( 302116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch web_contents, scheme_, path_after_query_separator, callback, 303116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch dom_distiller_service_->GetDistilledPagePrefs()); 304a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch scoped_ptr<ViewerHandle> viewer_handle = viewer::CreateViewRequest( 3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) dom_distiller_service_, path, request_viewer_handle, 3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) web_contents->GetContainerBounds().size()); 307a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (viewer_handle) { 3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The service returned a |ViewerHandle| and guarantees it will call 3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // the |RequestViewerHandle|, so passing ownership to it, to ensure the 3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // request is not cancelled. The |RequestViewerHandle| will delete itself 3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // after receiving the callback. 3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request_viewer_handle->TakeViewerHandle(viewer_handle.Pass()); 3145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } else { 3155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // The service did not return a |ViewerHandle|, which means the 3165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // |RequestViewerHandle| will never be called, so clean up now. 3175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delete request_viewer_handle; 3185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 319116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch std::string error_page_html = viewer::GetErrorPageHtml( 3206e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) dom_distiller_service_->GetDistilledPagePrefs()->GetTheme(), 3216e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) dom_distiller_service_->GetDistilledPagePrefs()->GetFontFamily()); 322a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch callback.Run(base::RefCountedString::TakeString(&error_page_html)); 3235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 3245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}; 3255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)std::string DomDistillerViewerSource::GetMimeType( 327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) const std::string& path) const { 328cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (kViewerCssPath == path) { 3295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return "text/css"; 330cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) if (kViewerJsPath == path) { 332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) return "text/javascript"; 333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) } 3345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return "text/html"; 3355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool DomDistillerViewerSource::ShouldServiceRequest( 3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const net::URLRequest* request) const { 3395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return request->url().SchemeIs(scheme_.c_str()); 3405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 3415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 342a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// TODO(nyquist): Start tracking requests using this method. 3435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void DomDistillerViewerSource::WillServiceRequest( 3445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const net::URLRequest* request, 345a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch std::string* path) const { 346a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch} 3475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 3485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::string DomDistillerViewerSource::GetContentSecurityPolicyObjectSrc() 3495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const { 3506e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles) return "object-src 'none'; style-src 'self' https://fonts.googleapis.com;"; 351a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)} 352a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) 3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} // namespace dom_distiller 354