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

Side by Side Diff: chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk.cc

Issue 8781001: GTK: Port omnibox drawing from GdkGC interface to cairo. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Fix crash by copying bitmap. Created 9 years 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/gtk/omnibox/omnibox_popup_view_gtk.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) 2011 The Chromium Authors. All rights reserved. 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 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/gtk/omnibox/omnibox_popup_view_gtk.h" 5 #include "chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk.h"
6 6
7 #include <gtk/gtk.h> 7 #include <gtk/gtk.h>
8 8
9 #include <algorithm> 9 #include <algorithm>
10 #include <string> 10 #include <string>
(...skipping 16 matching lines...) Expand all
27 #include "chrome/browser/ui/omnibox/omnibox_view.h" 27 #include "chrome/browser/ui/omnibox/omnibox_view.h"
28 #include "chrome/common/chrome_notification_types.h" 28 #include "chrome/common/chrome_notification_types.h"
29 #include "content/public/browser/notification_source.h" 29 #include "content/public/browser/notification_source.h"
30 #include "grit/theme_resources.h" 30 #include "grit/theme_resources.h"
31 #include "ui/base/gtk/gtk_compat.h" 31 #include "ui/base/gtk/gtk_compat.h"
32 #include "ui/base/gtk/gtk_hig_constants.h" 32 #include "ui/base/gtk/gtk_hig_constants.h"
33 #include "ui/base/gtk/gtk_windowing.h" 33 #include "ui/base/gtk/gtk_windowing.h"
34 #include "ui/gfx/color_utils.h" 34 #include "ui/gfx/color_utils.h"
35 #include "ui/gfx/font.h" 35 #include "ui/gfx/font.h"
36 #include "ui/gfx/gtk_util.h" 36 #include "ui/gfx/gtk_util.h"
37 #include "ui/gfx/image/cairo_cached_surface.h"
38 #include "ui/gfx/image/image.h"
37 #include "ui/gfx/rect.h" 39 #include "ui/gfx/rect.h"
38 #include "ui/gfx/skia_utils_gtk.h" 40 #include "ui/gfx/skia_utils_gtk.h"
39 41
40 namespace { 42 namespace {
41 43
42 const GdkColor kBorderColor = GDK_COLOR_RGB(0xc7, 0xca, 0xce); 44 const GdkColor kBorderColor = GDK_COLOR_RGB(0xc7, 0xca, 0xce);
43 const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xff, 0xff, 0xff); 45 const GdkColor kBackgroundColor = GDK_COLOR_RGB(0xff, 0xff, 0xff);
44 const GdkColor kSelectedBackgroundColor = GDK_COLOR_RGB(0xdf, 0xe6, 0xf6); 46 const GdkColor kSelectedBackgroundColor = GDK_COLOR_RGB(0xdf, 0xe6, 0xf6);
45 const GdkColor kHoveredBackgroundColor = GDK_COLOR_RGB(0xef, 0xf2, 0xfa); 47 const GdkColor kHoveredBackgroundColor = GDK_COLOR_RGB(0xef, 0xf2, 0xfa);
46 48
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 // Return a Rect for the space for a result line. This excludes the border, 99 // Return a Rect for the space for a result line. This excludes the border,
98 // but includes the padding. This is the area that is colored for a selection. 100 // but includes the padding. This is the area that is colored for a selection.
99 gfx::Rect GetRectForLine(size_t line, int width) { 101 gfx::Rect GetRectForLine(size_t line, int width) {
100 return gfx::Rect(kBorderThickness, 102 return gfx::Rect(kBorderThickness,
101 (line * kHeightPerResult) + kBorderThickness, 103 (line * kHeightPerResult) + kBorderThickness,
102 width - (kBorderThickness * 2), 104 width - (kBorderThickness * 2),
103 kHeightPerResult); 105 kHeightPerResult);
104 } 106 }
105 107
106 // Helper for drawing an entire pixbuf without dithering. 108 // Helper for drawing an entire pixbuf without dithering.
107 void DrawFullPixbuf(GdkDrawable* drawable, GdkGC* gc, GdkPixbuf* pixbuf, 109 void DrawFullImage(cairo_t* cr, GtkWidget* widget, const gfx::Image* image,
108 gint dest_x, gint dest_y) { 110 gint dest_x, gint dest_y) {
109 gdk_draw_pixbuf(drawable, gc, pixbuf, 111 gfx::CairoCachedSurface* surface = image->ToCairo();
110 0, 0, // Source. 112 surface->SetSource(cr, widget, dest_x, dest_y);
111 dest_x, dest_y, // Dest. 113 cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT);
112 -1, -1, // Width/height (auto). 114 cairo_rectangle(cr, dest_x, dest_y, surface->Width(), surface->Height());
113 GDK_RGB_DITHER_NONE, 0, 0); // Don't dither. 115 cairo_fill(cr);
114 } 116 }
115 117
116 // TODO(deanm): Find some better home for this, and make it more efficient. 118 // TODO(deanm): Find some better home for this, and make it more efficient.
117 size_t GetUTF8Offset(const string16& text, size_t text_offset) { 119 size_t GetUTF8Offset(const string16& text, size_t text_offset) {
118 return UTF16ToUTF8(text.substr(0, text_offset)).length(); 120 return UTF16ToUTF8(text.substr(0, text_offset)).length();
119 } 121 }
120 122
121 // Generates the normal URL color, a green color used in unhighlighted URL 123 // Generates the normal URL color, a green color used in unhighlighted URL
122 // text. It is a mix of |kURLTextColor| and the current text color. Unlike the 124 // text. It is a mix of |kURLTextColor| and the current text color. Unlike the
123 // selected text color, it is more important to match the qualities of the 125 // selected text color, it is more important to match the qualities of the
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
331 } 333 }
332 334
333 OmniboxPopupViewGtk::~OmniboxPopupViewGtk() { 335 OmniboxPopupViewGtk::~OmniboxPopupViewGtk() {
334 // Explicitly destroy our model here, before we destroy our GTK widgets. 336 // Explicitly destroy our model here, before we destroy our GTK widgets.
335 // This is because the model destructor can call back into us, and we need 337 // This is because the model destructor can call back into us, and we need
336 // to make sure everything is still valid when it does. 338 // to make sure everything is still valid when it does.
337 model_.reset(); 339 model_.reset();
338 g_object_unref(layout_); 340 g_object_unref(layout_);
339 gtk_widget_destroy(window_); 341 gtk_widget_destroy(window_);
340 342
341 for (PixbufMap::iterator it = pixbufs_.begin(); it != pixbufs_.end(); ++it) 343 for (ImageMap::iterator it = images_.begin(); it != images_.end(); ++it)
342 g_object_unref(it->second); 344 delete it->second;
343 } 345 }
344 346
345 bool OmniboxPopupViewGtk::IsOpen() const { 347 bool OmniboxPopupViewGtk::IsOpen() const {
346 return opened_; 348 return opened_;
347 } 349 }
348 350
349 void OmniboxPopupViewGtk::InvalidateLine(size_t line) { 351 void OmniboxPopupViewGtk::InvalidateLine(size_t line) {
350 // TODO(deanm): Is it possible to use some constant for the width, instead 352 // TODO(deanm): Is it possible to use some constant for the width, instead
351 // of having to query the width of the window? 353 // of having to query the width of the window?
352 GdkRectangle line_rect = GetRectForLine( 354 GdkRectangle line_rect = GetRectForLine(
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
476 // OpenMatch() may close the popup, which will clear the result set and, by 478 // OpenMatch() may close the popup, which will clear the result set and, by
477 // extension, |match| and its contents. So copy the relevant match out to 479 // extension, |match| and its contents. So copy the relevant match out to
478 // make sure it stays alive until the call completes. 480 // make sure it stays alive until the call completes.
479 AutocompleteMatch match = model_->result().match_at(line); 481 AutocompleteMatch match = model_->result().match_at(line);
480 string16 keyword; 482 string16 keyword;
481 const bool is_keyword_hint = model_->GetKeywordForMatch(match, &keyword); 483 const bool is_keyword_hint = model_->GetKeywordForMatch(match, &keyword);
482 omnibox_view_->OpenMatch(match, disposition, GURL(), line, 484 omnibox_view_->OpenMatch(match, disposition, GURL(), line,
483 is_keyword_hint ? string16() : keyword); 485 is_keyword_hint ? string16() : keyword);
484 } 486 }
485 487
486 GdkPixbuf* OmniboxPopupViewGtk::IconForMatch(const AutocompleteMatch& match, 488 const gfx::Image* OmniboxPopupViewGtk::IconForMatch(
487 bool selected) { 489 const AutocompleteMatch& match, bool selected) {
488 const SkBitmap* bitmap = model_->GetIconIfExtensionMatch(match); 490 const SkBitmap* bitmap = model_->GetIconIfExtensionMatch(match);
489 if (bitmap) { 491 if (bitmap) {
490 if (!ContainsKey(pixbufs_, bitmap)) 492 if (!ContainsKey(images_, bitmap))
491 pixbufs_[bitmap] = gfx::GdkPixbufFromSkBitmap(bitmap); 493 images_[bitmap] = new gfx::Image(gfx::GdkPixbufFromSkBitmap(bitmap));
Nico 2011/12/05 18:55:39 Can you explain why this crashed? Is there any way
492 return pixbufs_[bitmap]; 494 return images_[bitmap];
493 } 495 }
494 496
495 int icon = match.starred ? 497 int icon = match.starred ?
496 IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match.type); 498 IDR_OMNIBOX_STAR : AutocompleteMatch::TypeToIcon(match.type);
497 if (selected) { 499 if (selected) {
498 switch (icon) { 500 switch (icon) {
499 case IDR_OMNIBOX_EXTENSION_APP: 501 case IDR_OMNIBOX_EXTENSION_APP:
500 icon = IDR_OMNIBOX_EXTENSION_APP_DARK; 502 icon = IDR_OMNIBOX_EXTENSION_APP_DARK;
501 break; 503 break;
502 case IDR_OMNIBOX_HTTP: 504 case IDR_OMNIBOX_HTTP:
503 icon = IDR_OMNIBOX_HTTP_DARK; 505 icon = IDR_OMNIBOX_HTTP_DARK;
504 break; 506 break;
505 case IDR_OMNIBOX_HISTORY: 507 case IDR_OMNIBOX_HISTORY:
506 icon = IDR_OMNIBOX_HISTORY_DARK; 508 icon = IDR_OMNIBOX_HISTORY_DARK;
507 break; 509 break;
508 case IDR_OMNIBOX_SEARCH: 510 case IDR_OMNIBOX_SEARCH:
509 icon = IDR_OMNIBOX_SEARCH_DARK; 511 icon = IDR_OMNIBOX_SEARCH_DARK;
510 break; 512 break;
511 case IDR_OMNIBOX_STAR: 513 case IDR_OMNIBOX_STAR:
512 icon = IDR_OMNIBOX_STAR_DARK; 514 icon = IDR_OMNIBOX_STAR_DARK;
513 break; 515 break;
514 default: 516 default:
515 NOTREACHED(); 517 NOTREACHED();
516 break; 518 break;
517 } 519 }
518 } 520 }
519 521
520 // TODO(estade): Do we want to flip these for RTL? (Windows doesn't). 522 return theme_service_->GetImageNamed(icon);
521 return theme_service_->GetPixbufNamed(icon);
522 } 523 }
523 524
524 gboolean OmniboxPopupViewGtk::HandleMotion(GtkWidget* widget, 525 gboolean OmniboxPopupViewGtk::HandleMotion(GtkWidget* widget,
525 GdkEventMotion* event) { 526 GdkEventMotion* event) {
526 // TODO(deanm): Windows has a bunch of complicated logic here. 527 // TODO(deanm): Windows has a bunch of complicated logic here.
527 size_t line = LineFromY(static_cast<int>(event->y)); 528 size_t line = LineFromY(static_cast<int>(event->y));
528 // There is both a hovered and selected line, hovered just means your mouse 529 // There is both a hovered and selected line, hovered just means your mouse
529 // is over it, but selected is what's showing in the location edit. 530 // is over it, but selected is what's showing in the location edit.
530 model_->SetHoveredLine(line); 531 model_->SetHoveredLine(line);
531 // Select the line if the user has the left mouse button down. 532 // Select the line if the user has the left mouse button down.
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
576 gfx::Rect window_rect = GetWindowRect(event->window); 577 gfx::Rect window_rect = GetWindowRect(event->window);
577 gfx::Rect damage_rect = gfx::Rect(event->area); 578 gfx::Rect damage_rect = gfx::Rect(event->area);
578 // Handle when our window is super narrow. A bunch of the calculations 579 // Handle when our window is super narrow. A bunch of the calculations
579 // below would go negative, and really we're not going to fit anything 580 // below would go negative, and really we're not going to fit anything
580 // useful in such a small window anyway. Just don't paint anything. 581 // useful in such a small window anyway. Just don't paint anything.
581 // This means we won't draw the border, but, yeah, whatever. 582 // This means we won't draw the border, but, yeah, whatever.
582 // TODO(deanm): Make the code more robust and remove this check. 583 // TODO(deanm): Make the code more robust and remove this check.
583 if (window_rect.width() < (kIconAreaWidth * 3)) 584 if (window_rect.width() < (kIconAreaWidth * 3))
584 return TRUE; 585 return TRUE;
585 586
586 GdkDrawable* drawable = GDK_DRAWABLE(event->window); 587 cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(widget->window));
587 GdkGC* gc = gdk_gc_new(drawable); 588 gdk_cairo_rectangle(cr, &event->area);
588 589 cairo_clip(cr);
589 // kBorderColor is unallocated, so use the GdkRGB routine.
590 gdk_gc_set_rgb_fg_color(gc, &border_color_);
591 590
592 // This assert is kinda ugly, but it would be more currently unneeded work 591 // This assert is kinda ugly, but it would be more currently unneeded work
593 // to support painting a border that isn't 1 pixel thick. There is no point 592 // to support painting a border that isn't 1 pixel thick. There is no point
594 // in writing that code now, and explode if that day ever comes. 593 // in writing that code now, and explode if that day ever comes.
595 COMPILE_ASSERT(kBorderThickness == 1, border_1px_implied); 594 COMPILE_ASSERT(kBorderThickness == 1, border_1px_implied);
596 // Draw the 1px border around the entire window. 595 // Draw the 1px border around the entire window.
597 gdk_draw_rectangle(drawable, gc, FALSE, 596 gdk_cairo_set_source_color(cr, &border_color_);
598 0, 0, 597 cairo_rectangle(cr, 0, 0, window_rect.width(), window_rect.height());
599 window_rect.width() - 1, window_rect.height() - 1); 598 cairo_stroke(cr);
600 599
601 pango_layout_set_height(layout_, kHeightPerResult * PANGO_SCALE); 600 pango_layout_set_height(layout_, kHeightPerResult * PANGO_SCALE);
602 601
603 for (size_t i = 0; i < result.size(); ++i) { 602 for (size_t i = 0; i < result.size(); ++i) {
604 gfx::Rect line_rect = GetRectForLine(i, window_rect.width()); 603 gfx::Rect line_rect = GetRectForLine(i, window_rect.width());
605 // Only repaint and layout damaged lines. 604 // Only repaint and layout damaged lines.
606 if (!line_rect.Intersects(damage_rect)) 605 if (!line_rect.Intersects(damage_rect))
607 continue; 606 continue;
608 607
609 const AutocompleteMatch& match = result.match_at(i); 608 const AutocompleteMatch& match = result.match_at(i);
610 bool is_selected = (model_->selected_line() == i); 609 bool is_selected = (model_->selected_line() == i);
611 bool is_hovered = (model_->hovered_line() == i); 610 bool is_hovered = (model_->hovered_line() == i);
612 if (is_selected || is_hovered) { 611 if (is_selected || is_hovered) {
613 gdk_gc_set_rgb_fg_color(gc, is_selected ? &selected_background_color_ : 612 gdk_cairo_set_source_color(cr, is_selected ? &selected_background_color_ :
614 &hovered_background_color_); 613 &hovered_background_color_);
615 // This entry is selected or hovered, fill a rect with the color. 614 // This entry is selected or hovered, fill a rect with the color.
616 gdk_draw_rectangle(drawable, gc, TRUE, 615 cairo_rectangle(cr, line_rect.x(), line_rect.y(),
617 line_rect.x(), line_rect.y(), 616 line_rect.width(), line_rect.height());
618 line_rect.width(), line_rect.height()); 617 cairo_fill(cr);
619 } 618 }
620 619
621 int icon_start_x = ltr ? kIconLeftPadding : 620 int icon_start_x = ltr ? kIconLeftPadding :
622 (line_rect.width() - kIconLeftPadding - kIconWidth); 621 (line_rect.width() - kIconLeftPadding - kIconWidth);
623 // Draw the icon for this result. 622 // Draw the icon for this result.
624 DrawFullPixbuf(drawable, gc, 623 DrawFullImage(cr, widget,
625 IconForMatch(match, is_selected), 624 IconForMatch(match, is_selected),
626 icon_start_x, line_rect.y() + kIconTopPadding); 625 icon_start_x, line_rect.y() + kIconTopPadding);
627 626
628 // Draw the results text vertically centered in the results space. 627 // Draw the results text vertically centered in the results space.
629 // First draw the contents / url, but don't let it take up the whole width 628 // First draw the contents / url, but don't let it take up the whole width
630 // if there is also a description to be shown. 629 // if there is also a description to be shown.
631 bool has_description = !match.description.empty(); 630 bool has_description = !match.description.empty();
632 int text_width = window_rect.width() - (kIconAreaWidth + kRightPadding); 631 int text_width = window_rect.width() - (kIconAreaWidth + kRightPadding);
633 int allocated_content_width = has_description ? 632 int allocated_content_width = has_description ?
634 static_cast<int>(text_width * kContentWidthPercentage) : text_width; 633 static_cast<int>(text_width * kContentWidthPercentage) : text_width;
635 pango_layout_set_width(layout_, allocated_content_width * PANGO_SCALE); 634 pango_layout_set_width(layout_, allocated_content_width * PANGO_SCALE);
636 635
(...skipping 11 matching lines...) Expand all
648 pango_layout_get_size(layout_, 647 pango_layout_get_size(layout_,
649 &actual_content_width, &actual_content_height); 648 &actual_content_width, &actual_content_height);
650 actual_content_width /= PANGO_SCALE; 649 actual_content_width /= PANGO_SCALE;
651 actual_content_height /= PANGO_SCALE; 650 actual_content_height /= PANGO_SCALE;
652 651
653 // DCHECK_LT(actual_content_height, kHeightPerResult); // Font is too tall. 652 // DCHECK_LT(actual_content_height, kHeightPerResult); // Font is too tall.
654 // Center the text within the line. 653 // Center the text within the line.
655 int content_y = std::max(line_rect.y(), 654 int content_y = std::max(line_rect.y(),
656 line_rect.y() + ((kHeightPerResult - actual_content_height) / 2)); 655 line_rect.y() + ((kHeightPerResult - actual_content_height) / 2));
657 656
658 gdk_draw_layout(drawable, gc, 657 cairo_save(cr);
659 ltr ? kIconAreaWidth : 658 cairo_move_to(cr,
659 ltr ? kIconAreaWidth :
660 (text_width - actual_content_width), 660 (text_width - actual_content_width),
661 content_y, layout_); 661 content_y);
662 pango_cairo_show_layout(cr, layout_);
663 cairo_restore(cr);
662 664
663 if (has_description) { 665 if (has_description) {
664 pango_layout_set_width(layout_, 666 pango_layout_set_width(layout_,
665 (text_width - actual_content_width) * PANGO_SCALE); 667 (text_width - actual_content_width) * PANGO_SCALE);
666 668
667 // In Windows, a boolean "force_dim" is passed as true for the 669 // In Windows, a boolean "force_dim" is passed as true for the
668 // description. Here, we pass the dim text color for both normal and dim, 670 // description. Here, we pass the dim text color for both normal and dim,
669 // to accomplish the same thing. 671 // to accomplish the same thing.
670 SetupLayoutForMatch(layout_, match.description, match.description_class, 672 SetupLayoutForMatch(layout_, match.description, match.description_class,
671 is_selected ? &selected_content_dim_text_color_ : 673 is_selected ? &selected_content_dim_text_color_ :
672 &content_dim_text_color_, 674 &content_dim_text_color_,
673 is_selected ? &selected_content_dim_text_color_ : 675 is_selected ? &selected_content_dim_text_color_ :
674 &content_dim_text_color_, 676 &content_dim_text_color_,
675 is_selected ? &url_selected_text_color_ : 677 is_selected ? &url_selected_text_color_ :
676 &url_text_color_, 678 &url_text_color_,
677 std::string(" - ")); 679 std::string(" - "));
678 gint actual_description_width; 680 gint actual_description_width;
679 pango_layout_get_size(layout_, &actual_description_width, NULL); 681 pango_layout_get_size(layout_, &actual_description_width, NULL);
680 gdk_draw_layout(drawable, gc, ltr ? 682
681 (kIconAreaWidth + actual_content_width) : 683 cairo_save(cr);
682 (text_width - actual_content_width - 684 cairo_move_to(cr, ltr ?
683 (actual_description_width / PANGO_SCALE)), 685 (kIconAreaWidth + actual_content_width) :
684 content_y, layout_); 686 (text_width - actual_content_width -
687 (actual_description_width / PANGO_SCALE)),
688 content_y);
689 pango_cairo_show_layout(cr, layout_);
690 cairo_restore(cr);
685 } 691 }
686 } 692 }
687 693
688 g_object_unref(gc); 694 cairo_destroy(cr);
689
690 return TRUE; 695 return TRUE;
691 } 696 }
OLDNEW
« no previous file with comments | « chrome/browser/ui/gtk/omnibox/omnibox_popup_view_gtk.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698