Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Side by Side Diff: chrome/browser/ui/views/omnibox/omnibox_result_view.cc

Issue 917333004: Answers in Suggest icon downloading (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: added retry logic to fetch image service Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « chrome/browser/ui/views/omnibox/omnibox_result_view.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 // For WinDDK ATL compatibility, these ATL headers must come first. 5 // For WinDDK ATL compatibility, these ATL headers must come first.
6 #include "build/build_config.h" 6 #include "build/build_config.h"
7 #if defined(OS_WIN) 7 #if defined(OS_WIN)
8 #include <atlbase.h> // NOLINT 8 #include <atlbase.h> // NOLINT
9 #include <atlwin.h> // NOLINT 9 #include <atlwin.h> // NOLINT
10 #endif 10 #endif
11 11
12 #include "chrome/browser/ui/views/omnibox/omnibox_result_view.h" 12 #include "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
13 13
14 #include <algorithm> // NOLINT 14 #include <algorithm> // NOLINT
15 15
16 #include "base/i18n/bidi_line_iterator.h" 16 #include "base/i18n/bidi_line_iterator.h"
17 #include "base/memory/scoped_vector.h" 17 #include "base/memory/scoped_vector.h"
18 #include "base/strings/string_number_conversions.h" 18 #include "base/strings/string_number_conversions.h"
19 #include "base/strings/string_util.h" 19 #include "base/strings/string_util.h"
20 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_service_factory.h"
21 #include "chrome/browser/profiles/profile.h"
20 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h" 22 #include "chrome/browser/ui/omnibox/omnibox_popup_model.h"
21 #include "chrome/browser/ui/views/location_bar/location_bar_view.h" 23 #include "chrome/browser/ui/views/location_bar/location_bar_view.h"
22 #include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h" 24 #include "chrome/browser/ui/views/omnibox/omnibox_popup_contents_view.h"
23 #include "chrome/grit/generated_resources.h" 25 #include "chrome/grit/generated_resources.h"
24 #include "components/omnibox/suggestion_answer.h" 26 #include "components/omnibox/suggestion_answer.h"
25 #include "grit/components_scaled_resources.h" 27 #include "grit/components_scaled_resources.h"
26 #include "grit/theme_resources.h" 28 #include "grit/theme_resources.h"
27 #include "ui/base/l10n/l10n_util.h" 29 #include "ui/base/l10n/l10n_util.h"
28 #include "ui/base/theme_provider.h" 30 #include "ui/base/theme_provider.h"
29 #include "ui/gfx/canvas.h" 31 #include "ui/gfx/canvas.h"
30 #include "ui/gfx/color_utils.h" 32 #include "ui/gfx/color_utils.h"
31 #include "ui/gfx/image/image.h" 33 #include "ui/gfx/image/image.h"
32 #include "ui/gfx/range/range.h" 34 #include "ui/gfx/range/range.h"
33 #include "ui/gfx/render_text.h" 35 #include "ui/gfx/render_text.h"
34 #include "ui/gfx/text_utils.h" 36 #include "ui/gfx/text_utils.h"
35 #include "ui/native_theme/native_theme.h" 37 #include "ui/native_theme/native_theme.h"
36 38
37 using ui::NativeTheme; 39 using ui::NativeTheme;
38 40
39 namespace { 41 namespace {
40 42
43 // The observer watches for changes in the image being downloaded.
44 class AnswersImageObserverDesktop : public BitmapFetcherService::Observer {
45 public:
46 explicit AnswersImageObserverDesktop(
47 const base::WeakPtr<OmniboxResultView>& view)
48 : view_(view) {}
49
50 void OnImageChanged(BitmapFetcherService::RequestId request_id,
51 const SkBitmap& image) override;
52
53 private:
54 const base::WeakPtr<OmniboxResultView> view_;
55 DISALLOW_COPY_AND_ASSIGN(AnswersImageObserverDesktop);
56 };
57
58 void AnswersImageObserverDesktop::OnImageChanged(
59 BitmapFetcherService::RequestId request_id,
60 const SkBitmap& image) {
61 DCHECK(!image.empty());
62 if (view_)
63 view_.get()->SetAnswerImage(gfx::ImageSkia::CreateFrom1xBitmap(image));
Peter Kasting 2015/03/03 00:04:01 Nit: No .get()
dschuyler 2015/03/03 21:13:56 Done.
64 }
65
41 // The minimum distance between the top and bottom of the {icon|text} and the 66 // The minimum distance between the top and bottom of the {icon|text} and the
42 // top or bottom of the row. 67 // top or bottom of the row.
43 const int kMinimumIconVerticalPadding = 2; 68 const int kMinimumIconVerticalPadding = 2;
44 const int kMinimumTextVerticalPadding = 3; 69 const int kMinimumTextVerticalPadding = 3;
45 70
46 // A mapping from OmniboxResultView's ResultViewState/ColorKind types to 71 // A mapping from OmniboxResultView's ResultViewState/ColorKind types to
47 // NativeTheme colors. 72 // NativeTheme colors.
48 struct TranslationTable { 73 struct TranslationTable {
49 ui::NativeTheme::ColorId id; 74 ui::NativeTheme::ColorId id;
50 OmniboxResultView::ResultViewState state; 75 OmniboxResultView::ResultViewState state;
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
120 int center_; 145 int center_;
121 int right_; 146 int right_;
122 147
123 DISALLOW_COPY_AND_ASSIGN(MirroringContext); 148 DISALLOW_COPY_AND_ASSIGN(MirroringContext);
124 }; 149 };
125 150
126 OmniboxResultView::OmniboxResultView(OmniboxPopupContentsView* model, 151 OmniboxResultView::OmniboxResultView(OmniboxPopupContentsView* model,
127 int model_index, 152 int model_index,
128 LocationBarView* location_bar_view, 153 LocationBarView* location_bar_view,
129 const gfx::FontList& font_list) 154 const gfx::FontList& font_list)
130 : edge_item_padding_(LocationBarView::kItemPadding), 155 : image_service_(nullptr),
156 request_id_(BitmapFetcherService::REQUEST_ID_INVALID),
157 edge_item_padding_(LocationBarView::kItemPadding),
131 item_padding_(LocationBarView::kItemPadding), 158 item_padding_(LocationBarView::kItemPadding),
132 minimum_text_vertical_padding_(kMinimumTextVerticalPadding), 159 minimum_text_vertical_padding_(kMinimumTextVerticalPadding),
133 model_(model), 160 model_(model),
134 model_index_(model_index), 161 model_index_(model_index),
135 location_bar_view_(location_bar_view), 162 location_bar_view_(location_bar_view),
136 font_list_(font_list), 163 font_list_(font_list),
137 font_height_( 164 font_height_(
138 std::max(font_list.GetHeight(), 165 std::max(font_list.GetHeight(),
139 font_list.DeriveWithStyle(gfx::Font::BOLD).GetHeight())), 166 font_list.DeriveWithStyle(gfx::Font::BOLD).GetHeight())),
140 mirroring_context_(new MirroringContext()), 167 mirroring_context_(new MirroringContext()),
141 keyword_icon_(new views::ImageView()), 168 keyword_icon_(new views::ImageView()),
142 animation_(new gfx::SlideAnimation(this)) { 169 animation_(new gfx::SlideAnimation(this)),
170 weak_ptr_factory_(this) {
143 CHECK_GE(model_index, 0); 171 CHECK_GE(model_index, 0);
144 if (default_icon_size_ == 0) { 172 if (default_icon_size_ == 0) {
145 default_icon_size_ = 173 default_icon_size_ =
146 location_bar_view_->GetThemeProvider()->GetImageSkiaNamed( 174 location_bar_view_->GetThemeProvider()->GetImageSkiaNamed(
147 AutocompleteMatch::TypeToIcon( 175 AutocompleteMatch::TypeToIcon(
148 AutocompleteMatchType::URL_WHAT_YOU_TYPED))->width(); 176 AutocompleteMatchType::URL_WHAT_YOU_TYPED))->width();
149 } 177 }
150 keyword_icon_->set_owned_by_client(); 178 keyword_icon_->set_owned_by_client();
151 keyword_icon_->EnableCanvasFlippingForRTLUI(true); 179 keyword_icon_->EnableCanvasFlippingForRTLUI(true);
152 keyword_icon_->SetImage(GetKeywordIcon()); 180 keyword_icon_->SetImage(GetKeywordIcon());
153 keyword_icon_->SizeToPreferredSize(); 181 keyword_icon_->SizeToPreferredSize();
154 } 182 }
155 183
156 OmniboxResultView::~OmniboxResultView() { 184 OmniboxResultView::~OmniboxResultView() {
185 if (HasImageService())
Peter Kasting 2015/03/03 00:04:01 This will create the image service if it doesn't e
dschuyler 2015/03/03 00:16:04 Yep. I'll change that (but I want to ask question
186 image_service_->CancelRequest(request_id_);
157 } 187 }
158 188
159 SkColor OmniboxResultView::GetColor( 189 SkColor OmniboxResultView::GetColor(
160 ResultViewState state, 190 ResultViewState state,
161 ColorKind kind) const { 191 ColorKind kind) const {
162 for (size_t i = 0; i < arraysize(kTranslationTable); ++i) { 192 for (size_t i = 0; i < arraysize(kTranslationTable); ++i) {
163 if (kTranslationTable[i].state == state && 193 if (kTranslationTable[i].state == state &&
164 kTranslationTable[i].kind == kind) { 194 kTranslationTable[i].kind == kind) {
165 return GetNativeTheme()->GetSystemColor(kTranslationTable[i].id); 195 return GetNativeTheme()->GetSystemColor(kTranslationTable[i].id);
166 } 196 }
167 } 197 }
168 198
169 NOTREACHED(); 199 NOTREACHED();
170 return SK_ColorRED; 200 return SK_ColorRED;
171 } 201 }
172 202
173 void OmniboxResultView::SetMatch(const AutocompleteMatch& match) { 203 void OmniboxResultView::SetMatch(const AutocompleteMatch& match) {
174 match_ = match; 204 match_ = match;
175 ResetRenderTexts(); 205 ResetRenderTexts();
176 animation_->Reset(); 206 animation_->Reset();
177 207
208 answer_image_ = gfx::ImageSkia();
209 if (match_.answer && match_.answer->second_line().image_url().is_valid())
210 GetAnswerIcon();
211
178 AutocompleteMatch* associated_keyword_match = match_.associated_keyword.get(); 212 AutocompleteMatch* associated_keyword_match = match_.associated_keyword.get();
179 if (associated_keyword_match) { 213 if (associated_keyword_match) {
180 keyword_icon_->SetImage(GetKeywordIcon()); 214 keyword_icon_->SetImage(GetKeywordIcon());
181 if (!keyword_icon_->parent()) 215 if (!keyword_icon_->parent())
182 AddChildView(keyword_icon_.get()); 216 AddChildView(keyword_icon_.get());
183 } else if (keyword_icon_->parent()) { 217 } else if (keyword_icon_->parent()) {
184 RemoveChildView(keyword_icon_.get()); 218 RemoveChildView(keyword_icon_.get());
185 } 219 }
186 220
187 Layout(); 221 Layout();
(...skipping 27 matching lines...) Expand all
215 OmniboxResultView::ResultViewState OmniboxResultView::GetState() const { 249 OmniboxResultView::ResultViewState OmniboxResultView::GetState() const {
216 if (model_->IsSelectedIndex(model_index_)) 250 if (model_->IsSelectedIndex(model_index_))
217 return SELECTED; 251 return SELECTED;
218 return model_->IsHoveredIndex(model_index_) ? HOVERED : NORMAL; 252 return model_->IsHoveredIndex(model_index_) ? HOVERED : NORMAL;
219 } 253 }
220 254
221 int OmniboxResultView::GetTextHeight() const { 255 int OmniboxResultView::GetTextHeight() const {
222 return font_height_; 256 return font_height_;
223 } 257 }
224 258
225 void OmniboxResultView::PaintMatch( 259 void OmniboxResultView::PaintMatch(const AutocompleteMatch& match,
226 const AutocompleteMatch& match, 260 gfx::RenderText* contents,
227 gfx::RenderText* contents, 261 gfx::RenderText* description,
228 gfx::RenderText* description, 262 gfx::Canvas* canvas,
229 gfx::Canvas* canvas, 263 int x) const {
230 int x) const {
231 int y = text_bounds_.y(); 264 int y = text_bounds_.y();
232 265
233 if (!separator_rendertext_) { 266 if (!separator_rendertext_) {
234 const base::string16& separator = 267 const base::string16& separator =
235 l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR); 268 l10n_util::GetStringUTF16(IDS_AUTOCOMPLETE_MATCH_DESCRIPTION_SEPARATOR);
236 separator_rendertext_.reset(CreateRenderText(separator).release()); 269 separator_rendertext_.reset(CreateRenderText(separator).release());
237 separator_rendertext_->SetColor(GetColor(GetState(), DIMMED_TEXT)); 270 separator_rendertext_->SetColor(GetColor(GetState(), DIMMED_TEXT));
238 separator_width_ = separator_rendertext_->GetContentWidth(); 271 separator_width_ = separator_rendertext_->GetContentWidth();
239 } 272 }
240 273
241 int contents_max_width, description_max_width; 274 int contents_max_width, description_max_width;
242 OmniboxPopupModel::ComputeMatchMaxWidths( 275 OmniboxPopupModel::ComputeMatchMaxWidths(
243 contents->GetContentWidth(), 276 contents->GetContentWidth(),
244 separator_width_, 277 separator_width_,
245 description ? description->GetContentWidth() : 0, 278 description ? description->GetContentWidth() : 0,
246 mirroring_context_->remaining_width(x), 279 mirroring_context_->remaining_width(x),
247 !AutocompleteMatch::IsSearchType(match.type), 280 !AutocompleteMatch::IsSearchType(match.type),
248 &contents_max_width, 281 &contents_max_width,
249 &description_max_width); 282 &description_max_width);
250 283
251 x = DrawRenderText(match, contents, true, canvas, x, y, contents_max_width); 284 x = DrawRenderText(match, contents, true, canvas, x, y, contents_max_width);
252 285
253 if (description_max_width != 0) { 286 if (description_max_width != 0) {
254 x = DrawRenderText(match, separator_rendertext_.get(), false, canvas, x, y, 287 x = DrawRenderText(match, separator_rendertext_.get(), false, canvas, x, y,
255 separator_width_); 288 separator_width_);
289
290 if (!answer_image_.size().IsEmpty()) {
291 canvas->DrawImageInt(answer_image_,
292 // Source x, y, w, h.
293 0, 0, answer_image_.width(), answer_image_.height(),
294 // Destination x, y, w, h.
295 GetMirroredXInView(x),
296 y + kMinimumIconVerticalPadding, default_icon_size_,
297 default_icon_size_, true);
298 x += default_icon_size_ + LocationBarView::kIconInternalPadding;
299 }
300
256 DrawRenderText(match, description, false, canvas, x, y, 301 DrawRenderText(match, description, false, canvas, x, y,
257 description_max_width); 302 description_max_width);
258 } 303 }
259 } 304 }
260 305
261 int OmniboxResultView::DrawRenderText( 306 int OmniboxResultView::DrawRenderText(
262 const AutocompleteMatch& match, 307 const AutocompleteMatch& match,
263 gfx::RenderText* render_text, 308 gfx::RenderText* render_text,
264 bool contents, 309 bool contents,
265 gfx::Canvas* canvas, 310 gfx::Canvas* canvas,
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
389 render_text->ApplyColor(GetColor(GetState(), color_kind), current_range); 434 render_text->ApplyColor(GetColor(GetState(), color_kind), current_range);
390 } 435 }
391 return render_text.Pass(); 436 return render_text.Pass();
392 } 437 }
393 438
394 int OmniboxResultView::GetMatchContentsWidth() const { 439 int OmniboxResultView::GetMatchContentsWidth() const {
395 InitContentsRenderTextIfNecessary(); 440 InitContentsRenderTextIfNecessary();
396 return contents_rendertext_ ? contents_rendertext_->GetContentWidth() : 0; 441 return contents_rendertext_ ? contents_rendertext_->GetContentWidth() : 0;
397 } 442 }
398 443
444 void OmniboxResultView::SetAnswerImage(gfx::ImageSkia image) {
445 answer_image_ = image;
446 SchedulePaint();
447 }
448
399 // TODO(skanuj): This is probably identical across all OmniboxResultView rows in 449 // TODO(skanuj): This is probably identical across all OmniboxResultView rows in
400 // the omnibox dropdown. Consider sharing the result. 450 // the omnibox dropdown. Consider sharing the result.
401 int OmniboxResultView::GetDisplayOffset( 451 int OmniboxResultView::GetDisplayOffset(
402 const AutocompleteMatch& match, 452 const AutocompleteMatch& match,
403 bool is_ui_rtl, 453 bool is_ui_rtl,
404 bool is_match_contents_rtl) const { 454 bool is_match_contents_rtl) const {
405 if (match.type != AutocompleteMatchType::SEARCH_SUGGEST_TAIL) 455 if (match.type != AutocompleteMatchType::SEARCH_SUGGEST_TAIL)
406 return 0; 456 return 0;
407 457
408 const base::string16& input_text = 458 const base::string16& input_text =
409 base::UTF8ToUTF16(match.GetAdditionalInfo(kACMatchPropertyInputText)); 459 base::UTF8ToUTF16(match.GetAdditionalInfo(kACMatchPropertyInputText));
410 int contents_start_index = 0; 460 int contents_start_index = 0;
411 base::StringToInt(match.GetAdditionalInfo(kACMatchPropertyContentsStartIndex), 461 base::StringToInt(match.GetAdditionalInfo(kACMatchPropertyContentsStartIndex),
412 &contents_start_index); 462 &contents_start_index);
413 463
414 scoped_ptr<gfx::RenderText> input_render_text(CreateRenderText(input_text)); 464 scoped_ptr<gfx::RenderText> input_render_text(CreateRenderText(input_text));
415 const gfx::Range& glyph_bounds = 465 const gfx::Range& glyph_bounds =
416 input_render_text->GetGlyphBounds(contents_start_index); 466 input_render_text->GetGlyphBounds(contents_start_index);
417 const int start_padding = is_match_contents_rtl ? 467 const int start_padding = is_match_contents_rtl ?
418 std::max(glyph_bounds.start(), glyph_bounds.end()) : 468 std::max(glyph_bounds.start(), glyph_bounds.end()) :
419 std::min(glyph_bounds.start(), glyph_bounds.end()); 469 std::min(glyph_bounds.start(), glyph_bounds.end());
420 470
421 return is_ui_rtl ? 471 return is_ui_rtl ?
422 (input_render_text->GetContentWidth() - start_padding) : start_padding; 472 (input_render_text->GetContentWidth() - start_padding) : start_padding;
423 } 473 }
424 474
425 // static 475 // static
426 int OmniboxResultView::default_icon_size_ = 0; 476 int OmniboxResultView::default_icon_size_ = 0;
427 477
478 void OmniboxResultView::GetAnswerIcon() {
479 // The answer images are not bundled with Chrome, so we need to download
480 // them.
481 if (HasImageService()) {
Peter Kasting 2015/03/03 00:04:01 This now becomes the lone caller of this function.
dschuyler 2015/03/03 00:16:04 It was initializing in the constructor and that se
Peter Kasting 2015/03/03 00:18:28 That doesn't sound like the problem was in initial
dschuyler 2015/03/03 21:13:56 Done.
482 image_service_->CancelRequest(request_id_);
483 request_id_ = image_service_->RequestImage(
484 match_.answer->second_line().image_url(),
485 new AnswersImageObserverDesktop(GetWeakPtr()));
486 }
487 }
488
428 const char* OmniboxResultView::GetClassName() const { 489 const char* OmniboxResultView::GetClassName() const {
429 return "OmniboxResultView"; 490 return "OmniboxResultView";
430 } 491 }
431 492
432 gfx::ImageSkia OmniboxResultView::GetIcon() const { 493 gfx::ImageSkia OmniboxResultView::GetIcon() const {
433 const gfx::Image image = model_->GetIconIfExtensionMatch(model_index_); 494 const gfx::Image image = model_->GetIconIfExtensionMatch(model_index_);
434 if (!image.IsEmpty()) 495 if (!image.IsEmpty())
435 return image.AsImageSkia(); 496 return image.AsImageSkia();
436 497
437 int icon = model_->IsStarredMatch(match_) ? 498 int icon = model_->IsStarredMatch(match_) ?
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
568 } 629 }
569 PaintMatch(*keyword_match, keyword_contents_rendertext_.get(), 630 PaintMatch(*keyword_match, keyword_contents_rendertext_.get(),
570 keyword_description_rendertext_.get(), canvas, x); 631 keyword_description_rendertext_.get(), canvas, x);
571 } 632 }
572 } 633 }
573 634
574 void OmniboxResultView::AnimationProgressed(const gfx::Animation* animation) { 635 void OmniboxResultView::AnimationProgressed(const gfx::Animation* animation) {
575 Layout(); 636 Layout();
576 SchedulePaint(); 637 SchedulePaint();
577 } 638 }
639
640 bool OmniboxResultView::HasImageService()
641 {
642 if (image_service_ == nullptr) {
643 image_service_ = BitmapFetcherServiceFactory::GetForBrowserContext(
644 location_bar_view_->profile());
Peter Kasting 2015/03/03 00:04:01 Can this call ever actually return null? Maybe wh
dschuyler 2015/03/03 00:16:04 GetForBrowserContext can return null in unit tests
645 }
646 return image_service_ != nullptr;
647 }
648
OLDNEW
« no previous file with comments | « chrome/browser/ui/views/omnibox/omnibox_result_view.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698