Chromium Code Reviews| Index: chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc |
| diff --git a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc |
| index 5df1bdcef9f1bea5ddab2ef80c96dbcaeed4318b..3cef23f6472d1ac8d5d2709607d09e3562a21f2e 100644 |
| --- a/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc |
| +++ b/chrome/browser/ui/gtk/autofill/autofill_popup_view_gtk.cc |
| @@ -5,7 +5,41 @@ |
| #include "autofill_popup_view_gtk.h" |
| #include "base/logging.h" |
| +#include "base/utf_string_conversions.h" |
| +#include "ui/gfx/rect.h" |
| +#include "ui/gfx/native_widget_types.h" |
| +#include "ui/base/gtk/gtk_hig_constants.h" |
| #include "ui/base/gtk/gtk_windowing.h" |
| +#include "ui/gfx/font.h" |
| + |
| +namespace { |
| +const GdkColor kTextColor = GDK_COLOR_RGB(0x00, 0x00, 0x00); |
| +const int kMiddlePadding = 10; |
| + |
| +gfx::Rect GetWindowRect(GdkWindow* window) { |
| + gint width, height; |
| + gdk_drawable_get_size(GDK_DRAWABLE(window), &width, &height); |
| + return gfx::Rect(width, height); |
| +} |
| + |
| +gfx::Rect GetRectForLine(size_t line, int width, int height) { |
| + return gfx::Rect(0, (line * height), width, height); |
| +} |
| + |
| +void SetTextToDraw(PangoLayout* layout, |
| + const string16& text) { |
| + // Pango is really easy to overflow and send into a computational death |
| + // spiral that can corrupt the screen. Assume that we'll never have more than |
| + // 2000 characters, which should be a safe assumption until we all get robot |
| + // eyes. http://crbug.com/66576 |
| + std::string text_utf8 = UTF16ToUTF8(text); |
| + if (text_utf8.length() > 2000) |
| + text_utf8 = text_utf8.substr(0, 2000); |
| + |
| + pango_layout_set_text(layout, text_utf8.data(), text_utf8.length()); |
| +} |
| + |
| +} // namespace |
| AutofillPopupViewGtk::AutofillPopupViewGtk(content::WebContents* web_contents, |
| GtkWidget* parent) |
| @@ -21,9 +55,15 @@ AutofillPopupViewGtk::AutofillPopupViewGtk(content::WebContents* web_contents, |
| gtk_widget_add_events(window_, GDK_EXPOSURE_MASK); |
| g_signal_connect(window_, "expose-event", |
| G_CALLBACK(HandleExposeThunk), this); |
| + |
| + // Cache the layout so we don't have to create it for every expose. |
| + layout_ = gtk_widget_create_pango_layout(window_, NULL); |
| + |
| + row_height_ = font_.GetHeight(); |
| } |
| AutofillPopupViewGtk::~AutofillPopupViewGtk() { |
| + g_object_unref(layout_); |
| gtk_widget_destroy(window_); |
| } |
| @@ -31,23 +71,34 @@ void AutofillPopupViewGtk::Hide() { |
| gtk_widget_hide(window_); |
| } |
| -// TODO(csharp): Actually show the values. |
| -void AutofillPopupViewGtk::Show(const std::vector<string16>& autofill_values, |
| - const std::vector<string16>& autofill_labels, |
| - const std::vector<string16>& autofill_icons, |
| - const std::vector<int>& autofill_unique_ids, |
| - int separator_index) { |
| +void AutofillPopupViewGtk::ShowInternal( |
| + const std::vector<string16>& autofill_values, |
| + const std::vector<string16>& autofill_labels, |
| + const std::vector<string16>& autofill_icons) { |
| gint origin_x, origin_y; |
| gdk_window_get_origin(gtk_widget_get_window(parent_), &origin_x, &origin_y); |
| + // Move the popup to appear right below the text field it is using. |
| gtk_window_move(GTK_WINDOW(window_), |
| origin_x + element_bounds().x(), |
| origin_y + element_bounds().y() + element_bounds().height()); |
| + // Find out the maximum bounds required by the popup. |
| + // TODO(csharp): Once the icon is also displayed it will affect the required |
| + // size so it will need to be include in the calculation. |
| + int popup_required_width = element_bounds().width(); |
| + CHECK_EQ(autofill_values.size(), autofill_labels.size()); |
| + for (size_t i = 0; i < autofill_values.size(); ++i) { |
| + popup_required_width = std::max(popup_required_width, |
| + font_.GetStringWidth(autofill_values[i]) + |
| + kMiddlePadding + |
| + font_.GetStringWidth(autofill_labels[i])); |
| + } |
| + |
| gtk_widget_set_size_request( |
| window_, |
| - element_bounds().width(), |
| - element_bounds().height() * autofill_values.size()); |
| + popup_required_width, |
| + row_height_ * autofill_values.size()); |
| gtk_widget_show(window_); |
| @@ -58,5 +109,55 @@ void AutofillPopupViewGtk::Show(const std::vector<string16>& autofill_values, |
| gboolean AutofillPopupViewGtk::HandleExpose(GtkWidget* widget, |
| GdkEventExpose* event) { |
| + gfx::Rect window_rect = GetWindowRect(event->window); |
| + gfx::Rect damage_rect = gfx::Rect(event->area); |
| + |
| + GdkDrawable* drawable = GDK_DRAWABLE(event->window); |
| + GdkGC* gc = gdk_gc_new(drawable); |
|
Elliot Glaysher
2012/01/11 19:01:47
Please don't use GdkGC or other deprecated stuff.
csharp
2012/01/11 22:40:04
Sorry about that, I grab the code in early Decembe
|
| + |
| + SetupLayout(window_rect, &kTextColor); |
| + |
| + for (size_t i = 0; i < autofill_values().size(); ++i) { |
| + gfx::Rect line_rect = GetRectForLine(i, window_rect.width(), row_height_); |
| + // Only repaint and layout damaged lines. |
| + if (!line_rect.Intersects(damage_rect)) |
| + continue; |
| + |
| + if (separator_index() == static_cast<int>(i)) { |
| + int line_y = i * row_height_; |
| + gdk_draw_line(drawable, gc, 0, line_y, window_rect.width(), line_y); |
| + } |
| + |
| + // Draw the autofill value. |
| + SetTextToDraw(layout_, autofill_values()[i]); |
| + gdk_draw_layout(drawable, gc, 0, line_rect.y(), layout_); |
| + |
| + // Draw the autofill label. |
| + int x_align_left = window_rect.width() |
| + - font_.GetStringWidth(autofill_labels()[i]); |
| + SetTextToDraw(layout_, autofill_labels()[i]); |
| + gdk_draw_layout(drawable, gc, x_align_left, line_rect.y(), layout_); |
| + } |
| + |
| + g_object_unref(gc); |
| + |
| return TRUE; |
| } |
| + |
| +void AutofillPopupViewGtk::SetupLayout(const gfx::Rect& window_rect, |
| + const GdkColor* text_color) { |
| + int allocated_content_width = window_rect.width(); |
| + pango_layout_set_width(layout_, allocated_content_width * PANGO_SCALE); |
| + pango_layout_set_height(layout_, row_height_ * PANGO_SCALE); |
| + |
| + PangoAttrList* attrs = pango_attr_list_new(); |
| + |
| + PangoAttribute* fg_attr = pango_attr_foreground_new(text_color->red, |
| + text_color->green, |
| + text_color->blue); |
| + pango_attr_list_insert(attrs, fg_attr); // Ownership taken. |
| + |
| + |
| + pango_layout_set_attributes(layout_, attrs); // Ref taken. |
| + pango_attr_list_unref(attrs); |
| +} |