bug 1211892 read -unico-border-gradient of early Unico versions for ThreeDHighlight and ThreeDShadow r=acomminos
authorKarl Tomlinson <karlt+@karlt.net>
Fri, 18 Mar 2016 22:49:46 +1300
changeset 289621 ea2b3a89986eacac865dd97b9fd306a275bbe48b
parent 289620 b0e2c28119d871c1d30c66331e9d47cf4468054a
child 289622 2678b91f4165e884f043df42bcddc91f91d2bb69
push id19656
push usergwagner@mozilla.com
push dateMon, 04 Apr 2016 13:43:23 +0000
treeherderb2g-inbound@e99061fde28a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersacomminos
bugs1211892
milestone48.0a1
bug 1211892 read -unico-border-gradient of early Unico versions for ThreeDHighlight and ThreeDShadow r=acomminos MozReview-Commit-ID: KWfQqT5MIjT
config/system-headers
widget/gtk/mozgtk/mozgtk.c
widget/gtk/nsLookAndFeel.cpp
--- a/config/system-headers
+++ b/config/system-headers
@@ -240,16 +240,17 @@ builtin.h
 Button.h
 byteswap.h
 pixman.h
 cairo.h
 cairo-atsui.h
 cairo-beos.h
 cairo-ft.h
 cairo-glitz.h
+cairo-gobject.h
 cairo-pdf.h
 cairo-ps.h
 cairo-tee.h
 cairo-quartz.h
 cairo-win32.h
 cairo-xlib.h
 cairo-xlib-xrender.h
 cairo-directfb.h
--- a/widget/gtk/mozgtk/mozgtk.c
+++ b/widget/gtk/mozgtk/mozgtk.c
@@ -546,24 +546,27 @@ STUB(gtk_style_context_add_class)
 STUB(gtk_style_context_add_region)
 STUB(gtk_style_context_get)
 STUB(gtk_style_context_get_background_color)
 STUB(gtk_style_context_get_border)
 STUB(gtk_style_context_get_border_color)
 STUB(gtk_style_context_get_color)
 STUB(gtk_style_context_get_margin)
 STUB(gtk_style_context_get_padding)
+STUB(gtk_style_context_get_property)
+STUB(gtk_style_context_get_state)
 STUB(gtk_style_context_has_class)
 STUB(gtk_style_context_new)
 STUB(gtk_style_context_remove_class)
 STUB(gtk_style_context_remove_region)
 STUB(gtk_style_context_restore)
 STUB(gtk_style_context_save)
 STUB(gtk_style_context_set_path)
 STUB(gtk_style_context_set_state)
+STUB(gtk_style_properties_lookup_property)
 STUB(gtk_tree_view_column_get_button)
 STUB(gtk_widget_get_preferred_size)
 STUB(gtk_widget_get_state_flags)
 STUB(gtk_widget_get_style_context)
 STUB(gtk_widget_path_append_type)
 STUB(gtk_widget_path_free)
 STUB(gtk_widget_path_new)
 STUB(gtk_widget_set_visual)
--- a/widget/gtk/nsLookAndFeel.cpp
+++ b/widget/gtk/nsLookAndFeel.cpp
@@ -24,16 +24,20 @@
 #include "nsStyleConsts.h"
 #include "gfxFontConstants.h"
 #include "WidgetUtils.h"
 
 #include <dlfcn.h>
 
 #include "mozilla/gfx/2D.h"
 
+#if MOZ_WIDGET_GTK != 2
+#include <cairo-gobject.h>
+#endif
+
 using mozilla::LookAndFeel;
 
 #define GDK_COLOR_TO_NS_RGB(c) \
     ((nscolor) NS_RGB(c.red>>8, c.green>>8, c.blue>>8))
 #define GDK_RGBA_TO_NS_RGBA(c) \
     ((nscolor) NS_RGBA((int)((c).red*255), (int)((c).green*255), \
                        (int)((c).blue*255), (int)((c).alpha*255)))
 
@@ -56,16 +60,131 @@ nsLookAndFeel::~nsLookAndFeel()
 #if (MOZ_WIDGET_GTK == 2)
     g_object_unref(mStyle);
 #else
     g_object_unref(mBackgroundStyle);
     g_object_unref(mButtonStyle);
 #endif
 }
 
+#if MOZ_WIDGET_GTK != 2
+static void
+GetLightAndDarkness(const GdkRGBA& aColor,
+                    double* aLightness, double* aDarkness)
+{
+    double sum = aColor.red + aColor.green + aColor.blue;
+    *aLightness = sum * aColor.alpha;
+    *aDarkness = (3.0 - sum) * aColor.alpha;
+}
+
+static bool
+GetGradientColors(const GValue* aValue,
+                  GdkRGBA* aLightColor, GdkRGBA* aDarkColor)
+{
+    if (!G_TYPE_CHECK_VALUE_TYPE(aValue, CAIRO_GOBJECT_TYPE_PATTERN))
+        return false;
+
+    auto pattern = static_cast<cairo_pattern_t*>(g_value_get_boxed(aValue));
+
+    // Just picking the lightest and darkest colors as simple samples rather
+    // than trying to blend, which could get messy if there are many stops.
+    if (CAIRO_STATUS_SUCCESS !=
+        cairo_pattern_get_color_stop_rgba(pattern, 0, nullptr, &aDarkColor->red,
+                                          &aDarkColor->green, &aDarkColor->blue,
+                                          &aDarkColor->alpha))
+        return false;
+
+    double maxLightness, maxDarkness;
+    GetLightAndDarkness(*aDarkColor, &maxLightness, &maxDarkness);
+    *aLightColor = *aDarkColor;
+
+    GdkRGBA stop;
+    for (int index = 1;
+         CAIRO_STATUS_SUCCESS ==
+             cairo_pattern_get_color_stop_rgba(pattern, index, nullptr,
+                                               &stop.red, &stop.green,
+                                               &stop.blue, &stop.alpha);
+         ++index) {
+        double lightness, darkness;
+        GetLightAndDarkness(stop, &lightness, &darkness);
+        if (lightness > maxLightness) {
+            maxLightness = lightness;
+            *aLightColor = stop;
+        }
+        if (darkness > maxDarkness) {
+            maxDarkness = darkness;
+            *aDarkColor = stop;
+        }
+    }
+
+    return true;
+}
+
+static bool
+GetUnicoBorderGradientColors(GtkStyleContext* aContext,
+                             GdkRGBA* aLightColor, GdkRGBA* aDarkColor)
+{
+    // Ubuntu 12.04 has GTK engine Unico-1.0.2, which overrides render_frame,
+    // providing its own border code.  Ubuntu 14.04 has
+    // Unico-1.0.3+14.04.20140109, which does not override render_frame, and
+    // so does not need special attention.  The earlier Unico can be detected
+    // by the -unico-border-gradient style property it registers.
+    // gtk_style_properties_lookup_property() is checked first to avoid the
+    // warning from gtk_style_context_get_property() when the property does
+    // not exist.  (gtk_render_frame() of GTK+ 3.16 no longer uses the
+    // engine.)
+    const char* propertyName = "-unico-border-gradient";
+    if (!gtk_style_properties_lookup_property(propertyName, nullptr, nullptr))
+        return false;
+
+    // -unico-border-gradient is used only when the CSS node's engine is Unico.
+    GtkThemingEngine* engine;
+    GtkStateFlags state = gtk_style_context_get_state(aContext);
+    gtk_style_context_get(aContext, state, "engine", &engine, nullptr);
+    if (strcmp(g_type_name(G_TYPE_FROM_INSTANCE(engine)), "UnicoEngine") != 0)
+        return false;
+
+    // draw_border() of Unico engine uses -unico-border-gradient
+    // in preference to border-color.
+    GValue value = G_VALUE_INIT;
+    gtk_style_context_get_property(aContext, propertyName, state, &value);
+
+    bool result = GetGradientColors(&value, aLightColor, aDarkColor);
+
+    g_value_unset(&value);
+    return result;
+}
+
+
+static void
+GetBorderColors(GtkStyleContext* aContext,
+                GdkRGBA* aLightColor, GdkRGBA* aDarkColor)
+{
+    if (GetUnicoBorderGradientColors(aContext, aLightColor, aDarkColor))
+        return;
+
+    GtkStateFlags state = gtk_style_context_get_state(aContext);
+    gtk_style_context_get_border_color(aContext, state, aDarkColor);
+    // TODO GTK3 - update aLightColor
+    // for GTK_BORDER_STYLE_INSET/OUTSET/GROVE/RIDGE border styles.
+    // https://bugzilla.mozilla.org/show_bug.cgi?id=978172#c25
+    *aLightColor = *aDarkColor;
+}
+
+static void
+GetBorderColors(GtkStyleContext* aContext,
+                nscolor* aLightColor, nscolor* aDarkColor)
+{
+    GdkRGBA lightColor, darkColor;
+    GetBorderColors(aContext, &lightColor, &darkColor);
+    *aLightColor = GDK_RGBA_TO_NS_RGBA(lightColor);
+    *aDarkColor = GDK_RGBA_TO_NS_RGBA(darkColor);
+}
+#endif
+
 nsresult
 nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor)
 {
 #if (MOZ_WIDGET_GTK == 3)
     GdkRGBA gdk_color;
 #endif
     nsresult res = NS_OK;
 
@@ -1196,22 +1315,18 @@ nsLookAndFeel::Init()
     gtk_style_context_save(style);
     gtk_style_context_add_region(style, GTK_STYLE_REGION_ROW, GTK_REGION_ODD);
     gtk_style_context_get_background_color(style, GTK_STATE_FLAG_NORMAL, &color);
     sOddCellBackground = GDK_RGBA_TO_NS_RGBA(color);
     gtk_style_context_restore(style);
 
     GtkWidget *frame = gtk_frame_new(nullptr);
     gtk_container_add(GTK_CONTAINER(parent), frame);
-
-    // TODO GTK3 - update sFrameOuterLightBorder 
-    // for GTK_BORDER_STYLE_INSET/OUTSET/GROVE/RIDGE border styles (Bug 978172).
     style = gtk_widget_get_style_context(frame);
-    gtk_style_context_get_border_color(style, GTK_STATE_FLAG_NORMAL, &color);
-    sFrameInnerDarkBorder = sFrameOuterLightBorder = GDK_RGBA_TO_NS_RGBA(color);
+    GetBorderColors(style, &sFrameOuterLightBorder, &sFrameInnerDarkBorder);
 
     gtk_widget_path_free(path);
 
     // GtkInfoBar
     GtkWidget* infoBar = gtk_info_bar_new();
     GtkWidget* infoBarContent = gtk_info_bar_get_content_area(GTK_INFO_BAR(infoBar));
     GtkWidget* infoBarLabel = gtk_label_new(nullptr);
     gtk_container_add(GTK_CONTAINER(parent), infoBar);