| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/ui/webui/theme_source.h" | 5 #include "chrome/browser/ui/webui/theme_source.h" |
| 6 | 6 |
| 7 #include "base/memory/ref_counted_memory.h" | 7 #include "base/memory/ref_counted_memory.h" |
| 8 #include "base/message_loop/message_loop.h" | 8 #include "base/message_loop/message_loop.h" |
| 9 #include "base/strings/string_number_conversions.h" | 9 #include "base/strings/string_number_conversions.h" |
| 10 #include "chrome/browser/profiles/profile.h" | 10 #include "chrome/browser/profiles/profile.h" |
| (...skipping 12 matching lines...) Expand all Loading... |
| 23 #include "grit/theme_resources.h" | 23 #include "grit/theme_resources.h" |
| 24 #include "net/url_request/url_request.h" | 24 #include "net/url_request/url_request.h" |
| 25 #include "ui/base/layout.h" | 25 #include "ui/base/layout.h" |
| 26 #include "ui/base/resource/resource_bundle.h" | 26 #include "ui/base/resource/resource_bundle.h" |
| 27 #include "ui/base/webui/web_ui_util.h" | 27 #include "ui/base/webui/web_ui_util.h" |
| 28 #include "ui/gfx/codec/png_codec.h" | 28 #include "ui/gfx/codec/png_codec.h" |
| 29 #include "ui/gfx/image/image_skia.h" | 29 #include "ui/gfx/image/image_skia.h" |
| 30 #include "ui/gfx/image/image_skia_rep.h" | 30 #include "ui/gfx/image/image_skia_rep.h" |
| 31 #include "url/gurl.h" | 31 #include "url/gurl.h" |
| 32 | 32 |
| 33 using content::BrowserThread; | |
| 34 | |
| 35 namespace { | 33 namespace { |
| 36 | 34 |
| 37 GURL GetThemePath(const std::string& path) { | 35 GURL GetThemeURL(const std::string& path) { |
| 38 return GURL(std::string(content::kChromeUIScheme) + "://" + | 36 return GURL(std::string(content::kChromeUIScheme) + "://" + |
| 39 std::string(chrome::kChromeUIThemeHost) + "/" + path); | 37 std::string(chrome::kChromeUIThemeHost) + "/" + path); |
| 40 } | 38 } |
| 41 | 39 |
| 42 // use a resource map rather than hard-coded strings. | 40 bool IsNewTabCSSPath(const std::string& path) { |
| 43 static const char* kNewTabCSSPath = "css/new_tab_theme.css"; | 41 static const char kNewTabCSSPath[] = "css/new_tab_theme.css"; |
| 44 static const char* kNewIncognitoTabCSSPath = "css/incognito_new_tab_theme.css"; | 42 static const char kIncognitoNewTabCSSPath[] = |
| 43 "css/incognito_new_tab_theme.css"; |
| 44 return (path == kNewTabCSSPath) || (path == kIncognitoNewTabCSSPath); |
| 45 } |
| 45 | 46 |
| 46 void ProcessImageOnUIThread(const gfx::ImageSkia& image, | 47 void ProcessImageOnUIThread(const gfx::ImageSkia& image, |
| 47 float scale_factor, | 48 float scale, |
| 48 scoped_refptr<base::RefCountedBytes> data) { | 49 scoped_refptr<base::RefCountedBytes> data) { |
| 49 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 50 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 50 const gfx::ImageSkiaRep& rep = image.GetRepresentation(scale_factor); | 51 const gfx::ImageSkiaRep& rep = image.GetRepresentation(scale); |
| 51 gfx::PNGCodec::EncodeBGRASkBitmap( | 52 gfx::PNGCodec::EncodeBGRASkBitmap( |
| 52 rep.sk_bitmap(), false /* discard transparency */, &data->data()); | 53 rep.sk_bitmap(), false /* discard transparency */, &data->data()); |
| 53 } | 54 } |
| 54 | 55 |
| 55 void ProcessResourceOnUIThread(int resource_id, | 56 void ProcessResourceOnUIThread(int resource_id, |
| 56 float scale_factor, | 57 float scale, |
| 57 scoped_refptr<base::RefCountedBytes> data) { | 58 scoped_refptr<base::RefCountedBytes> data) { |
| 58 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 59 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 59 ProcessImageOnUIThread( | 60 ProcessImageOnUIThread( |
| 60 *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id), | 61 *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id), |
| 61 scale_factor, data); | 62 scale, data); |
| 62 } | 63 } |
| 63 | 64 |
| 64 } // namespace | 65 } // namespace |
| 65 | 66 |
| 66 //////////////////////////////////////////////////////////////////////////////// | 67 //////////////////////////////////////////////////////////////////////////////// |
| 67 // ThemeSource, public: | 68 // ThemeSource, public: |
| 68 | 69 |
| 69 ThemeSource::ThemeSource(Profile* profile) | 70 ThemeSource::ThemeSource(Profile* profile) |
| 70 : profile_(profile->GetOriginalProfile()) { | 71 : profile_(profile->GetOriginalProfile()) { |
| 71 // NB: it's important that this is |profile| and not |profile_|. | 72 // NB: it's important that this is |profile| and not |profile_|. |
| 72 NTPResourceCache::WindowType win_type = NTPResourceCache::GetWindowType( | 73 NTPResourceCache::WindowType win_type = NTPResourceCache::GetWindowType( |
| 73 profile, NULL); | 74 profile, nullptr); |
| 74 css_bytes_ = | 75 css_bytes_ = |
| 75 NTPResourceCacheFactory::GetForProfile(profile)->GetNewTabCSS(win_type); | 76 NTPResourceCacheFactory::GetForProfile(profile)->GetNewTabCSS(win_type); |
| 76 } | 77 } |
| 77 | 78 |
| 78 ThemeSource::~ThemeSource() { | 79 ThemeSource::~ThemeSource() { |
| 79 } | 80 } |
| 80 | 81 |
| 81 std::string ThemeSource::GetSource() const { | 82 std::string ThemeSource::GetSource() const { |
| 82 return chrome::kChromeUIThemeHost; | 83 return chrome::kChromeUIThemeHost; |
| 83 } | 84 } |
| 84 | 85 |
| 85 void ThemeSource::StartDataRequest( | 86 void ThemeSource::StartDataRequest( |
| 86 const std::string& path, | 87 const std::string& path, |
| 87 int render_process_id, | 88 int render_process_id, |
| 88 int render_frame_id, | 89 int render_frame_id, |
| 89 const content::URLDataSource::GotDataCallback& callback) { | 90 const content::URLDataSource::GotDataCallback& callback) { |
| 90 // Default scale factor if not specified. | 91 // Default scale factor if not specified. |
| 91 float scale_factor = 1.0f; | 92 float scale = 1.0f; |
| 92 std::string uncached_path; | 93 std::string parsed_path; |
| 93 webui::ParsePathAndScale(GetThemePath(path), &uncached_path, &scale_factor); | 94 webui::ParsePathAndScale(GetThemeURL(path), &parsed_path, &scale); |
| 94 scale_factor = | |
| 95 ui::GetScaleForScaleFactor(ui::GetSupportedScaleFactor(scale_factor)); | |
| 96 | 95 |
| 97 if (uncached_path == kNewTabCSSPath || | 96 if (IsNewTabCSSPath(parsed_path)) { |
| 98 uncached_path == kNewIncognitoTabCSSPath) { | 97 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 99 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
| 100 | |
| 101 callback.Run(css_bytes_.get()); | 98 callback.Run(css_bytes_.get()); |
| 102 return; | 99 return; |
| 103 } | 100 } |
| 104 | 101 |
| 105 int resource_id = -1; | 102 int resource_id = -1; |
| 106 if (uncached_path == "current-channel-logo") { | 103 if (parsed_path == "current-channel-logo") { |
| 107 switch (chrome::GetChannel()) { | 104 switch (chrome::GetChannel()) { |
| 108 #if defined(GOOGLE_CHROME_BUILD) | 105 #if defined(GOOGLE_CHROME_BUILD) |
| 109 case version_info::Channel::CANARY: | 106 case version_info::Channel::CANARY: |
| 110 resource_id = IDR_PRODUCT_LOGO_32_CANARY; | 107 resource_id = IDR_PRODUCT_LOGO_32_CANARY; |
| 111 break; | 108 break; |
| 112 case version_info::Channel::DEV: | 109 case version_info::Channel::DEV: |
| 113 resource_id = IDR_PRODUCT_LOGO_32_DEV; | 110 resource_id = IDR_PRODUCT_LOGO_32_DEV; |
| 114 break; | 111 break; |
| 115 case version_info::Channel::BETA: | 112 case version_info::Channel::BETA: |
| 116 resource_id = IDR_PRODUCT_LOGO_32_BETA; | 113 resource_id = IDR_PRODUCT_LOGO_32_BETA; |
| 117 break; | 114 break; |
| 118 case version_info::Channel::STABLE: | 115 case version_info::Channel::STABLE: |
| 119 resource_id = IDR_PRODUCT_LOGO_32; | 116 resource_id = IDR_PRODUCT_LOGO_32; |
| 120 break; | 117 break; |
| 121 #else | 118 #else |
| 122 case version_info::Channel::CANARY: | 119 case version_info::Channel::CANARY: |
| 123 case version_info::Channel::DEV: | 120 case version_info::Channel::DEV: |
| 124 case version_info::Channel::BETA: | 121 case version_info::Channel::BETA: |
| 125 case version_info::Channel::STABLE: | 122 case version_info::Channel::STABLE: |
| 126 NOTREACHED(); | 123 NOTREACHED(); |
| 127 #endif | 124 #endif |
| 128 case version_info::Channel::UNKNOWN: | 125 case version_info::Channel::UNKNOWN: |
| 129 resource_id = IDR_PRODUCT_LOGO_32; | 126 resource_id = IDR_PRODUCT_LOGO_32; |
| 130 break; | 127 break; |
| 131 } | 128 } |
| 132 } else { | 129 } else { |
| 133 resource_id = ResourcesUtil::GetThemeResourceId(uncached_path); | 130 resource_id = ResourcesUtil::GetThemeResourceId(parsed_path); |
| 134 } | |
| 135 if (resource_id != -1) { | |
| 136 if (GetMimeType(path) == "image/png") | |
| 137 SendThemeImage(callback, resource_id, scale_factor); | |
| 138 else | |
| 139 SendThemeBitmap(callback, resource_id, scale_factor); | |
| 140 return; | |
| 141 } | 131 } |
| 142 | 132 |
| 143 // We don't have any data to send back. This shouldn't happen normally, as | 133 if (resource_id == -1) { |
| 144 // chrome://theme/ data source is used only by chrome WebUI pages and | 134 // We don't have any data to send back. This shouldn't happen normally, as |
| 145 // component extensions. We don't want to crash in Release build though, as | 135 // chrome://theme/ data source is used only by chrome WebUI pages and |
| 146 // it is possible that a user has entered an unexisting chrome://theme URL | 136 // component extensions. We don't want to crash in Release build though, as |
| 147 // into the address bar. | 137 // it is possible that a user has entered an unexisting chrome://theme URL |
| 148 NOTREACHED() << path << " not found."; | 138 // into the address bar. |
| 149 callback.Run(NULL); | 139 callback.Run(nullptr); |
| 140 } else if (GetMimeType(path) == "image/png") { |
| 141 SendThemeImage(callback, resource_id, scale); |
| 142 } else { |
| 143 SendThemeBitmap(callback, resource_id, scale); |
| 144 } |
| 150 } | 145 } |
| 151 | 146 |
| 152 std::string ThemeSource::GetMimeType(const std::string& path) const { | 147 std::string ThemeSource::GetMimeType(const std::string& path) const { |
| 153 std::string uncached_path; | 148 std::string parsed_path; |
| 154 webui::ParsePathAndScale(GetThemePath(path), &uncached_path, NULL); | 149 webui::ParsePathAndScale(GetThemeURL(path), &parsed_path, nullptr); |
| 155 | 150 return IsNewTabCSSPath(parsed_path) ? "text/css" : "image/png"; |
| 156 if (uncached_path == kNewTabCSSPath || | |
| 157 uncached_path == kNewIncognitoTabCSSPath) { | |
| 158 return "text/css"; | |
| 159 } | |
| 160 | |
| 161 return "image/png"; | |
| 162 } | 151 } |
| 163 | 152 |
| 164 base::MessageLoop* ThemeSource::MessageLoopForRequestPath( | 153 base::MessageLoop* ThemeSource::MessageLoopForRequestPath( |
| 165 const std::string& path) const { | 154 const std::string& path) const { |
| 166 std::string uncached_path; | 155 std::string parsed_path; |
| 167 webui::ParsePathAndScale(GetThemePath(path), &uncached_path, NULL); | 156 webui::ParsePathAndScale(GetThemeURL(path), &parsed_path, nullptr); |
| 168 | 157 |
| 169 if (uncached_path == kNewTabCSSPath || | 158 if (IsNewTabCSSPath(parsed_path)) { |
| 170 uncached_path == kNewIncognitoTabCSSPath) { | |
| 171 // We generated and cached this when we initialized the object. We don't | 159 // We generated and cached this when we initialized the object. We don't |
| 172 // have to go back to the UI thread to send the data. | 160 // have to go back to the UI thread to send the data. |
| 173 return NULL; | 161 return nullptr; |
| 174 } | 162 } |
| 175 | 163 |
| 176 // If it's not a themeable image, we don't need to go to the UI thread. | 164 // If it's not a themeable image, we don't need to go to the UI thread. |
| 177 int resource_id = ResourcesUtil::GetThemeResourceId(uncached_path); | 165 int resource_id = ResourcesUtil::GetThemeResourceId(parsed_path); |
| 178 if (!BrowserThemePack::IsPersistentImageID(resource_id)) | 166 return BrowserThemePack::IsPersistentImageID(resource_id) ? |
| 179 return NULL; | 167 content::URLDataSource::MessageLoopForRequestPath(path) : nullptr; |
| 180 | |
| 181 return content::URLDataSource::MessageLoopForRequestPath(path); | |
| 182 } | 168 } |
| 183 | 169 |
| 184 bool ThemeSource::ShouldReplaceExistingSource() const { | 170 bool ThemeSource::ShouldReplaceExistingSource() const { |
| 185 // We currently get the css_bytes_ in the ThemeSource constructor, so we need | 171 // We currently get the css_bytes_ in the ThemeSource constructor, so we need |
| 186 // to recreate the source itself when a theme changes. | 172 // to recreate the source itself when a theme changes. |
| 187 return true; | 173 return true; |
| 188 } | 174 } |
| 189 | 175 |
| 190 bool ThemeSource::ShouldServiceRequest(const net::URLRequest* request) const { | 176 bool ThemeSource::ShouldServiceRequest(const net::URLRequest* request) const { |
| 191 if (request->url().SchemeIs(chrome::kChromeSearchScheme)) | 177 return request->url().SchemeIs(chrome::kChromeSearchScheme) ? |
| 192 return InstantIOContext::ShouldServiceRequest(request); | 178 InstantIOContext::ShouldServiceRequest(request) : |
| 193 return URLDataSource::ShouldServiceRequest(request); | 179 URLDataSource::ShouldServiceRequest(request); |
| 194 } | 180 } |
| 195 | 181 |
| 196 //////////////////////////////////////////////////////////////////////////////// | 182 //////////////////////////////////////////////////////////////////////////////// |
| 197 // ThemeSource, private: | 183 // ThemeSource, private: |
| 198 | 184 |
| 199 void ThemeSource::SendThemeBitmap( | 185 void ThemeSource::SendThemeBitmap( |
| 200 const content::URLDataSource::GotDataCallback& callback, | 186 const content::URLDataSource::GotDataCallback& callback, |
| 201 int resource_id, | 187 int resource_id, |
| 202 float scale_factor) { | 188 float scale) { |
| 203 ui::ScaleFactor resource_scale_factor = | 189 ui::ScaleFactor scale_factor = ui::GetSupportedScaleFactor(scale); |
| 204 ui::GetSupportedScaleFactor(scale_factor); | |
| 205 if (BrowserThemePack::IsPersistentImageID(resource_id)) { | 190 if (BrowserThemePack::IsPersistentImageID(resource_id)) { |
| 206 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 191 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 207 const ui::ThemeProvider& tp = | |
| 208 ThemeService::GetThemeProviderForProfile(profile_); | |
| 209 | |
| 210 scoped_refptr<base::RefCountedMemory> image_data( | 192 scoped_refptr<base::RefCountedMemory> image_data( |
| 211 tp.GetRawData(resource_id, resource_scale_factor)); | 193 ThemeService::GetThemeProviderForProfile(profile_).GetRawData( |
| 194 resource_id, scale_factor)); |
| 212 callback.Run(image_data.get()); | 195 callback.Run(image_data.get()); |
| 213 } else { | 196 } else { |
| 214 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 197 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 215 const ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 198 const ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 216 callback.Run( | 199 callback.Run(rb.LoadDataResourceBytesForScale(resource_id, scale_factor)); |
| 217 rb.LoadDataResourceBytesForScale(resource_id, resource_scale_factor)); | |
| 218 } | 200 } |
| 219 } | 201 } |
| 220 | 202 |
| 221 void ThemeSource::SendThemeImage( | 203 void ThemeSource::SendThemeImage( |
| 222 const content::URLDataSource::GotDataCallback& callback, | 204 const content::URLDataSource::GotDataCallback& callback, |
| 223 int resource_id, | 205 int resource_id, |
| 224 float scale_factor) { | 206 float scale) { |
| 225 // If the resource bundle contains the data pack for |scale_factor|, we can | 207 // If the resource bundle contains the data pack for |scale_factor|, we can |
| 226 // safely fallback to SendThemeBitmap(). | 208 // safely fallback to SendThemeBitmap(). |
| 227 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); | 209 ResourceBundle& rb = ResourceBundle::GetSharedInstance(); |
| 228 if (ui::GetScaleForScaleFactor(rb.GetMaxScaleFactor()) >= scale_factor) { | 210 if (ui::GetScaleForScaleFactor(rb.GetMaxScaleFactor()) >= scale) { |
| 229 SendThemeBitmap(callback, resource_id, scale_factor); | 211 SendThemeBitmap(callback, resource_id, scale); |
| 230 return; | 212 return; |
| 231 } | 213 } |
| 232 | 214 |
| 233 // Otherwise, we should use gfx::ImageSkia to obtain the data. ImageSkia can | 215 // Otherwise, we should use gfx::ImageSkia to obtain the data. ImageSkia can |
| 234 // rescale the bitmap if its backend doesn't contain the representation for | 216 // rescale the bitmap if its backend doesn't contain the representation for |
| 235 // the specified scale factor. This is the fallback path in case chrome is | 217 // the specified scale factor. This is the fallback path in case chrome is |
| 236 // shipped without 2x resource pack but needs to use HighDPI display, which | 218 // shipped without 2x resource pack but needs to use HighDPI display, which |
| 237 // can happen in ChromeOS or Linux. | 219 // can happen in ChromeOS or Linux. |
| 238 scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes()); | 220 scoped_refptr<base::RefCountedBytes> data(new base::RefCountedBytes()); |
| 239 if (BrowserThemePack::IsPersistentImageID(resource_id)) { | 221 if (BrowserThemePack::IsPersistentImageID(resource_id)) { |
| 240 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 222 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| 241 const ui::ThemeProvider& tp = | 223 const ui::ThemeProvider& tp = |
| 242 ThemeService::GetThemeProviderForProfile(profile_); | 224 ThemeService::GetThemeProviderForProfile(profile_); |
| 243 ProcessImageOnUIThread(*tp.GetImageSkiaNamed(resource_id), scale_factor, | 225 ProcessImageOnUIThread(*tp.GetImageSkiaNamed(resource_id), scale, data); |
| 244 data); | |
| 245 callback.Run(data.get()); | 226 callback.Run(data.get()); |
| 246 } else { | 227 } else { |
| 247 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 228 DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| 248 // Fetching image data in ResourceBundle should happen on the UI thread. See | 229 // Fetching image data in ResourceBundle should happen on the UI thread. See |
| 249 // crbug.com/449277 | 230 // crbug.com/449277 |
| 250 content::BrowserThread::PostTaskAndReply( | 231 content::BrowserThread::PostTaskAndReply( |
| 251 content::BrowserThread::UI, FROM_HERE, | 232 content::BrowserThread::UI, FROM_HERE, |
| 252 base::Bind(&ProcessResourceOnUIThread, resource_id, scale_factor, data), | 233 base::Bind(&ProcessResourceOnUIThread, resource_id, scale, data), |
| 253 base::Bind(callback, data)); | 234 base::Bind(callback, data)); |
| 254 } | 235 } |
| 255 } | 236 } |
| OLD | NEW |