| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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 "base/json/json_parser.h" | |
| 6 #include "base/strings/utf_string_conversions.h" | |
| 7 #include "base/values.h" | |
| 8 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher.h" | |
| 9 #include "chrome/browser/enhanced_bookmarks/android/bookmark_image_service_andro
id.h" | |
| 10 #include "chrome/browser/enhanced_bookmarks/enhanced_bookmark_model_factory.h" | |
| 11 #include "chrome/common/chrome_isolated_world_ids.h" | |
| 12 #include "chrome/grit/browser_resources.h" | |
| 13 #include "components/bookmarks/browser/bookmark_model.h" | |
| 14 #include "components/enhanced_bookmarks/enhanced_bookmark_model.h" | |
| 15 #include "content/public/browser/browser_context.h" | |
| 16 #include "content/public/browser/browser_thread.h" | |
| 17 #include "content/public/browser/navigation_entry.h" | |
| 18 #include "content/public/browser/render_frame_host.h" | |
| 19 #include "content/public/browser/web_contents.h" | |
| 20 #include "grit/enhanced_bookmarks_resources.h" | |
| 21 #include "net/base/load_flags.h" | |
| 22 #include "skia/ext/image_operations.h" | |
| 23 #include "ui/base/device_form_factor.h" | |
| 24 #include "ui/base/resource/resource_bundle.h" | |
| 25 #include "ui/gfx/android/device_display_info.h" | |
| 26 #include "ui/gfx/image/image_skia.h" | |
| 27 | |
| 28 using content::Referrer; | |
| 29 using bookmarks::BookmarkNode; | |
| 30 | |
| 31 namespace enhanced_bookmarks { | |
| 32 | |
| 33 BookmarkImageServiceAndroid::BookmarkImageServiceAndroid( | |
| 34 content::BrowserContext* browserContext) | |
| 35 : BookmarkImageService( | |
| 36 browserContext->GetPath(), | |
| 37 EnhancedBookmarkModelFactory::GetForBrowserContext(browserContext), | |
| 38 make_scoped_refptr(content::BrowserThread::GetBlockingPool())), | |
| 39 browser_context_(browserContext) { | |
| 40 // The images we're saving will be used locally. So it's wasteful to store | |
| 41 // images larger than the device resolution. | |
| 42 gfx::DeviceDisplayInfo display_info; | |
| 43 int max_length = std::min(display_info.GetPhysicalDisplayWidth(), | |
| 44 display_info.GetPhysicalDisplayHeight()); | |
| 45 // GetPhysicalDisplay*() returns 0 for pre-JB MR1. If so, fall back to the | |
| 46 // second best option we have. | |
| 47 if (max_length == 0) { | |
| 48 max_length = std::min(display_info.GetDisplayWidth(), | |
| 49 display_info.GetDisplayHeight()); | |
| 50 } | |
| 51 | |
| 52 if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) { | |
| 53 max_length = max_length / 2; | |
| 54 } else if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_PHONE) { | |
| 55 max_length = max_length * 3 / 4; | |
| 56 } | |
| 57 | |
| 58 DCHECK(max_length > 0); | |
| 59 max_size_.set_height(max_length); | |
| 60 max_size_.set_width(max_length); | |
| 61 } | |
| 62 | |
| 63 BookmarkImageServiceAndroid::~BookmarkImageServiceAndroid() { | |
| 64 } | |
| 65 | |
| 66 void BookmarkImageServiceAndroid::RetrieveSalientImage( | |
| 67 const GURL& page_url, | |
| 68 const GURL& image_url, | |
| 69 const std::string& referrer, | |
| 70 net::URLRequest::ReferrerPolicy referrer_policy, | |
| 71 bool update_bookmark) { | |
| 72 const BookmarkNode* bookmark = | |
| 73 enhanced_bookmark_model_->bookmark_model() | |
| 74 ->GetMostRecentlyAddedUserNodeForURL(page_url); | |
| 75 if (!bookmark || !image_url.is_valid()) { | |
| 76 ProcessNewImage(page_url, update_bookmark, image_url, | |
| 77 scoped_ptr<gfx::Image>(new gfx::Image())); | |
| 78 return; | |
| 79 } | |
| 80 | |
| 81 BitmapFetcherHandler* bitmap_fetcher_handler = | |
| 82 new BitmapFetcherHandler(this, image_url); | |
| 83 bitmap_fetcher_handler->Start( | |
| 84 browser_context_, referrer, referrer_policy, | |
| 85 net::LOAD_DO_NOT_SEND_COOKIES | net::LOAD_DO_NOT_SAVE_COOKIES, | |
| 86 update_bookmark, page_url); | |
| 87 } | |
| 88 | |
| 89 void BookmarkImageServiceAndroid::RetrieveSalientImageFromContext( | |
| 90 content::WebContents* web_contents, | |
| 91 const GURL& page_url, | |
| 92 bool update_bookmark) { | |
| 93 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 94 if (IsPageUrlInProgress(page_url)) | |
| 95 return; // A request for this URL is already in progress. | |
| 96 | |
| 97 const BookmarkNode* bookmark = enhanced_bookmark_model_->bookmark_model() | |
| 98 ->GetMostRecentlyAddedUserNodeForURL(page_url); | |
| 99 if (!bookmark) | |
| 100 return; | |
| 101 | |
| 102 // Stop the image extraction if there is already an image present. | |
| 103 GURL url; | |
| 104 int height, width; | |
| 105 if (enhanced_bookmark_model_->GetOriginalImage(bookmark, &url, &width, | |
| 106 &height) || | |
| 107 enhanced_bookmark_model_->GetThumbnailImage(bookmark, &url, &width, | |
| 108 &height)) { | |
| 109 return; | |
| 110 } | |
| 111 | |
| 112 if (dom_initializer_script_.empty()) { | |
| 113 dom_initializer_script_ = | |
| 114 base::UTF8ToUTF16( | |
| 115 ResourceBundle::GetSharedInstance() | |
| 116 .GetRawDataResource(IDR_DOM_INITIALIZER_GEN_JS) | |
| 117 .as_string()); | |
| 118 } | |
| 119 | |
| 120 blink::WebReferrerPolicy policy = | |
| 121 web_contents->GetController().GetVisibleEntry()->GetReferrer().policy; | |
| 122 | |
| 123 content::RenderFrameHost* render_frame_host = web_contents->GetMainFrame(); | |
| 124 | |
| 125 render_frame_host->ExecuteJavaScriptInIsolatedWorld( | |
| 126 dom_initializer_script_, | |
| 127 base::Bind( | |
| 128 &BookmarkImageServiceAndroid::InitializeDomCallback, | |
| 129 base::Unretained(this), policy, render_frame_host, page_url, | |
| 130 update_bookmark), | |
| 131 chrome::ISOLATED_WORLD_ID_CHROME_INTERNAL); | |
| 132 } | |
| 133 | |
| 134 void BookmarkImageServiceAndroid::FinishSuccessfulPageLoadForTab( | |
| 135 content::WebContents* web_contents, bool update_bookmark) { | |
| 136 content::NavigationEntry* entry = | |
| 137 web_contents->GetController().GetVisibleEntry(); | |
| 138 | |
| 139 // If the navigation is a simple back or forward, do not extract images, those | |
| 140 // were extracted already. | |
| 141 if (!entry || (entry->GetTransitionType() & ui::PAGE_TRANSITION_FORWARD_BACK)) | |
| 142 return; | |
| 143 const GURL& entry_url = entry->GetURL(); | |
| 144 const GURL& entry_original_url = entry->GetOriginalRequestURL(); | |
| 145 std::vector<GURL> urls; | |
| 146 urls.push_back(entry_url); | |
| 147 if (entry_url != entry_original_url) | |
| 148 urls.push_back(entry_original_url); | |
| 149 for (GURL url : urls) { | |
| 150 if (enhanced_bookmark_model_->bookmark_model()->IsBookmarked(url)) { | |
| 151 RetrieveSalientImageFromContext(web_contents, url, | |
| 152 update_bookmark); | |
| 153 } | |
| 154 } | |
| 155 } | |
| 156 | |
| 157 void BookmarkImageServiceAndroid::InitializeDomCallback( | |
| 158 blink::WebReferrerPolicy policy, | |
| 159 content::RenderFrameHost* render_frame_host, | |
| 160 const GURL& page_url, | |
| 161 bool update_bookmark, | |
| 162 const base::Value* result) { | |
| 163 if (get_salient_image_url_script_.empty()) { | |
| 164 get_salient_image_url_script_ = | |
| 165 base::UTF8ToUTF16( | |
| 166 ResourceBundle::GetSharedInstance() | |
| 167 .GetRawDataResource(IDR_GET_SALIENT_IMAGE_URL_GEN_JS) | |
| 168 .as_string()); | |
| 169 } | |
| 170 | |
| 171 render_frame_host->ExecuteJavaScriptInIsolatedWorld( | |
| 172 get_salient_image_url_script_, | |
| 173 base::Bind( | |
| 174 &BookmarkImageServiceAndroid::RetrieveSalientImageFromContextCallback, | |
| 175 base::Unretained(this), policy, page_url, update_bookmark), | |
| 176 chrome::ISOLATED_WORLD_ID_CHROME_INTERNAL); | |
| 177 } | |
| 178 | |
| 179 void BookmarkImageServiceAndroid::RetrieveSalientImageFromContextCallback( | |
| 180 blink::WebReferrerPolicy policy, | |
| 181 const GURL& page_url, | |
| 182 bool update_bookmark, | |
| 183 const base::Value* result) { | |
| 184 if (!result) | |
| 185 return; | |
| 186 | |
| 187 std::string json; | |
| 188 if (!result->GetAsString(&json)) { | |
| 189 LOG(WARNING) | |
| 190 << "Salient image extracting script returned non-string result."; | |
| 191 return; | |
| 192 } | |
| 193 | |
| 194 int error_code = 0; | |
| 195 std::string error_message; | |
| 196 scoped_ptr<base::Value> json_data = base::JSONReader::ReadAndReturnError( | |
| 197 json, base::JSON_PARSE_RFC, &error_code, &error_message); | |
| 198 if (error_code || !json_data) { | |
| 199 LOG(WARNING) << "JSON parse error: " << error_message << json; | |
| 200 return; | |
| 201 } | |
| 202 | |
| 203 base::DictionaryValue* dict; | |
| 204 if (!json_data->GetAsDictionary(&dict)) { | |
| 205 LOG(WARNING) << "JSON parse error, not a dict: " << json; | |
| 206 return; | |
| 207 } | |
| 208 | |
| 209 std::string referrerPolicy; | |
| 210 std::string image_url; | |
| 211 dict->GetString("referrerPolicy", &referrerPolicy); | |
| 212 dict->GetString("imageUrl", &image_url); | |
| 213 | |
| 214 in_progress_page_urls_.insert(page_url); | |
| 215 | |
| 216 Referrer referrer = | |
| 217 Referrer::SanitizeForRequest(GURL(image_url), Referrer(page_url, policy)); | |
| 218 net::URLRequest::ReferrerPolicy referrer_policy = | |
| 219 net::URLRequest::CLEAR_REFERRER_ON_TRANSITION_FROM_SECURE_TO_INSECURE; | |
| 220 if (!referrer.url.is_empty()) { | |
| 221 switch (policy) { | |
| 222 case blink::WebReferrerPolicyDefault: | |
| 223 break; | |
| 224 case blink::WebReferrerPolicyAlways: | |
| 225 case blink::WebReferrerPolicyNever: | |
| 226 case blink::WebReferrerPolicyOrigin: | |
| 227 referrer_policy = net::URLRequest::NEVER_CLEAR_REFERRER; | |
| 228 break; | |
| 229 default: | |
| 230 NOTREACHED(); | |
| 231 } | |
| 232 } | |
| 233 RetrieveSalientImage(page_url, GURL(image_url), referrer.url.spec(), | |
| 234 referrer_policy, update_bookmark); | |
| 235 } | |
| 236 | |
| 237 scoped_ptr<gfx::Image> BookmarkImageServiceAndroid::ResizeImage( | |
| 238 const gfx::Image& image) { | |
| 239 DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | |
| 240 | |
| 241 scoped_ptr<gfx::Image> result(new gfx::Image()); | |
| 242 | |
| 243 if (image.Width() > max_size_.width() && | |
| 244 image.Height() > max_size_.height()) { | |
| 245 float resize_ratio = std::min( | |
| 246 ((float)max_size_.width()) / image.Width(), | |
| 247 ((float)max_size_.height()) / image.Height()); | |
| 248 // +0.5f is for correct rounding. Without it, it's possible that dest_width | |
| 249 // is smaller than max_size_.Width() by one. | |
| 250 int dest_width = static_cast<int>(resize_ratio * image.Width() + 0.5f); | |
| 251 int dest_height = static_cast<int>( | |
| 252 resize_ratio * image.Height() + 0.5f); | |
| 253 | |
| 254 *result = gfx::Image::CreateFrom1xBitmap( | |
| 255 skia::ImageOperations::Resize(image.AsBitmap(), | |
| 256 skia::ImageOperations::RESIZE_BEST, | |
| 257 dest_width, | |
| 258 dest_height)); | |
| 259 result->AsImageSkia().MakeThreadSafe(); | |
| 260 } else { | |
| 261 *result = image; | |
| 262 } | |
| 263 | |
| 264 return result.Pass(); | |
| 265 } | |
| 266 | |
| 267 void BookmarkImageServiceAndroid::BitmapFetcherHandler::Start( | |
| 268 content::BrowserContext* browser_context, | |
| 269 const std::string& referrer, | |
| 270 net::URLRequest::ReferrerPolicy referrer_policy, | |
| 271 int load_flags, | |
| 272 bool update_bookmark, | |
| 273 const GURL& page_url) { | |
| 274 update_bookmark_ = update_bookmark; | |
| 275 page_url_ = page_url; | |
| 276 | |
| 277 bitmap_fetcher_.Init(browser_context->GetRequestContext(), referrer, | |
| 278 referrer_policy, load_flags); | |
| 279 bitmap_fetcher_.Start(); | |
| 280 } | |
| 281 | |
| 282 void BookmarkImageServiceAndroid::BitmapFetcherHandler::OnFetchComplete( | |
| 283 const GURL& url, | |
| 284 const SkBitmap* bitmap) { | |
| 285 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); | |
| 286 | |
| 287 scoped_ptr<gfx::Image> image; | |
| 288 if (bitmap) { | |
| 289 gfx::ImageSkia imageSkia = gfx::ImageSkia::CreateFrom1xBitmap(*bitmap); | |
| 290 imageSkia.MakeThreadSafe(); | |
| 291 image.reset(new gfx::Image(imageSkia)); | |
| 292 } else { | |
| 293 image.reset(new gfx::Image()); | |
| 294 } | |
| 295 service_->ProcessNewImage(page_url_, update_bookmark_, url, image.Pass()); | |
| 296 | |
| 297 delete this; | |
| 298 } | |
| 299 | |
| 300 } // namespace enhanced_bookmarks | |
| OLD | NEW |