Gtk3: Refactor GtkButtonImageSource::GetImageForScale

This CL refactors GetImageForScale() on Gtk3 so no widget gets created.  Only
a GtkStyleContext is needed.

In addition, it adds GtkStateFlagFocused to the style context if |focus_| is true.
This fixes focused button rendering on Ambiance, which doesn't use a focus
rectangle, but instead changes the button's border directly.

BUG=695357
R=erg@chromium.org

Review-Url: https://codereview.chromium.org/2715153002
Cr-Commit-Position: refs/heads/master@{#453292}
diff --git a/chrome/browser/ui/libgtkui/gtk_ui.cc b/chrome/browser/ui/libgtkui/gtk_ui.cc
index 50e6fbff..9bdb18c 100644
--- a/chrome/browser/ui/libgtkui/gtk_ui.cc
+++ b/chrome/browser/ui/libgtkui/gtk_ui.cc
@@ -116,6 +116,12 @@
     border.allocN32Pixels(width, height);
     border.eraseColor(0);
 
+    cairo_surface_t* surface = cairo_image_surface_create_for_data(
+        static_cast<unsigned char*>(border.getAddr(0, 0)), CAIRO_FORMAT_ARGB32,
+        width, height, width * 4);
+    cairo_t* cr = cairo_create(surface);
+
+#if GTK_MAJOR_VERSION == 2
     // Create a temporary GTK button to snapshot
     GtkWidget* window = gtk_offscreen_window_new();
     GtkWidget* button = gtk_toggle_button_new();
@@ -133,12 +139,6 @@
 
     gtk_widget_show_all(window);
 
-    cairo_surface_t* surface = cairo_image_surface_create_for_data(
-        static_cast<unsigned char*>(border.getAddr(0, 0)), CAIRO_FORMAT_ARGB32,
-        width, height, width * 4);
-    cairo_t* cr = cairo_create(surface);
-
-#if GTK_MAJOR_VERSION == 2
     if (focus_)
       GTK_WIDGET_SET_FLAGS(button, GTK_HAS_FOCUS);
 
@@ -161,8 +161,18 @@
 
     g_object_unref(pixbuf);
     g_object_unref(pixmap);
+
+    gtk_widget_destroy(window);
 #else
-    GtkStyleContext* context = gtk_widget_get_style_context(button);
+    ScopedStyleContext context = GetStyleContextFromCss(
+        is_blue_ ? "GtkButton#button.default.suggested-action"
+                 : "GtkButton#button");
+    GtkStateFlags state_flags = StateToStateFlags(state_);
+    if (focus_) {
+      state_flags =
+          static_cast<GtkStateFlags>(state_flags | GTK_STATE_FLAG_FOCUSED);
+    }
+    gtk_style_context_set_state(context, state_flags);
     gtk_render_background(context, cr, 0, 0, width, height);
     gtk_render_frame(context, cr, 0, 0, width, height);
     if (focus_)
@@ -172,8 +182,6 @@
     cairo_destroy(cr);
     cairo_surface_destroy(surface);
 
-    gtk_widget_destroy(window);
-
     return gfx::ImageSkiaRep(border, scale);
   }
 
diff --git a/chrome/browser/ui/libgtkui/gtk_util.cc b/chrome/browser/ui/libgtkui/gtk_util.cc
index 23808239b..6c10b43 100644
--- a/chrome/browser/ui/libgtkui/gtk_util.cc
+++ b/chrome/browser/ui/libgtkui/gtk_util.cc
@@ -278,6 +278,23 @@
     return false;
 }
 
+GtkStateFlags StateToStateFlags(ui::NativeTheme::State state) {
+  switch (state) {
+    case ui::NativeTheme::kDisabled:
+      return GTK_STATE_FLAG_INSENSITIVE;
+    case ui::NativeTheme::kHovered:
+      return GTK_STATE_FLAG_PRELIGHT;
+    case ui::NativeTheme::kNormal:
+      return GTK_STATE_FLAG_NORMAL;
+    case ui::NativeTheme::kPressed:
+      return static_cast<GtkStateFlags>(GTK_STATE_FLAG_PRELIGHT |
+                                        GTK_STATE_FLAG_ACTIVE);
+    default:
+      NOTREACHED();
+      return GTK_STATE_FLAG_NORMAL;
+  }
+}
+
 ScopedStyleContext AppendCssNodeToStyleContext(GtkStyleContext* context,
                                                const std::string& css_node) {
   GtkWidgetPath* path =
diff --git a/chrome/browser/ui/libgtkui/gtk_util.h b/chrome/browser/ui/libgtkui/gtk_util.h
index c87f70e0a..1598d99 100644
--- a/chrome/browser/ui/libgtkui/gtk_util.h
+++ b/chrome/browser/ui/libgtkui/gtk_util.h
@@ -177,6 +177,9 @@
 typedef ScopedGObject<GtkStyleContext> ScopedStyleContext;
 typedef ScopedGObject<GtkCssProvider> ScopedCssProvider;
 
+// Converts ui::NativeTheme::State to GtkStateFlags.
+GtkStateFlags StateToStateFlags(ui::NativeTheme::State state);
+
 // If |context| is nullptr, creates a new top-level style context
 // specified by parsing |css_node|.  Otherwise, creates the child
 // context with |context| as the parent.
diff --git a/chrome/browser/ui/libgtkui/native_theme_gtk3.cc b/chrome/browser/ui/libgtkui/native_theme_gtk3.cc
index 2bf1e90..af7ea82 100644
--- a/chrome/browser/ui/libgtkui/native_theme_gtk3.cc
+++ b/chrome/browser/ui/libgtkui/native_theme_gtk3.cc
@@ -63,23 +63,6 @@
       rect.y());
 }
 
-GtkStateFlags StateToStateFlags(NativeThemeGtk3::State state) {
-  switch (state) {
-    case NativeThemeGtk3::kDisabled:
-      return GTK_STATE_FLAG_INSENSITIVE;
-    case NativeThemeGtk3::kHovered:
-      return GTK_STATE_FLAG_PRELIGHT;
-    case NativeThemeGtk3::kNormal:
-      return GTK_STATE_FLAG_NORMAL;
-    case NativeThemeGtk3::kPressed:
-      return static_cast<GtkStateFlags>(GTK_STATE_FLAG_PRELIGHT |
-                                        GTK_STATE_FLAG_ACTIVE);
-    default:
-      NOTREACHED();
-      return GTK_STATE_FLAG_NORMAL;
-  }
-}
-
 SkColor SkColorFromColorId(ui::NativeTheme::ColorId color_id) {
   const SkColor kPositiveTextColor = SkColorSetRGB(0x0b, 0x80, 0x43);
   const SkColor kNegativeTextColor = SkColorSetRGB(0xc5, 0x39, 0x29);