Compare commits

...

25 Commits

Author SHA1 Message Date
Timm Bäder
2b5c49fb58 gl renderer: Add simple blend node implementation 2019-04-28 07:46:17 +02:00
Benjamin Otte
c0791ca38e rendernode: Parse and print blend nodes properly 2019-04-28 07:05:08 +02:00
Timm Bäder
8ca1a46272 gl renderer: Move texture labeling below initialization
Apparently genTextures and friends only "reserves names", initializing
them will actually create them. Using glObjectLabel on textures before
initializing them will throw a GL_INVALID_VALUE error.
2019-04-27 10:35:03 +02:00
Timm Bäder
97b688702b gdkglcontext: Limit gl debug label length
There's a maximum length we have to adhere to, otherwise GL throws a
GL_INVALID_VALUE error.
2019-04-27 10:35:01 +02:00
Timm Bäder
31e503aa46 testsuite: Add nodeparser test case
An serialized frame from the widget factory!
2019-04-27 10:35:01 +02:00
Benjamin Otte
5d63bfd285 Add gtk4-node-editor
It's meant to be a little editor for render nodes so we can do testing
with it.
2019-04-27 10:35:01 +02:00
Timm Bäder
78859b9e2a ci: Don't disable the gsk suite 2019-04-27 10:35:01 +02:00
Timm Bäder
d4dd43f93d testsuite: Update clipped_rounded_clip test case 2019-04-27 10:35:01 +02:00
Timm Bäder
ed51dd58b5 Add error func to node deserialization 2019-04-27 10:35:01 +02:00
Timm Bäder
f3742a37db testsuite: Remove another test case
That one's just drawing a 1px outset shadow with rounded corners on top,
which is bound to be slightly different between renderer, hardware
and drivers.
2019-04-27 10:35:01 +02:00
Timm Bäder
f1ebc75f58 testsuite: Remove old cairo/vulkan tests
They are still in the old binary format and haven't worked for a while.
2019-04-27 10:35:01 +02:00
Timm Bäder
0ec6abcedb rendernode: Remove old GVariant (de)serialization code
We're doing the CSS thing now.
2019-04-27 10:35:01 +02:00
Timm Bäder
cc1cc27037 testsuite: Add another gl renderer test 2019-04-27 10:35:01 +02:00
Timm Bäder
b86fd0269e testsuite: Add cross-fade-in-opacity test
Making sure that an opacity node doesn't end up reviving a node that's
hidden because the cross-fade has progress 0 or 1.
2019-04-27 10:35:01 +02:00
Timm Bäder
adb6d5f965 testsuite: Remove broken GL comparison tests
These only work on special hardware, which not even I have anymore.
We'll need to redo them in a way that works on different systems.
2019-04-27 10:35:01 +02:00
Timm Bäder
982524c860 testsuite: Print serialized nodes when parsing fails 2019-04-27 10:35:00 +02:00
Timm Bäder
b56c102f8e testsuite: add shadow node parser test 2019-04-27 10:35:00 +02:00
Timm Bäder
a3daaac009 testsuite: add another nodeparser crash test 2019-04-27 10:35:00 +02:00
Timm Bäder
77ace0a39f testsuite: Add serialize-deserialize tests
Check that we can successfully deserialize a node, then serialize it
again and serialize that result once more.
2019-04-27 10:35:00 +02:00
Timm Bäder
6c9011d181 build: don't use 'continue'
ffs
2019-04-27 10:35:00 +02:00
Benjamin Otte
e6865e1c21 testsuite: Add a broken test
This also adds some build magic so all tests that contain "-3d" in them
won't be added to the Cairo renderer.

Of course, this new test is such a test.
2019-04-27 10:35:00 +02:00
Benjamin Otte
cc20e07347 Move working tests to new directory
These are tests that are working on both GL and Cairo now.

Some tests got black boxes over the areas that aren't easy to compare.
2019-04-27 10:35:00 +02:00
Timm Bäder
e37319193c testsuite: Port gl tests to text-based format 2019-04-27 10:35:00 +02:00
Benjamin Otte
107e462831 testsuite: Add tests for the new node parser
These are just a few crashes I encountered while developing it.
2019-04-27 10:35:00 +02:00
Timm Bäder
76254a18ad Parse render nodes from text files 2019-04-27 10:35:00 +02:00
125 changed files with 7064 additions and 2410 deletions

View File

@@ -32,7 +32,6 @@ xvfb-run -a -s "-screen 0 1024x768x24" \
--timeout-multiplier 2 \
--print-errorlogs \
--suite=gtk \
--no-suite=gtk:gsk \
--no-suite=gtk:a11y
# Save the exit code

View File

@@ -1,3 +1,4 @@
subdir('gtk-demo')
subdir('icon-browser')
subdir('node-editor')
subdir('widget-factory')

28
demos/node-editor/main.c Normal file
View File

@@ -0,0 +1,28 @@
/*
* Copyright © 2019 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include <node-editor-application.h>
int
main (int argc, char *argv[])
{
return g_application_run (G_APPLICATION (node_editor_application_new ()), argc, argv);
}

View File

@@ -0,0 +1,17 @@
node_editor_sources = [
'main.c',
'node-editor-application.c',
'node-editor-window.c',
]
node_editor_resources = gnome.compile_resources('node_editor_resources',
'node-editor.gresource.xml',
source_dir: '.')
executable('gtk4-node-editor',
node_editor_sources, node_editor_resources,
dependencies: libgtk_dep,
include_directories: confinc,
gui_app: true,
link_args: extra_demo_ldflags,
install: false)

View File

@@ -0,0 +1,114 @@
/*
* Copyright © 2019 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "node-editor-application.h"
#include "node-editor-window.h"
struct _NodeEditorApplication
{
GtkApplication parent;
};
struct _NodeEditorApplicationClass
{
GtkApplicationClass parent_class;
};
G_DEFINE_TYPE(NodeEditorApplication, node_editor_application, GTK_TYPE_APPLICATION);
static void
node_editor_application_init (NodeEditorApplication *app)
{
}
static void
quit_activated (GSimpleAction *action,
GVariant *parameter,
gpointer data)
{
g_application_quit (G_APPLICATION (data));
}
static GActionEntry app_entries[] =
{
{ "quit", quit_activated, NULL, NULL, NULL }
};
static void
node_editor_application_startup (GApplication *app)
{
const gchar *quit_accels[2] = { "<Ctrl>Q", NULL };
G_APPLICATION_CLASS (node_editor_application_parent_class)->startup (app);
g_action_map_add_action_entries (G_ACTION_MAP (app),
app_entries, G_N_ELEMENTS (app_entries),
app);
gtk_application_set_accels_for_action (GTK_APPLICATION (app),
"app.quit",
quit_accels);
}
static void
node_editor_application_activate (GApplication *app)
{
NodeEditorWindow *win;
win = node_editor_window_new (NODE_EDITOR_APPLICATION (app));
gtk_window_present (GTK_WINDOW (win));
}
static void
node_editor_application_open (GApplication *app,
GFile **files,
gint n_files,
const gchar *hint)
{
NodeEditorWindow *win;
gint i;
for (i = 0; i < n_files; i++)
{
win = node_editor_window_new (NODE_EDITOR_APPLICATION (app));
node_editor_window_load (win, files[i]);
gtk_window_present (GTK_WINDOW (win));
}
}
static void
node_editor_application_class_init (NodeEditorApplicationClass *class)
{
GApplicationClass *application_class = G_APPLICATION_CLASS (class);
application_class->startup = node_editor_application_startup;
application_class->activate = node_editor_application_activate;
application_class->open = node_editor_application_open;
}
NodeEditorApplication *
node_editor_application_new (void)
{
return g_object_new (NODE_EDITOR_APPLICATION_TYPE,
"application-id", "org.gtk.gtk4.NodeEditor",
"flags", G_APPLICATION_HANDLES_OPEN,
NULL);
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright © 2019 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __NODE_EDITOR_APPLICATION_H__
#define __NODE_EDITOR_APPLICATION_H__
#include <gtk/gtk.h>
#define NODE_EDITOR_APPLICATION_TYPE (node_editor_application_get_type ())
#define NODE_EDITOR_APPLICATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NODE_EDITOR_APPLICATION_TYPE, NodeEditorApplication))
typedef struct _NodeEditorApplication NodeEditorApplication;
typedef struct _NodeEditorApplicationClass NodeEditorApplicationClass;
GType node_editor_application_get_type (void);
NodeEditorApplication *node_editor_application_new (void);
#endif /* __NODE_EDITOR_APPLICATION_H__ */

View File

@@ -0,0 +1,431 @@
/*
* Copyright © 2019 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#include "config.h"
#include "node-editor-window.h"
#include "gsk/gskrendernodeparserprivate.h"
typedef struct
{
gsize start_chars;
gsize end_chars;
char *message;
} TextViewError;
struct _NodeEditorWindow
{
GtkApplicationWindow parent;
GtkWidget *picture;
GtkWidget *text_view;
GtkTextBuffer *text_buffer;
GArray *errors;
};
struct _NodeEditorWindowClass
{
GtkApplicationWindowClass parent_class;
};
G_DEFINE_TYPE(NodeEditorWindow, node_editor_window, GTK_TYPE_APPLICATION_WINDOW);
static void
text_view_error_free (TextViewError *e)
{
g_free (e->message);
}
static gchar *
get_current_text (GtkTextBuffer *buffer)
{
GtkTextIter start, end;
gtk_text_buffer_get_start_iter (buffer, &start);
gtk_text_buffer_get_end_iter (buffer, &end);
gtk_text_buffer_remove_all_tags (buffer, &start, &end);
return gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
}
static void
deserialize_error_func (const GtkCssSection *section,
const GError *error,
gpointer user_data)
{
const GtkCssLocation *start_location = gtk_css_section_get_start_location (section);
const GtkCssLocation *end_location = gtk_css_section_get_end_location (section);
NodeEditorWindow *self = user_data;
GtkTextIter start_iter, end_iter;
TextViewError text_view_error;
gtk_text_buffer_get_iter_at_line_offset (self->text_buffer, &start_iter,
start_location->lines,
start_location->line_chars);
gtk_text_buffer_get_iter_at_line_offset (self->text_buffer, &end_iter,
end_location->lines,
end_location->line_chars);
gtk_text_buffer_apply_tag_by_name (self->text_buffer, "error",
&start_iter, &end_iter);
text_view_error.start_chars = start_location->chars;
text_view_error.end_chars = end_location->chars;
text_view_error.message = g_strdup (error->message);
g_array_append_val (self->errors, text_view_error);
}
static void
text_changed (GtkTextBuffer *buffer,
NodeEditorWindow *self)
{
GskRenderNode *node;
char *text;
GBytes *bytes;
g_array_remove_range (self->errors, 0, self->errors->len);
text = get_current_text (self->text_buffer);
bytes = g_bytes_new_take (text, strlen (text));
/* If this is too slow, go fix the parser performance */
node = gsk_render_node_deserialize (bytes, deserialize_error_func, self);
g_bytes_unref (bytes);
if (node)
{
/* XXX: Is this code necessary or can we have API to turn nodes into paintables? */
GtkSnapshot *snapshot;
GdkPaintable *paintable;
graphene_rect_t bounds;
snapshot = gtk_snapshot_new ();
gsk_render_node_get_bounds (node, &bounds);
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (- bounds.origin.x, - bounds.origin.y));
gtk_snapshot_append_node (snapshot, node);
gsk_render_node_unref (node);
paintable = gtk_snapshot_free_to_paintable (snapshot, &bounds.size);
gtk_picture_set_paintable (GTK_PICTURE (self->picture), paintable);
g_clear_object (&paintable);
}
else
{
gtk_picture_set_paintable (GTK_PICTURE (self->picture), NULL);
}
}
static gboolean
text_view_query_tooltip_cb (GtkWidget *widget,
int x,
int y,
gboolean keyboard_tip,
GtkTooltip *tooltip,
NodeEditorWindow *self)
{
GtkTextIter iter;
guint i;
if (keyboard_tip)
{
gint offset;
g_object_get (self->text_buffer, "cursor-position", &offset, NULL);
gtk_text_buffer_get_iter_at_offset (self->text_buffer, &iter, offset);
}
else
{
gint bx, by, trailing;
gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (self->text_view), GTK_TEXT_WINDOW_TEXT,
x, y, &bx, &by);
gtk_text_view_get_iter_at_position (GTK_TEXT_VIEW (self->text_view), &iter, &trailing, bx, by);
}
for (i = 0; i < self->errors->len; i ++)
{
const TextViewError *e = &g_array_index (self->errors, TextViewError, i);
GtkTextIter start_iter, end_iter;
gtk_text_buffer_get_iter_at_offset (self->text_buffer, &start_iter, e->start_chars);
gtk_text_buffer_get_iter_at_offset (self->text_buffer, &end_iter, e->end_chars);
if (gtk_text_iter_in_range (&iter, &start_iter, &end_iter))
{
gtk_tooltip_set_text (tooltip, e->message);
return TRUE;
}
}
return FALSE;
}
gboolean
node_editor_window_load (NodeEditorWindow *self,
GFile *file)
{
GtkTextIter end;
GBytes *bytes;
bytes = g_file_load_bytes (file, NULL, NULL, NULL);
if (bytes == NULL)
return FALSE;
if (!g_utf8_validate (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL))
{
g_bytes_unref (bytes);
return FALSE;
}
gtk_text_buffer_get_end_iter (self->text_buffer, &end);
gtk_text_buffer_insert (self->text_buffer,
&end,
g_bytes_get_data (bytes, NULL),
g_bytes_get_size (bytes));
return TRUE;
}
static void
open_response_cb (GtkWidget *dialog,
gint response,
NodeEditorWindow *self)
{
gtk_widget_hide (dialog);
if (response == GTK_RESPONSE_ACCEPT)
{
GFile *file;
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
node_editor_window_load (self, file);
g_object_unref (file);
}
gtk_widget_destroy (dialog);
}
static void
open_cb (GtkWidget *button,
NodeEditorWindow *self)
{
GtkWidget *dialog;
dialog = gtk_file_chooser_dialog_new ("Open node file",
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (button))),
GTK_FILE_CHOOSER_ACTION_OPEN,
"_Cancel", GTK_RESPONSE_CANCEL,
"_Load", GTK_RESPONSE_ACCEPT,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), ".");
g_signal_connect (dialog, "response", G_CALLBACK (open_response_cb), self);
gtk_widget_show (dialog);
}
static void
save_response_cb (GtkWidget *dialog,
gint response,
NodeEditorWindow *self)
{
gtk_widget_hide (dialog);
if (response == GTK_RESPONSE_ACCEPT)
{
char *text, *filename;
GError *error = NULL;
text = get_current_text (self->text_buffer);
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
if (!g_file_set_contents (filename, text, -1, &error))
{
GtkWidget *dialog;
dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (self))),
GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"Saving failed");
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", error->message);
g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (dialog);
g_error_free (error);
}
g_free (filename);
}
gtk_widget_destroy (dialog);
}
static void
save_cb (GtkWidget *button,
NodeEditorWindow *self)
{
GtkWidget *dialog;
dialog = gtk_file_chooser_dialog_new ("Save node",
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (button))),
GTK_FILE_CHOOSER_ACTION_SAVE,
"_Cancel", GTK_RESPONSE_CANCEL,
"_Save", GTK_RESPONSE_ACCEPT,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), ".");
g_signal_connect (dialog, "response", G_CALLBACK (save_response_cb), self);
gtk_widget_show (dialog);
}
static GdkTexture *
create_texture (NodeEditorWindow *self)
{
GdkPaintable *paintable;
GtkSnapshot *snapshot;
GskRenderer *renderer;
GskRenderNode *node;
GdkTexture *texture;
paintable = gtk_picture_get_paintable (GTK_PICTURE (self->picture));
if (paintable == NULL ||
gdk_paintable_get_intrinsic_width (paintable) <= 0 ||
gdk_paintable_get_intrinsic_height (paintable) <= 0)
return NULL;
snapshot = gtk_snapshot_new ();
gdk_paintable_snapshot (paintable, snapshot, gdk_paintable_get_intrinsic_width (paintable), gdk_paintable_get_intrinsic_height (paintable));
node = gtk_snapshot_free_to_node (snapshot);
if (node == NULL)
return NULL;
/* ahem */
renderer = GTK_ROOT_GET_IFACE (gtk_widget_get_root (GTK_WIDGET (self)))->get_renderer (gtk_widget_get_root (GTK_WIDGET (self)));
texture = gsk_renderer_render_texture (renderer, node, NULL);
gsk_render_node_unref (node);
return texture;
}
static void
export_image_response_cb (GtkWidget *dialog,
gint response,
GdkTexture *texture)
{
gtk_widget_hide (dialog);
if (response == GTK_RESPONSE_ACCEPT)
{
char *filename;
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
if (!gdk_texture_save_to_png (texture, filename))
{
GtkWidget *message_dialog;
message_dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_window_get_transient_for (GTK_WINDOW (dialog))),
GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_INFO,
GTK_BUTTONS_OK,
"Exporting to image failed");
g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
gtk_widget_show (message_dialog);
}
g_free (filename);
}
gtk_widget_destroy (dialog);
g_object_unref (texture);
}
static void
export_image_cb (GtkWidget *button,
NodeEditorWindow *self)
{
GdkTexture *texture;
GtkWidget *dialog;
texture = create_texture (self);
if (texture == NULL)
return;
dialog = gtk_file_chooser_dialog_new ("",
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (button))),
GTK_FILE_CHOOSER_ACTION_SAVE,
"_Cancel", GTK_RESPONSE_CANCEL,
"_Save", GTK_RESPONSE_ACCEPT,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
g_signal_connect (dialog, "response", G_CALLBACK (export_image_response_cb), texture);
gtk_widget_show (dialog);
}
static void
node_editor_window_finalize (GObject *object)
{
NodeEditorWindow *self = (NodeEditorWindow *)object;
g_array_free (self->errors, TRUE);
G_OBJECT_CLASS (node_editor_window_parent_class)->finalize (object);
}
static void
node_editor_window_class_init (NodeEditorWindowClass *class)
{
GObjectClass *object_class = G_OBJECT_CLASS (class);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
object_class->finalize = node_editor_window_finalize;
gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (class),
"/org/gtk/gtk4/node-editor/node-editor-window.ui");
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, text_buffer);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, text_view);
gtk_widget_class_bind_template_child (widget_class, NodeEditorWindow, picture);
gtk_widget_class_bind_template_callback (widget_class, text_changed);
gtk_widget_class_bind_template_callback (widget_class, text_view_query_tooltip_cb);
gtk_widget_class_bind_template_callback (widget_class, open_cb);
gtk_widget_class_bind_template_callback (widget_class, save_cb);
gtk_widget_class_bind_template_callback (widget_class, export_image_cb);
}
static void
node_editor_window_init (NodeEditorWindow *self)
{
gtk_widget_init_template (GTK_WIDGET (self));
self->errors = g_array_new (FALSE, TRUE, sizeof (TextViewError));
g_array_set_clear_func (self->errors, (GDestroyNotify)text_view_error_free);
}
NodeEditorWindow *
node_editor_window_new (NodeEditorApplication *application)
{
return g_object_new (NODE_EDITOR_WINDOW_TYPE,
"application", application,
NULL);
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright © 2019 Benjamin Otte
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Authors: Benjamin Otte <otte@gnome.org>
*/
#ifndef __NODE_EDITOR_WINDOW_H__
#define __NODE_EDITOR_WINDOW_H__
#include <gtk/gtk.h>
#include "node-editor-application.h"
#define NODE_EDITOR_WINDOW_TYPE (node_editor_window_get_type ())
#define NODE_EDITOR_WINDOW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NODE_EDITOR_WINDOW_TYPE, NodeEditorWindow))
typedef struct _NodeEditorWindow NodeEditorWindow;
typedef struct _NodeEditorWindowClass NodeEditorWindowClass;
GType node_editor_window_get_type (void);
NodeEditorWindow * node_editor_window_new (NodeEditorApplication *application);
gboolean node_editor_window_load (NodeEditorWindow *self,
GFile *file);
#endif /* __NODE_EDITOR_WINDOW_H__ */

View File

@@ -0,0 +1,99 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<object class="GtkTextTagTable" id="tags">
<child type="tag">
<object class="GtkTextTag">
<property name="name">error</property>
<property name="underline">error</property>
</object>
</child>
</object>
<object class="GtkTextBuffer" id="text_buffer">
<property name="tag-table">tags</property>
<signal name="changed" handler="text_changed"/>
</object>
<template class="NodeEditorWindow" parent="GtkApplicationWindow">
<style>
<class name="devel"/>
</style>
<property name="title" translatable="yes">GTK Node Editor</property>
<property name="default-width">1024</property>
<property name="default-height">768</property>
<child type="titlebar">
<object class="GtkHeaderBar" id="header">
<property name="title" translatable="yes">GTK Node Editor</property>
<property name="show-title-buttons">1</property>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-open-symbolic</property>
<property name="tooltip-text">Open node file</property>
<signal name="clicked" handler="open_cb"/>
</object>
</child>
<child type="start">
<object class="GtkButton">
<property name="icon-name">document-save-symbolic</property>
<property name="tooltip-text">Save to node file</property>
<signal name="clicked" handler="save_cb"/>
</object>
</child>
<child type="start">
<object class="GtkButton">
<property name="icon-name">insert-image-symbolic</property>
<property name="tooltip-text">Export to image</property>
<signal name="clicked" handler="export_image_cb"/>
</object>
</child>
<child type="title">
<object class="GtkLabel">
<property name="label" translatable="yes">GTK Node Editor</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkPaned">
<property name="shrink-child2">false</property>
<property name="position">400</property>
<child>
<object class="GtkScrolledWindow">
<property name="hscrollbar-policy">never</property>
<property name="expand">1</property>
<child>
<object class="GtkTextView" id="text_view">
<property name="buffer">text_buffer</property>
<property name="wrap-mode">word</property>
<property name="monospace">1</property>
<property name="has-focus">1</property>
<property name="top-margin">6</property>
<property name="left-margin">6</property>
<property name="right-margin">6</property>
<property name="bottom-margin">6</property>
<property name="has-tooltip">1</property>
<signal name="query-tooltip" handler="text_view_query_tooltip_cb"/>
</object>
</child>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="expand">1</property>
<property name="min-content-height">100</property>
<property name="min-content-width">100</property>
<child>
<object class="GtkViewport">
<child>
<object class="GtkPicture" id="picture">
<property name="can-shrink">0</property>
<property name="halign">center</property>
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</template>
</interface>

View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
<gresource prefix="/org/gtk/gtk4/node-editor">
<file preprocess="xml-stripblanks">node-editor-window.ui</file>
</gresource>
</gresources>

View File

@@ -116,6 +116,8 @@ typedef struct {
int use_es;
int max_debug_label_length;
GdkGLContextPaintData *paint_data;
} GdkGLContextPrivate;
@@ -457,11 +459,14 @@ gdk_gl_context_push_debug_group_printf (GdkGLContext *context,
if (priv->use_khr_debug)
{
int msg_len;
va_start (args, format);
message = g_strdup_vprintf (format, args);
va_end (args);
glPushDebugGroupKHR (GL_DEBUG_SOURCE_APPLICATION, 0, -1, message);
msg_len = MIN (priv->max_debug_label_length, strlen (message) - 1);
glPushDebugGroupKHR (GL_DEBUG_SOURCE_APPLICATION, 0, msg_len, message);
g_free (message);
}
}
@@ -500,11 +505,15 @@ gdk_gl_context_label_object_printf (GdkGLContext *context,
if (priv->use_khr_debug)
{
int msg_len;
va_start (args, format);
message = g_strdup_vprintf (format, args);
va_end (args);
glObjectLabel (identifier, name, -1, message);
msg_len = MIN (priv->max_debug_label_length, strlen (message) - 1);
glObjectLabel (identifier, name, msg_len, message);
g_free (message);
}
}
@@ -992,7 +1001,10 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
if (priv->has_khr_debug && GDK_DISPLAY_DEBUG_CHECK (display, GL_DEBUG))
priv->use_khr_debug = TRUE;
{
priv->use_khr_debug = TRUE;
glGetIntegerv (GL_MAX_LABEL_LENGTH, &priv->max_debug_label_length);
}
if (!priv->use_es && GDK_DISPLAY_DEBUG_CHECK (display, GL_TEXTURE_RECT))
priv->use_texture_rectangle = TRUE;
else if (has_npot)

View File

@@ -535,8 +535,6 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
}
t = create_texture (self, gdk_texture_get_width (texture), gdk_texture_get_height (texture));
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, t->texture_id,
"GdkTexture<%p> %d", texture, t->texture_id);
if (gdk_texture_set_render_data (texture, self, t, gsk_gl_driver_release_texture))
t->user = texture;
@@ -547,6 +545,9 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
surface,
min_filter,
mag_filter);
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, t->texture_id,
"GdkTexture<%p> %d", texture, t->texture_id);
cairo_surface_destroy (surface);
return t->texture_id;

View File

@@ -326,6 +326,7 @@ struct _GskGLRenderer
Program unblurred_outset_shadow_program;
Program border_program;
Program cross_fade_program;
Program blend_program;
};
};
@@ -479,14 +480,14 @@ render_fallback_node (GskGLRenderer *self,
texture_id = gsk_gl_driver_create_texture (self->gl_driver,
surface_width,
surface_height);
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
"Fallback %s %d", node->node_class->type_name, texture_id);
gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
gsk_gl_driver_init_texture_with_surface (self->gl_driver,
texture_id,
surface,
GL_NEAREST, GL_NEAREST);
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
"Fallback %s %d", node->node_class->type_name, texture_id);
cairo_surface_destroy (surface);
@@ -1431,10 +1432,10 @@ render_outset_shadow_node (GskGLRenderer *self,
GskRoundedRect blit_clip;
texture_id = gsk_gl_driver_create_texture (self->gl_driver, texture_width, texture_height);
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
"Outset Shadow Temp %d", texture_id);
gsk_gl_driver_bind_source_texture (self->gl_driver, texture_id);
gsk_gl_driver_init_texture_empty (self->gl_driver, texture_id);
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, texture_id,
"Outset Shadow Temp %d", texture_id);
render_target = gsk_gl_driver_create_render_target (self->gl_driver, texture_id, FALSE, FALSE);
gdk_gl_context_label_object_printf (self->gl_context, GL_FRAMEBUFFER, render_target,
"Outset Shadow FB Temp %d", render_target);
@@ -1468,10 +1469,10 @@ render_outset_shadow_node (GskGLRenderer *self,
});
blurred_texture_id = gsk_gl_driver_create_permanent_texture (self->gl_driver, texture_width, texture_height);
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, blurred_texture_id,
"Outset Shadow Cache %d", blurred_texture_id);
gsk_gl_driver_bind_source_texture (self->gl_driver, blurred_texture_id);
gsk_gl_driver_init_texture_empty (self->gl_driver, blurred_texture_id);
gdk_gl_context_label_object_printf (self->gl_context, GL_TEXTURE, blurred_texture_id,
"Outset Shadow Cache %d", blurred_texture_id);
blurred_render_target = gsk_gl_driver_create_render_target (self->gl_driver, blurred_texture_id, TRUE, TRUE);
gdk_gl_context_label_object_printf (self->gl_context, GL_FRAMEBUFFER, render_target,
"Outset Shadow Cache FB %d", render_target);
@@ -1900,6 +1901,54 @@ render_cross_fade_node (GskGLRenderer *self,
ops_draw (builder, vertex_data);
}
static inline void
render_blend_node (GskGLRenderer *self,
GskRenderNode *node,
RenderOpBuilder *builder)
{
GskRenderNode *top_child = gsk_blend_node_get_top_child (node);
GskRenderNode *bottom_child = gsk_blend_node_get_bottom_child (node);
const float min_x = builder->dx + node->bounds.origin.x;
const float min_y = builder->dy + node->bounds.origin.y;
const float max_x = min_x + node->bounds.size.width;
const float max_y = min_y + node->bounds.size.height;
int top_texture_id;
int bottom_texture_id;
gboolean is_offscreen1, is_offscreen2;
RenderOp op;
const GskQuadVertex vertex_data[GL_N_VERTICES] = {
{ { min_x, min_y }, { 0, 1 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
{ { max_x, max_y }, { 1, 0 }, },
{ { min_x, max_y }, { 0, 0 }, },
{ { max_x, min_y }, { 1, 1 }, },
};
/* TODO: We create 2 textures here as big as the blend node, but both the
* start and the end node might be a lot smaller than that. */
add_offscreen_ops (self, builder,
&node->bounds,
bottom_child,
&bottom_texture_id, &is_offscreen1,
FORCE_OFFSCREEN | RESET_CLIP);
add_offscreen_ops (self, builder,
&node->bounds,
top_child,
&top_texture_id, &is_offscreen2,
FORCE_OFFSCREEN | RESET_CLIP);
ops_set_program (builder, &self->blend_program);
ops_set_texture (builder, bottom_texture_id);
op.op = OP_CHANGE_BLEND;
op.blend.source2 = top_texture_id;
op.blend.mode = gsk_blend_node_get_blend_mode (node);
ops_add (builder, &op);
ops_draw (builder, vertex_data);
}
static inline void
apply_viewport_op (const Program *program,
const RenderOp *op)
@@ -2174,6 +2223,18 @@ apply_cross_fade_op (const Program *program,
glUniform1f (program->cross_fade.progress_location, op->cross_fade.progress);
}
static inline void
apply_blend_op (const Program *program,
const RenderOp *op)
{
/* End texture id */
glUniform1i (program->blend.source2_location, 1);
glActiveTexture (GL_TEXTURE0 + 1);
glBindTexture (GL_TEXTURE_2D, op->blend.source2);
/* progress */
glUniform1i (program->blend.mode_location, op->blend.mode);
}
static void
gsk_gl_renderer_dispose (GObject *gobject)
{
@@ -2206,6 +2267,7 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
{ "unblurred outset shadow", "unblurred_outset_shadow.fs.glsl" },
{ "border", "border.fs.glsl" },
{ "cross fade", "cross_fade.fs.glsl" },
{ "blend", "blend.fs.glsl" },
};
builder = gsk_shader_builder_new ();
@@ -2336,6 +2398,10 @@ gsk_gl_renderer_create_programs (GskGLRenderer *self,
INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, progress);
INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, source2);
/* blend */
INIT_PROGRAM_UNIFORM_LOCATION (blend, source2);
INIT_PROGRAM_UNIFORM_LOCATION (blend, mode);
g_object_unref (builder);
return TRUE;
}
@@ -2588,8 +2654,11 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
render_cross_fade_node (self, node, builder);
break;
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_BLEND_NODE:
render_blend_node (self, node, builder);
break;
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
case GSK_REPEAT_NODE:
case GSK_CAIRO_NODE:
default:
@@ -2855,6 +2924,11 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
apply_cross_fade_op (program, op);
break;
case OP_CHANGE_BLEND:
g_assert (program == &self->blend_program);
apply_blend_op (program, op);
break;
case OP_CHANGE_LINEAR_GRADIENT:
apply_linear_gradient_op (program, op);
break;

View File

@@ -11,7 +11,7 @@
#include "gskrendernodeprivate.h"
#define GL_N_VERTICES 6
#define GL_N_PROGRAMS 11
#define GL_N_PROGRAMS 12
@@ -61,6 +61,7 @@ enum {
OP_DUMP_FRAMEBUFFER = 23,
OP_PUSH_DEBUG_GROUP = 24,
OP_POP_DEBUG_GROUP = 25,
OP_CHANGE_BLEND = 26,
};
typedef struct
@@ -136,6 +137,10 @@ typedef struct
int source2_location;
int progress_location;
} cross_fade;
struct {
int source2_location;
int mode_location;
} blend;
};
} Program;
@@ -214,6 +219,10 @@ typedef struct
float progress;
int source2;
} cross_fade;
struct {
int source2;
int mode;
} blend;
struct {
char *filename;
int width;

View File

@@ -42,6 +42,7 @@
#include "gskdebugprivate.h"
#include "gskrendererprivate.h"
#include "gskrendernodeparserprivate.h"
#include <graphene-gobject.h>
@@ -328,19 +329,11 @@ gsk_render_node_diff (GskRenderNode *node1,
GBytes *
gsk_render_node_serialize (GskRenderNode *node)
{
GVariant *node_variant, *variant;
GBytes *result;
char *str;
node_variant = gsk_render_node_serialize_node (node);
variant = g_variant_new ("(suuv)",
GSK_RENDER_NODE_SERIALIZATION_ID,
(guint32) GSK_RENDER_NODE_SERIALIZATION_VERSION,
(guint32) gsk_render_node_get_node_type (node),
node_variant);
result = g_variant_get_data_as_bytes (variant);
g_variant_unref (variant);
str = gsk_render_node_serialize_to_string (node);
result = g_bytes_new_take (str, strlen (str));
return result;
}
@@ -394,39 +387,13 @@ gsk_render_node_write_to_file (GskRenderNode *node,
* error.
**/
GskRenderNode *
gsk_render_node_deserialize (GBytes *bytes,
GError **error)
gsk_render_node_deserialize (GBytes *bytes,
GskParseErrorFunc error_func,
gpointer user_data)
{
char *id_string;
guint32 version, node_type;
GVariant *variant, *node_variant;
GskRenderNode *node = NULL;
variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("(suuv)"), bytes, FALSE);
g_variant_get (variant, "(suuv)", &id_string, &version, &node_type, &node_variant);
if (!g_str_equal (id_string, GSK_RENDER_NODE_SERIALIZATION_ID))
{
g_set_error (error, GSK_SERIALIZATION_ERROR, GSK_SERIALIZATION_UNSUPPORTED_FORMAT,
"Data not in GskRenderNode serialization format.");
goto out;
}
if (version != GSK_RENDER_NODE_SERIALIZATION_VERSION)
{
g_set_error (error, GSK_SERIALIZATION_ERROR, GSK_SERIALIZATION_UNSUPPORTED_VERSION,
"Format version %u not supported.", version);
goto out;
}
node = gsk_render_node_deserialize_node (node_type, node_variant, error);
out:
g_free (id_string);
g_variant_unref (node_variant);
g_variant_unref (variant);
node = gsk_render_node_deserialize_from_bytes (bytes, error_func, user_data);
return node;
}

View File

@@ -25,6 +25,7 @@
#include <gsk/gskroundedrect.h>
#include <gsk/gsktypes.h>
#include <gtk/css/gtkcss.h>
G_BEGIN_DECLS
@@ -52,6 +53,10 @@ struct _GskShadow
float radius;
};
typedef void (* GskParseErrorFunc) (const GtkCssSection *section,
const GError *error,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
GType gsk_render_node_get_type (void) G_GNUC_CONST;
@@ -81,8 +86,9 @@ gboolean gsk_render_node_write_to_file (GskRenderNode *
const char *filename,
GError **error);
GDK_AVAILABLE_IN_ALL
GskRenderNode * gsk_render_node_deserialize (GBytes *bytes,
GError **error);
GskRenderNode * gsk_render_node_deserialize (GBytes *bytes,
GskParseErrorFunc error_func,
gpointer user_data);
GDK_AVAILABLE_IN_ALL
GskRenderNode * gsk_debug_node_new (GskRenderNode *child,

File diff suppressed because it is too large Load Diff

1879
gsk/gskrendernodeparser.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,12 @@
#ifndef __GSK_RENDER_NODE_PARSER_PRIVATE_H__
#define __GSK_RENDER_NODE_PARSER_PRIVATE_H__
#include "gskrendernode.h"
GskRenderNode * gsk_render_node_deserialize_from_bytes (GBytes *bytes,
GskParseErrorFunc error_func,
gpointer user_data);
char * gsk_render_node_serialize_to_string (GskRenderNode *root);
#endif

View File

@@ -33,9 +33,6 @@ struct _GskRenderNodeClass
void (* diff) (GskRenderNode *node1,
GskRenderNode *node2,
cairo_region_t *region);
GVariant * (* serialize) (GskRenderNode *node);
GskRenderNode * (* deserialize) (GVariant *variant,
GError **error);
};
GskRenderNode * gsk_render_node_new (const GskRenderNodeClass *node_class,
@@ -50,11 +47,6 @@ void gsk_render_node_diff_impossible (GskRenderNode *nod
GskRenderNode *node2,
cairo_region_t *region);
GVariant * gsk_render_node_serialize_node (GskRenderNode *node);
GskRenderNode * gsk_render_node_deserialize_node (GskRenderNodeType type,
GVariant *variant,
GError **error);
GskRenderNode * gsk_cairo_node_new_for_surface (const graphene_rect_t *bounds,
cairo_surface_t *surface);

View File

@@ -1695,6 +1695,7 @@ gsk_transform_parser_parse (GtkCssParser *parser,
if (gtk_css_token_is_ident (token, "none"))
{
gtk_css_parser_consume_token (parser);
*out_transform = NULL;
return TRUE;
}
@@ -1902,6 +1903,7 @@ gsk_transform_parse (const char *string,
result = FALSE;
}
gtk_css_parser_unref (parser);
g_bytes_unref (bytes);
return result;

View File

@@ -11,6 +11,7 @@ gsk_private_gl_shaders = [
'resources/glsl/unblurred_outset_shadow.fs.glsl',
'resources/glsl/border.fs.glsl',
'resources/glsl/cross_fade.fs.glsl',
'resources/glsl/blend.fs.glsl',
'resources/glsl/es2_common.fs.glsl',
'resources/glsl/es2_common.vs.glsl',
'resources/glsl/gl3_common.fs.glsl',
@@ -34,6 +35,7 @@ gsk_private_sources = files([
'gskdebug.c',
'gskprivate.c',
'gskprofiler.c',
'gskrendernodeparser.c',
'gl/gskshaderbuilder.c',
'gl/gskglprofiler.c',
'gl/gskglrenderer.c',

View File

@@ -0,0 +1,287 @@
uniform int u_mode;
uniform sampler2D u_source2;
float
combine (float source, float backdrop)
{
return source + backdrop * (1 - source);
}
vec4
composite (vec4 Cs, vec4 Cb, vec3 B)
{
float ao = Cs.a + Cb.a * (1 - Cs.a);
vec3 Co = (Cs.a*(1 - Cb.a)*Cs.rgb + Cs.a*Cb.a*B + (1 - Cs.a)*Cb.a*Cb.rgb) / ao;
return vec4(Co, ao);
}
vec4
normal (vec4 Cs, vec4 Cb)
{
return composite (Cs, Cb, Cs.rgb);
}
vec4
multiply (vec4 Cs, vec4 Cb)
{
return composite (Cs, Cb, Cs.rgb * Cb.rgb);
}
vec4
difference (vec4 Cs, vec4 Cb)
{
return composite (Cs, Cb, abs(Cs.rgb - Cb.rgb));
}
vec4
screen (vec4 Cs, vec4 Cb)
{
return composite (Cs, Cb, Cs.rgb + Cb.rgb - Cs.rgb * Cb.rgb);
}
float
hard_light (float source, float backdrop)
{
if (source <= 0.5)
return 2 * backdrop * source;
else
return 2 * (backdrop + source - backdrop * source) - 1;
}
vec4
hard_light (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (hard_light (Cs.r, Cb.r),
hard_light (Cs.g, Cb.g),
hard_light (Cs.b, Cb.b));
return composite (Cs, Cb, B);
}
float
soft_light (float source, float backdrop)
{
float db;
if (backdrop <= 0.25)
db = ((16 * backdrop - 12) * backdrop + 4) * backdrop;
else
db = sqrt (backdrop);
if (source <= 0.5)
return backdrop - (1 - 2 * source) * backdrop * (1 - backdrop);
else
return backdrop + (2 * source - 1) * (db - backdrop);
}
vec4
soft_light (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (soft_light (Cs.r, Cb.r),
soft_light (Cs.g, Cb.g),
soft_light (Cs.b, Cb.b));
return composite (Cs, Cb, B);
}
vec4
overlay (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (hard_light (Cb.r, Cs.r),
hard_light (Cb.g, Cs.g),
hard_light (Cb.b, Cs.b));
return composite (Cs, Cb, B);
}
vec4
darken (vec4 Cs, vec4 Cb)
{
vec3 B = min (Cs.rgb, Cb.rgb);
return composite (Cs, Cb, B);
}
vec4
lighten (vec4 Cs, vec4 Cb)
{
vec3 B = max (Cs.rgb, Cb.rgb);
return composite (Cs, Cb, B);
}
float
color_dodge (float source, float backdrop)
{
return (source == 1.0) ? source : min (backdrop / (1.0 - source), 1.0);
}
vec4
color_dodge (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (color_dodge (Cs.r, Cb.r),
color_dodge (Cs.g, Cb.g),
color_dodge (Cs.b, Cb.b));
return composite (Cs, Cb, B);
}
float
color_burn (float source, float backdrop)
{
return (source == 0.0) ? source : max ((1.0 - ((1.0 - backdrop) / source)), 0.0);
}
vec4
color_burn (vec4 Cs, vec4 Cb)
{
vec3 B = vec3 (color_burn (Cs.r, Cb.r),
color_burn (Cs.g, Cb.g),
color_burn (Cs.b, Cb.b));
return composite (Cs, Cb, B);
}
vec4
exclusion (vec4 Cs, vec4 Cb)
{
vec3 B = Cb.rgb + Cs.rgb - 2.0 * Cb.rgb * Cs.rgb;
return composite (Cs, Cb, B);
}
float
lum (vec3 c)
{
return 0.3 * c.r + 0.59 * c.g + 0.11 * c.b;
}
vec3
clip_color (vec3 c)
{
float l = lum (c);
float n = min (c.r, min (c.g, c.b));
float x = max (c.r, max (c.g, c.b));
if (n < 0) c = l + (((c - l) * l) / (l - n));
if (x > 1) c = l + (((c - l) * (1 - l)) / (x - l));
return c;
}
vec3
set_lum (vec3 c, float l)
{
float d = l - lum (c);
return clip_color (vec3 (c.r + d, c.g + d, c.b + d));
}
float
sat (vec3 c)
{
return max (c.r, max (c.g, c.b)) - min (c.r, min (c.g, c.b));
}
vec3
set_sat (vec3 c, float s)
{
float cmin = min (c.r, min (c.g, c.b));
float cmax = max (c.r, max (c.g, c.b));
vec3 res;
if (cmax == cmin)
res = vec3 (0, 0, 0);
else
{
if (c.r == cmax)
{
if (c.g == cmin)
{
res.b = ((c.b - cmin) * s) / (cmax - cmin);
res.g = 0;
}
else
{
res.g = ((c.g - cmin) * s) / (cmax - cmin);
res.b = 0;
}
res.r = s;
}
else if (c.g == cmax)
{
if (c.r == cmin)
{
res.b = ((c.b - cmin) * s) / (cmax - cmin);
res.r = 0;
}
else
{
res.r = ((c.r - cmin) * s) / (cmax - cmin);
res.b = 0;
}
res.g = s;
}
else
{
if (c.r == cmin)
{
res.g = ((c.g - cmin) * s) / (cmax - cmin);
res.r = 0;
}
else
{
res.r = ((c.r - cmin) * s) / (cmax - cmin);
res.g = 0;
}
res.b = s;
}
}
return res;
}
vec4
color (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (Cs.rgb, lum (Cb.rgb));
return composite (Cs, Cb, B);
}
vec4
hue (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (set_sat (Cs.rgb, sat (Cb.rgb)), lum (Cb.rgb));
return composite (Cs, Cb, B);
}
vec4
saturation (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (set_sat (Cb.rgb, sat (Cs.rgb)), lum (Cb.rgb));
return composite (Cs, Cb, B);
}
vec4
luminosity (vec4 Cs, vec4 Cb)
{
vec3 B = set_lum (Cb.rgb, lum (Cs.rgb));
return composite (Cs, Cb, B);
}
void main() {
vec4 bottom_color = Texture(u_source, vUv);
vec4 top_color = Texture(u_source2, vUv);
vec4 result;
switch(u_mode) {
case 0: result = normal(bottom_color, top_color); break;
case 1: result = multiply(bottom_color, top_color); break;
case 2: result = screen(bottom_color, top_color); break;
case 3: result = overlay(bottom_color, top_color); break;
case 4: result = darken(bottom_color, top_color); break;
case 5: result = lighten(bottom_color, top_color); break;
case 6: result = color_dodge(bottom_color, top_color); break;
case 7: result = color_burn(bottom_color, top_color); break;
case 8: result = hard_light(bottom_color, top_color); break;
case 9: result = soft_light(bottom_color, top_color); break;
case 10: result = difference(bottom_color, top_color); break;
case 11: result = exclusion(bottom_color, top_color); break;
case 12: result = color(bottom_color, top_color); break;
case 13: result = hue(bottom_color, top_color); break;
case 14: result = saturation(bottom_color, top_color); break;
case 15: result = luminosity(bottom_color, top_color); break;
default: discard;
}
setOutputColor(result * u_alpha);
}

View File

@@ -30,6 +30,29 @@ G_BEGIN_DECLS
#define GTK_IS_CSS_PROVIDER_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), GTK_TYPE_CSS_PROVIDER))
#define GTK_CSS_PROVIDER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_CSS_PROVIDER, GtkCssProviderClass))
/**
* GtkCssProviderError:
* @GTK_CSS_PROVIDER_ERROR_FAILED: Failed.
* @GTK_CSS_PROVIDER_ERROR_SYNTAX: Syntax error.
* @GTK_CSS_PROVIDER_ERROR_IMPORT: Import error.
* @GTK_CSS_PROVIDER_ERROR_NAME: Name error.
* @GTK_CSS_PROVIDER_ERROR_DEPRECATED: Deprecation error.
* @GTK_CSS_PROVIDER_ERROR_UNKNOWN_VALUE: Unknown value.
* @GTK_CSS_PROVIDER_WARN_GENERAL: A general warning.
*
* Error codes for %GTK_CSS_PROVIDER_ERROR.
*/
typedef enum
{
GTK_CSS_PROVIDER_ERROR_FAILED,
GTK_CSS_PROVIDER_ERROR_SYNTAX,
GTK_CSS_PROVIDER_ERROR_IMPORT,
GTK_CSS_PROVIDER_ERROR_NAME,
GTK_CSS_PROVIDER_ERROR_DEPRECATED,
GTK_CSS_PROVIDER_ERROR_UNKNOWN_VALUE,
GTK_CSS_PROVIDER_WARN_GENERAL,
} GtkCssProviderError;
typedef struct _GtkCssProvider GtkCssProvider;
typedef struct _GtkCssProviderClass GtkCssProviderClass;
typedef struct _GtkCssProviderPrivate GtkCssProviderPrivate;

View File

@@ -13,6 +13,19 @@ static GOptionEntry options[] = {
{ NULL }
};
static void
deserialize_error_func (const GtkCssSection *section,
const GError *error,
gpointer user_data)
{
char *section_str = gtk_css_section_to_string (section);
g_warning ("Error at %s: %s", section_str, error->message);
free (section_str);
}
int
main(int argc, char **argv)
{
@@ -66,7 +79,7 @@ main(int argc, char **argv)
}
start = g_get_monotonic_time ();
node = gsk_render_node_deserialize (bytes, &error);
node = gsk_render_node_deserialize (bytes, deserialize_error_func, NULL);
end = g_get_monotonic_time ();
if (benchmark)
{
@@ -78,8 +91,6 @@ main(int argc, char **argv)
if (node == NULL)
{
g_printerr ("Invalid node file: %s\n", error->message);
g_clear_error (&error);
return 1;
}

View File

@@ -108,6 +108,18 @@ gtk_node_view_class_init (GtkNodeViewClass *klass)
widget_class->snapshot = gtk_node_view_snapshot;
}
static void
deserialize_error_func (const GtkCssSection *section,
const GError *error,
gpointer user_data)
{
char *section_str = gtk_css_section_to_string (section);
g_warning ("Error at %s: %s", section_str, error->message);
free (section_str);
}
int
main (int argc, char **argv)
{
@@ -152,7 +164,7 @@ main (int argc, char **argv)
}
bytes = g_bytes_new_take (contents, len);
GTK_NODE_VIEW (nodeview)->node = gsk_render_node_deserialize (bytes, &error);
GTK_NODE_VIEW (nodeview)->node = gsk_render_node_deserialize (bytes, deserialize_error_func, NULL);
g_bytes_unref (bytes);
if (GTK_NODE_VIEW (nodeview)->node == NULL)

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

View File

@@ -54,6 +54,18 @@ save_image (cairo_surface_t *surface,
g_free (filename);
}
static void
deserialize_error_func (const GtkCssSection *section,
const GError *error,
gpointer user_data)
{
char *section_str = gtk_css_section_to_string (section);
g_error ("Error at %s: %s", section_str, error->message);
free (section_str);
}
/*
* Arguments:
* 1) .node file to compare
@@ -101,7 +113,7 @@ main (int argc, char **argv)
}
bytes = g_bytes_new_take (contents, len);
node = gsk_render_node_deserialize (bytes, &error);
node = gsk_render_node_deserialize (bytes, deserialize_error_func, NULL);
g_bytes_unref (bytes);
g_assert_no_error (error);

View File

@@ -0,0 +1,19 @@
transform {
/* adding the perspective line here turns the matrix from a 2D
category into a 3D category. It does not have any visual effect. */
transform: perspective(200) scale(2);
child: container {
color {
bounds: 0 0 50 50;
color: transparent;
}
clip {
clip: 10 10 30 30;
child: color {
bounds: 0 0 50 50;
color: red;
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 269 B

View File

@@ -0,0 +1,34 @@
color {
color: white;
bounds: 50 70 80 90;
}
clip {
clip: 60 80 60 70;
child: rounded-clip {
clip: 20 50 100 100 / 50;
child: color {
bounds: 20 50 100 100;
color: red;
}
}
}
/* The actual rounded portion of the clip is irrelevant
* for this test case. This just ensures that
* offscreen-drawn clips work and have the correct
* size, color, etc.
*/
debug {
message: "clipped out area";
child: container {
color {
bounds: 115 80 5 45;
color: black;
}
color {
bounds: 60 120 60 30;
color: black;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

View File

@@ -0,0 +1,36 @@
color {
bounds: 40 40 70 70;
color: transparent;
}
clip {
clip: 50 50 50 50;
child: opacity {
opacity: 0.4;
child: rounded-clip {
clip: 50 50 100 100 / 50;
child: color {
bounds: 50 50 100 100;
color: red;
}
}
}
}
debug {
message: "clipped out area";
child: container {
color {
bounds: 50 70 10 30;
color: black;
}
color {
bounds: 55 55 20 20;
color: black;
}
color {
bounds: 70 50 30 10;
color: black;
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -0,0 +1,8 @@
outset-shadow {
outline: 100 100 100 100;
color: black;
dx: -100;
dy: 100;
spread: 10;
blur: 0;
}

View File

Before

Width:  |  Height:  |  Size: 527 B

After

Width:  |  Height:  |  Size: 527 B

View File

@@ -0,0 +1,8 @@
outset-shadow {
outline: 100 100 100 100;
color: black;
dx: 10;
dy: 0;
spread: 10;
blur: 0;
}

View File

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 391 B

View File

@@ -0,0 +1,8 @@
outset-shadow {
outline: 100 100 100 100;
color: black;
dx: 0;
dy: 10;
spread: 10;
blur: 0;
}

View File

Before

Width:  |  Height:  |  Size: 391 B

After

Width:  |  Height:  |  Size: 391 B

View File

@@ -0,0 +1,8 @@
outset-shadow {
outline: 100 100 100 100;
color: black;
dx: 0;
dy: 0;
spread: 10;
blur: 0;
}

View File

Before

Width:  |  Height:  |  Size: 396 B

After

Width:  |  Height:  |  Size: 396 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

View File

@@ -0,0 +1,23 @@
/* Background */
color {
bounds: 0 0 200 200;
color: white;
}
/* It is important that the following node structure leaves the
* start child of the cross-fade node invisible. */
opacity {
opacity: 0.4;
child: cross-fade {
start: color {
color: blue;
bounds: 0 0 100 100;
}
end: color {
color: red;
bounds: 100 100 100 100;
}
progress: 1.0;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 744 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 761 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

View File

@@ -0,0 +1,24 @@
/*
The opacity node should affect both the shadow node child
(the node that's NOT colored) and the actual shadow.
I.e. the output should be entirely empty.
*/
opacity {
opacity: 0;
child: shadow {
child: cross-fade {
start: color {
color: blue;
bounds: 0 0 100 100;
}
end: color {
color: red;
bounds: 100 100 100 100;
}
progress: 0;
}
shadows: green 200 0 0;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1011 B

Some files were not shown because too many files have changed in this diff Show More