diff --git a/demos/gtk-demo/Makefile.am b/demos/gtk-demo/Makefile.am
index 80927d0cbe..8c15e16633 100644
--- a/demos/gtk-demo/Makefile.am
+++ b/demos/gtk-demo/Makefile.am
@@ -14,6 +14,7 @@ demos_base = \
combobox.c \
css_accordion.c \
css_basics.c \
+ css_blendmodes.c \
css_multiplebgs.c \
css_pixbufs.c \
css_shadows.c \
diff --git a/demos/gtk-demo/blendmodes.ui b/demos/gtk-demo/blendmodes.ui
new file mode 100644
index 0000000000..9badf330dc
--- /dev/null
+++ b/demos/gtk-demo/blendmodes.ui
@@ -0,0 +1,391 @@
+
+
+
+
+
diff --git a/demos/gtk-demo/blends.png b/demos/gtk-demo/blends.png
new file mode 100644
index 0000000000..afc6c4abc1
Binary files /dev/null and b/demos/gtk-demo/blends.png differ
diff --git a/demos/gtk-demo/cmy.jpg b/demos/gtk-demo/cmy.jpg
new file mode 100644
index 0000000000..f44d0966da
Binary files /dev/null and b/demos/gtk-demo/cmy.jpg differ
diff --git a/demos/gtk-demo/css_blendmodes.c b/demos/gtk-demo/css_blendmodes.c
new file mode 100644
index 0000000000..4c4e6730a8
--- /dev/null
+++ b/demos/gtk-demo/css_blendmodes.c
@@ -0,0 +1,178 @@
+/* Theming/CSS Blend Modes
+ *
+ * You can blend multiple backgrounds using the CSS blend modes available.
+ */
+
+#include
+
+#define WID(x) ((GtkWidget*) gtk_builder_get_object (builder, x))
+
+/*
+ * These are the available blend modes.
+ */
+struct {
+ gchar *name;
+ gchar *id;
+} blend_modes[] =
+{
+ { "Color", "color" },
+ { "Color (burn)", "color-burn" },
+ { "Color (dodge)", "color-dodge" },
+ { "Darken", "darken" },
+ { "Difference", "difference" },
+ { "Exclusion", "exclusion" },
+ { "Hard Light", "hard-light" },
+ { "Hue", "hue" },
+ { "Lighten", "lighten" },
+ { "Luminosity", "luminosity" },
+ { "Multiply", "multiply" },
+ { "Normal", "normal" },
+ { "Overlay", "overlay" },
+ { "Saturate", "saturate" },
+ { "Screen", "screen" },
+ { "Soft Light", "soft-light" },
+ { NULL }
+};
+
+/*
+ * The CSS class to be applied in the blended image. Notice that the first %s
+ * is replaced by the content of css_blendmodes.css and the second %s is
+ * replaced by the blend mode.
+ */
+static const gchar *CSS_TEMPLATE =
+"%s\n"
+"\n"
+"image.blend0 {\n"
+" background-image: url('resource://css_blendmodes/ducky.png'),\n"
+" linear-gradient(to right, red 0%, green 50%, blue 100%);\n"
+" background-size: cover;\n"
+" background-blend-mode: %s;\n"
+" min-width: 200px;\n"
+" min-height: 200px;\n"
+"}\n"
+"\n"
+"image.blend1 {\n"
+" background: url('resource://css_blendmodes/blends.png') top center,\n"
+" url('resource://css_blendmodes/blends.png') bottom center;\n"
+" background-blend-mode: %s;\n"
+" min-width: 200px;\n"
+" min-height: 200px;\n"
+"}\n"
+"\n"
+"image.blend2 {\n"
+" background: url('resource://css_blendmodes/cmy.jpg') top center,\n"
+" url('resource://css_blendmodes/cmy.jpg') center center,\n"
+" url('resource://css_blendmodes/cmy.jpg') bottom center;\n"
+" background-blend-mode: %s;\n"
+" min-width: 200px;\n"
+" min-height: 200px;\n"
+"}\n";
+
+static void
+update_css_for_blend_mode (GtkCssProvider *provider,
+ const gchar *blend_mode)
+{
+ GBytes *bytes;
+ gchar *css;
+
+ bytes = g_resources_lookup_data ("/css_blendmodes/css_blendmodes.css", 0, NULL);
+
+ css = g_strdup_printf (CSS_TEMPLATE,
+ (gchar*) g_bytes_get_data (bytes, NULL),
+ blend_mode,
+ blend_mode,
+ blend_mode);
+
+ gtk_css_provider_load_from_data (provider, css, -1, NULL);
+
+ g_bytes_unref (bytes);
+ g_free (css);
+}
+
+static void
+row_activated (GtkListBox *listbox,
+ GtkListBoxRow *row,
+ GtkCssProvider *provider)
+{
+ const gchar *blend_mode;
+
+ blend_mode = blend_modes[gtk_list_box_row_get_index (row)].id;
+
+ update_css_for_blend_mode (provider, blend_mode);
+}
+
+static void
+setup_listbox (GtkBuilder *builder,
+ GtkStyleProvider *provider)
+{
+ GtkWidget *normal_row;
+ GtkWidget *listbox;
+ gint i;
+
+ normal_row = NULL;
+ listbox = gtk_list_box_new ();
+ gtk_container_add (GTK_CONTAINER (WID ("scrolledwindow")), listbox);
+
+ g_signal_connect (listbox, "row-activated", G_CALLBACK (row_activated), provider);
+
+ /* Add a row for each blend mode available */
+ for (i = 0; blend_modes[i].name != NULL; i++)
+ {
+ GtkWidget *label;
+ GtkWidget *row;
+
+ row = gtk_list_box_row_new ();
+ label = g_object_new (GTK_TYPE_LABEL,
+ "label", blend_modes[i].name,
+ "xalign", 0.0,
+ NULL);
+
+ gtk_container_add (GTK_CONTAINER (row), label);
+
+ gtk_container_add (GTK_CONTAINER (listbox), row);
+
+ /* The first selected row is "normal" */
+ if (g_strcmp0 (blend_modes[i].id, "normal") == 0)
+ normal_row = row;
+ }
+
+ /* Select the "normal" row */
+ gtk_list_box_select_row (GTK_LIST_BOX (listbox), GTK_LIST_BOX_ROW (normal_row));
+ g_signal_emit_by_name (G_OBJECT (normal_row), "activate");
+
+ gtk_widget_grab_focus (normal_row);
+}
+
+GtkWidget *
+do_css_blendmodes (GtkWidget *do_widget)
+{
+ static GtkWidget *window = NULL;
+
+ if (!window)
+ {
+ GtkStyleProvider *provider;
+ GtkBuilder *builder;
+
+ builder = gtk_builder_new_from_resource ("/css_blendmodes/blendmodes.ui");
+
+ window = WID ("window");
+ gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (do_widget));
+ g_signal_connect (window, "destroy", G_CALLBACK (gtk_widget_destroyed), &window);
+
+ /* Setup the CSS provider for window */
+ provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
+
+ gtk_style_context_add_provider_for_screen (gdk_screen_get_default (),
+ provider,
+ GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+
+ setup_listbox (builder, provider);
+ }
+
+ if (!gtk_widget_get_visible (window))
+ gtk_widget_show_all (window);
+ else
+ gtk_widget_destroy (window);
+
+ return window;
+}
diff --git a/demos/gtk-demo/css_blendmodes.css b/demos/gtk-demo/css_blendmodes.css
new file mode 100644
index 0000000000..b212e50760
--- /dev/null
+++ b/demos/gtk-demo/css_blendmodes.css
@@ -0,0 +1,51 @@
+/*
+ * First page.
+ */
+image.duck {
+ background-image: url('resource://css_blendmodes/ducky.png');
+ background-size: cover;
+ min-width: 200px;
+ min-height: 200px;
+}
+
+image.gradient {
+ background-image: linear-gradient(to right, red 0%, green 50%, blue 100%);
+ min-width: 200px;
+ min-height: 200px;
+}
+
+/*
+ * Second page.
+ */
+image.red {
+ background: url('resource://css_blendmodes/blends.png') top center;
+ min-width: 200px;
+ min-height: 200px;
+}
+
+image.blue {
+ background: url('resource://css_blendmodes/blends.png') bottom center;
+ min-width: 200px;
+ min-height: 200px;
+}
+
+/*
+ * Third page.
+ */
+image.cyan {
+ background: url('resource://css_blendmodes/cmy.jpg') top center;
+ min-width: 200px;
+ min-height: 200px;
+}
+
+image.magenta {
+ background: url('resource://css_blendmodes/cmy.jpg') center center;
+ min-width: 200px;
+ min-height: 200px;
+}
+
+image.yellow {
+ background: url('resource://css_blendmodes/cmy.jpg') bottom center;
+ min-width: 200px;
+ min-height: 200px;
+}
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index 4b30c67c4b..f0c7201f3c 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -20,6 +20,13 @@
css_basics.css
reset.css
+
+ css_blendmodes.css
+ blendmodes.ui
+ blends.png
+ ducky.png
+ cmy.jpg
+
css_multiplebgs.css
brick.png
@@ -130,6 +137,7 @@
combobox.c
css_accordion.c
css_basics.c
+ css_blendmodes.c
css_multiplebgs.c
css_pixbufs.c
css_shadows.c
diff --git a/demos/gtk-demo/ducky.png b/demos/gtk-demo/ducky.png
new file mode 100644
index 0000000000..f1cbd35250
Binary files /dev/null and b/demos/gtk-demo/ducky.png differ