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. 4 5#include "components/dom_distiller/core/distiller_page.h" 6 7#include "base/bind.h" 8#include "base/json/json_writer.h" 9#include "base/logging.h" 10#include "base/message_loop/message_loop.h" 11#include "base/metrics/histogram.h" 12#include "base/strings/string_util.h" 13#include "base/strings/utf_string_conversions.h" 14#include "base/time/time.h" 15#include "grit/components_resources.h" 16#include "third_party/dom_distiller_js/dom_distiller.pb.h" 17#include "third_party/dom_distiller_js/dom_distiller_json_converter.h" 18#include "ui/base/resource/resource_bundle.h" 19#include "url/gurl.h" 20 21namespace dom_distiller { 22 23namespace { 24 25const char* kOptionsPlaceholder = "$$OPTIONS"; 26 27std::string GetDistillerScriptWithOptions( 28 const dom_distiller::proto::DomDistillerOptions& options) { 29 std::string script = ResourceBundle::GetSharedInstance() 30 .GetRawDataResource(IDR_DISTILLER_JS) 31 .as_string(); 32 if (script.empty()) { 33 return ""; 34 } 35 36 scoped_ptr<base::Value> options_value( 37 dom_distiller::proto::json::DomDistillerOptions::WriteToValue(options)); 38 std::string options_json; 39 if (!base::JSONWriter::Write(options_value.get(), &options_json)) { 40 NOTREACHED(); 41 } 42 size_t options_offset = script.find(kOptionsPlaceholder); 43 DCHECK_NE(std::string::npos, options_offset); 44 DCHECK_EQ(std::string::npos, 45 script.find(kOptionsPlaceholder, options_offset + 1)); 46 script = 47 script.replace(options_offset, strlen(kOptionsPlaceholder), options_json); 48 return script; 49} 50 51} 52 53DistillerPageFactory::~DistillerPageFactory() {} 54 55DistillerPage::DistillerPage() : ready_(true) {} 56 57DistillerPage::~DistillerPage() {} 58 59void DistillerPage::DistillPage( 60 const GURL& gurl, 61 const dom_distiller::proto::DomDistillerOptions options, 62 const DistillerPageCallback& callback) { 63 DCHECK(ready_); 64 // It is only possible to distill one page at a time. |ready_| is reset when 65 // the callback to OnDistillationDone happens. 66 ready_ = false; 67 distiller_page_callback_ = callback; 68 DistillPageImpl(gurl, GetDistillerScriptWithOptions(options)); 69} 70 71void DistillerPage::OnDistillationDone(const GURL& page_url, 72 const base::Value* value) { 73 DCHECK(!ready_); 74 ready_ = true; 75 76 scoped_ptr<dom_distiller::proto::DomDistillerResult> distiller_result( 77 new dom_distiller::proto::DomDistillerResult()); 78 bool found_content; 79 if (value->IsType(base::Value::TYPE_NULL)) { 80 found_content = false; 81 } else { 82 found_content = 83 dom_distiller::proto::json::DomDistillerResult::ReadFromValue( 84 value, distiller_result.get()); 85 if (!found_content) { 86 DVLOG(1) << "Unable to parse DomDistillerResult."; 87 } else { 88 if (distiller_result->has_timing_info()) { 89 const dom_distiller::proto::TimingInfo& timing = 90 distiller_result->timing_info(); 91 if (timing.has_markup_parsing_time()) { 92 UMA_HISTOGRAM_TIMES( 93 "DomDistiller.Time.MarkupParsing", 94 base::TimeDelta::FromMillisecondsD(timing.markup_parsing_time())); 95 } 96 if (timing.has_document_construction_time()) { 97 UMA_HISTOGRAM_TIMES( 98 "DomDistiller.Time.DocumentConstruction", 99 base::TimeDelta::FromMillisecondsD( 100 timing.document_construction_time())); 101 } 102 if (timing.has_article_processing_time()) { 103 UMA_HISTOGRAM_TIMES( 104 "DomDistiller.Time.ArticleProcessing", 105 base::TimeDelta::FromMillisecondsD( 106 timing.article_processing_time())); 107 } 108 if (timing.has_formatting_time()) { 109 UMA_HISTOGRAM_TIMES( 110 "DomDistiller.Time.Formatting", 111 base::TimeDelta::FromMillisecondsD(timing.formatting_time())); 112 } 113 if (timing.has_total_time()) { 114 UMA_HISTOGRAM_TIMES( 115 "DomDistiller.Time.DistillationTotal", 116 base::TimeDelta::FromMillisecondsD(timing.total_time())); 117 } 118 } 119 if (distiller_result->has_statistics_info()) { 120 const dom_distiller::proto::StatisticsInfo& statistics = 121 distiller_result->statistics_info(); 122 if (statistics.has_word_count()) { 123 UMA_HISTOGRAM_CUSTOM_COUNTS( 124 "DomDistiller.Statistics.WordCount", 125 statistics.word_count(), 126 1, 4000, 50); 127 } 128 } 129 } 130 } 131 132 base::MessageLoop::current()->PostTask( 133 FROM_HERE, 134 base::Bind(distiller_page_callback_, 135 base::Passed(&distiller_result), 136 found_content)); 137} 138 139} // namespace dom_distiller 140