Home | History | Annotate | Download | only in core
      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 
     21 namespace dom_distiller {
     22 
     23 namespace {
     24 
     25 const char* kOptionsPlaceholder = "$$OPTIONS";
     26 
     27 std::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 
     53 DistillerPageFactory::~DistillerPageFactory() {}
     54 
     55 DistillerPage::DistillerPage() : ready_(true) {}
     56 
     57 DistillerPage::~DistillerPage() {}
     58 
     59 void 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 
     71 void 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