Home | History | Annotate | Download | only in webui
      1 // Copyright (c) 2011 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 "chrome/browser/ui/webui/chrome_url_data_manager.h"
      6 
      7 #include <vector>
      8 
      9 #include "base/i18n/rtl.h"
     10 #include "base/memory/ref_counted_memory.h"
     11 #include "base/message_loop.h"
     12 #include "base/string_util.h"
     13 #include "base/synchronization/lock.h"
     14 #include "base/values.h"
     15 #include "chrome/browser/net/chrome_url_request_context.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/browser/ui/webui/chrome_url_data_manager_backend.h"
     18 #include "content/browser/browser_thread.h"
     19 #include "grit/platform_locale_settings.h"
     20 #include "ui/base/l10n/l10n_util.h"
     21 
     22 #if defined(OS_WIN)
     23 #include "base/win/windows_version.h"
     24 #endif
     25 
     26 // static
     27 base::Lock ChromeURLDataManager::delete_lock_;
     28 
     29 // static
     30 ChromeURLDataManager::DataSources* ChromeURLDataManager::data_sources_ = NULL;
     31 
     32 // Invoked on the IO thread to do the actual adding of the DataSource.
     33 static void AddDataSourceOnIOThread(
     34     scoped_refptr<net::URLRequestContextGetter> context_getter,
     35     scoped_refptr<ChromeURLDataManager::DataSource> data_source) {
     36   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
     37   static_cast<ChromeURLRequestContext*>(
     38       context_getter->GetURLRequestContext())->
     39       GetChromeURLDataManagerBackend()->AddDataSource(data_source.get());
     40 }
     41 
     42 ChromeURLDataManager::ChromeURLDataManager(Profile* profile)
     43     : profile_(profile) {
     44 }
     45 
     46 ChromeURLDataManager::~ChromeURLDataManager() {
     47 }
     48 
     49 void ChromeURLDataManager::AddDataSource(DataSource* source) {
     50   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     51   BrowserThread::PostTask(
     52       BrowserThread::IO, FROM_HERE,
     53       NewRunnableFunction(AddDataSourceOnIOThread,
     54                           make_scoped_refptr(profile_->GetRequestContext()),
     55                           make_scoped_refptr(source)));
     56 }
     57 
     58 // static
     59 void ChromeURLDataManager::DeleteDataSources() {
     60   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
     61   DataSources sources;
     62   {
     63     base::AutoLock lock(delete_lock_);
     64     if (!data_sources_)
     65       return;
     66     data_sources_->swap(sources);
     67   }
     68   for (size_t i = 0; i < sources.size(); ++i)
     69     delete sources[i];
     70 }
     71 
     72 // static
     73 void ChromeURLDataManager::DeleteDataSource(const DataSource* data_source) {
     74   // Invoked when a DataSource is no longer referenced and needs to be deleted.
     75   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
     76     // We're on the UI thread, delete right away.
     77     delete data_source;
     78     return;
     79   }
     80 
     81   // We're not on the UI thread, add the DataSource to the list of DataSources
     82   // to delete.
     83   bool schedule_delete = false;
     84   {
     85     base::AutoLock lock(delete_lock_);
     86     if (!data_sources_)
     87       data_sources_ = new DataSources();
     88     schedule_delete = data_sources_->empty();
     89     data_sources_->push_back(data_source);
     90   }
     91   if (schedule_delete) {
     92     // Schedule a task to delete the DataSource back on the UI thread.
     93     BrowserThread::PostTask(BrowserThread::UI,
     94                             FROM_HERE,
     95                             NewRunnableFunction(
     96                                 &ChromeURLDataManager::DeleteDataSources));
     97   }
     98 }
     99 
    100 // static
    101 bool ChromeURLDataManager::IsScheduledForDeletion(
    102     const DataSource* data_source) {
    103   base::AutoLock lock(delete_lock_);
    104   if (!data_sources_)
    105     return false;
    106   return std::find(data_sources_->begin(), data_sources_->end(), data_source) !=
    107       data_sources_->end();
    108 }
    109 
    110 ChromeURLDataManager::DataSource::DataSource(const std::string& source_name,
    111                                              MessageLoop* message_loop)
    112     : source_name_(source_name),
    113       message_loop_(message_loop),
    114       backend_(NULL) {
    115 }
    116 
    117 ChromeURLDataManager::DataSource::~DataSource() {
    118 }
    119 
    120 void ChromeURLDataManager::DataSource::SendResponse(int request_id,
    121                                                     RefCountedMemory* bytes) {
    122   if (IsScheduledForDeletion(this)) {
    123     // We're scheduled for deletion. Servicing the request would result in
    124     // this->AddRef being invoked, even though the ref count is 0 and 'this' is
    125     // about to be deleted. If the AddRef were allowed through, when 'this' is
    126     // released it would be deleted again.
    127     //
    128     // This scenario occurs with DataSources that make history requests. Such
    129     // DataSources do a history query in |StartDataRequest| and the request is
    130     // live until the object is deleted (history requests don't up the ref
    131     // count). This means it's entirely possible for the DataSource to invoke
    132     // |SendResponse| between the time when there are no more refs and the time
    133     // when the object is deleted.
    134     return;
    135   }
    136   BrowserThread::PostTask(
    137       BrowserThread::IO, FROM_HERE,
    138       NewRunnableMethod(this, &DataSource::SendResponseOnIOThread,
    139                         request_id, make_scoped_refptr(bytes)));
    140 }
    141 
    142 MessageLoop* ChromeURLDataManager::DataSource::MessageLoopForRequestPath(
    143     const std::string& path) const {
    144   return message_loop_;
    145 }
    146 
    147 bool ChromeURLDataManager::DataSource::ShouldReplaceExistingSource() const {
    148   return true;
    149 }
    150 
    151 // static
    152 void ChromeURLDataManager::DataSource::SetFontAndTextDirection(
    153     DictionaryValue* localized_strings) {
    154   localized_strings->SetString("fontfamily",
    155       l10n_util::GetStringUTF16(IDS_WEB_FONT_FAMILY));
    156 
    157   int web_font_size_id = IDS_WEB_FONT_SIZE;
    158 #if defined(OS_WIN)
    159   // Some fonts used for some languages changed a lot in terms of the font
    160   // metric in Vista. So, we need to use different size before Vista.
    161   if (base::win::GetVersion() < base::win::VERSION_VISTA)
    162     web_font_size_id = IDS_WEB_FONT_SIZE_XP;
    163 #endif
    164   localized_strings->SetString("fontsize",
    165       l10n_util::GetStringUTF16(web_font_size_id));
    166 
    167   localized_strings->SetString("textdirection",
    168       base::i18n::IsRTL() ? "rtl" : "ltr");
    169 }
    170 
    171 void ChromeURLDataManager::DataSource::SendResponseOnIOThread(
    172     int request_id,
    173     scoped_refptr<RefCountedMemory> bytes) {
    174   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
    175   if (backend_)
    176     backend_->DataAvailable(request_id, bytes);
    177 }
    178