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/theme_source.h" 6 7 #include "base/memory/ref_counted_memory.h" 8 #include "base/message_loop.h" 9 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/resources_util.h" 11 #include "chrome/browser/themes/theme_service.h" 12 #include "chrome/browser/themes/theme_service_factory.h" 13 #include "chrome/browser/ui/webui/ntp_resource_cache.h" 14 #include "chrome/common/url_constants.h" 15 #include "content/browser/browser_thread.h" 16 #include "googleurl/src/gurl.h" 17 #include "ui/base/resource/resource_bundle.h" 18 #include "ui/base/theme_provider.h" 19 20 // use a resource map rather than hard-coded strings. 21 static const char* kNewTabCSSPath = "css/newtab.css"; 22 static const char* kNewIncognitoTabCSSPath = "css/newincognitotab.css"; 23 24 static std::string StripQueryParams(const std::string& path) { 25 GURL path_url = GURL(std::string(chrome::kChromeUIScheme) + "://" + 26 std::string(chrome::kChromeUIThemePath) + "/" + path); 27 return path_url.path().substr(1); // path() always includes a leading '/'. 28 } 29 30 //////////////////////////////////////////////////////////////////////////////// 31 // ThemeSource, public: 32 33 ThemeSource::ThemeSource(Profile* profile) 34 : DataSource(chrome::kChromeUIThemePath, MessageLoop::current()), 35 profile_(profile->GetOriginalProfile()) { 36 css_bytes_ = profile_->GetNTPResourceCache()->GetNewTabCSS( 37 profile->IsOffTheRecord()); 38 } 39 40 ThemeSource::~ThemeSource() { 41 } 42 43 void ThemeSource::StartDataRequest(const std::string& path, 44 bool is_incognito, 45 int request_id) { 46 // Our path may include cachebuster arguments, so trim them off. 47 std::string uncached_path = StripQueryParams(path); 48 49 if (uncached_path == kNewTabCSSPath || 50 uncached_path == kNewIncognitoTabCSSPath) { 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 52 DCHECK((uncached_path == kNewTabCSSPath && !is_incognito) || 53 (uncached_path == kNewIncognitoTabCSSPath && is_incognito)); 54 55 SendResponse(request_id, css_bytes_); 56 return; 57 } else { 58 int resource_id = ResourcesUtil::GetThemeResourceId(uncached_path); 59 if (resource_id != -1) { 60 SendThemeBitmap(request_id, resource_id); 61 return; 62 } 63 } 64 // We don't have any data to send back. 65 SendResponse(request_id, NULL); 66 } 67 68 std::string ThemeSource::GetMimeType(const std::string& path) const { 69 std::string uncached_path = StripQueryParams(path); 70 71 if (uncached_path == kNewTabCSSPath || 72 uncached_path == kNewIncognitoTabCSSPath) { 73 return "text/css"; 74 } 75 76 return "image/png"; 77 } 78 79 MessageLoop* ThemeSource::MessageLoopForRequestPath( 80 const std::string& path) const { 81 std::string uncached_path = StripQueryParams(path); 82 83 if (uncached_path == kNewTabCSSPath || 84 uncached_path == kNewIncognitoTabCSSPath) { 85 // We generated and cached this when we initialized the object. We don't 86 // have to go back to the UI thread to send the data. 87 return NULL; 88 } 89 90 // If it's not a themeable image, we don't need to go to the UI thread. 91 int resource_id = ResourcesUtil::GetThemeResourceId(uncached_path); 92 if (!ThemeService::IsThemeableImage(resource_id)) 93 return NULL; 94 95 return DataSource::MessageLoopForRequestPath(path); 96 } 97 98 bool ThemeSource::ShouldReplaceExistingSource() const { 99 // We currently get the css_bytes_ in the ThemeSource constructor, so we need 100 // to recreate the source itself when a theme changes. 101 return true; 102 } 103 104 //////////////////////////////////////////////////////////////////////////////// 105 // ThemeSource, private: 106 107 void ThemeSource::SendThemeBitmap(int request_id, int resource_id) { 108 if (ThemeService::IsThemeableImage(resource_id)) { 109 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 110 ui::ThemeProvider* tp = ThemeServiceFactory::GetForProfile(profile_); 111 DCHECK(tp); 112 113 scoped_refptr<RefCountedMemory> image_data(tp->GetRawData(resource_id)); 114 SendResponse(request_id, image_data); 115 } else { 116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 117 const ResourceBundle& rb = ResourceBundle::GetSharedInstance(); 118 SendResponse(request_id, rb.LoadDataResourceBytes(resource_id)); 119 } 120 } 121