Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2b5c49fb58 | |||
| c0791ca38e | |||
| 8ca1a46272 | |||
| 97b688702b | |||
| 31e503aa46 | |||
| 5d63bfd285 | |||
| 78859b9e2a | |||
| d4dd43f93d | |||
| ed51dd58b5 | |||
| f3742a37db | |||
| f1ebc75f58 | |||
| 0ec6abcedb | |||
| cc1cc27037 | |||
| b86fd0269e | |||
| adb6d5f965 | |||
| 982524c860 | |||
| b56c102f8e | |||
| a3daaac009 | |||
| 77ace0a39f | |||
| 6c9011d181 | |||
| e6865e1c21 | |||
| cc20e07347 | |||
| e37319193c | |||
| 107e462831 | |||
| 76254a18ad |
@@ -32,7 +32,6 @@ xvfb-run -a -s "-screen 0 1024x768x24" \
|
|||||||
--timeout-multiplier 2 \
|
--timeout-multiplier 2 \
|
||||||
--print-errorlogs \
|
--print-errorlogs \
|
||||||
--suite=gtk \
|
--suite=gtk \
|
||||||
--no-suite=gtk:gsk \
|
|
||||||
--no-suite=gtk:a11y
|
--no-suite=gtk:a11y
|
||||||
|
|
||||||
# Save the exit code
|
# Save the exit code
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
subdir('gtk-demo')
|
subdir('gtk-demo')
|
||||||
subdir('icon-browser')
|
subdir('icon-browser')
|
||||||
|
subdir('node-editor')
|
||||||
subdir('widget-factory')
|
subdir('widget-factory')
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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__ */
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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__ */
|
||||||
@@ -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>
|
||||||
@@ -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>
|
||||||
@@ -116,6 +116,8 @@ typedef struct {
|
|||||||
|
|
||||||
int use_es;
|
int use_es;
|
||||||
|
|
||||||
|
int max_debug_label_length;
|
||||||
|
|
||||||
GdkGLContextPaintData *paint_data;
|
GdkGLContextPaintData *paint_data;
|
||||||
} GdkGLContextPrivate;
|
} GdkGLContextPrivate;
|
||||||
|
|
||||||
@@ -457,11 +459,14 @@ gdk_gl_context_push_debug_group_printf (GdkGLContext *context,
|
|||||||
|
|
||||||
if (priv->use_khr_debug)
|
if (priv->use_khr_debug)
|
||||||
{
|
{
|
||||||
|
int msg_len;
|
||||||
|
|
||||||
va_start (args, format);
|
va_start (args, format);
|
||||||
message = g_strdup_vprintf (format, args);
|
message = g_strdup_vprintf (format, args);
|
||||||
va_end (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);
|
g_free (message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -500,11 +505,15 @@ gdk_gl_context_label_object_printf (GdkGLContext *context,
|
|||||||
|
|
||||||
if (priv->use_khr_debug)
|
if (priv->use_khr_debug)
|
||||||
{
|
{
|
||||||
|
int msg_len;
|
||||||
|
|
||||||
va_start (args, format);
|
va_start (args, format);
|
||||||
message = g_strdup_vprintf (format, args);
|
message = g_strdup_vprintf (format, args);
|
||||||
va_end (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);
|
g_free (message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -992,7 +1001,10 @@ gdk_gl_context_check_extensions (GdkGLContext *context)
|
|||||||
display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
display = gdk_draw_context_get_display (GDK_DRAW_CONTEXT (context));
|
||||||
|
|
||||||
if (priv->has_khr_debug && GDK_DISPLAY_DEBUG_CHECK (display, GL_DEBUG))
|
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))
|
if (!priv->use_es && GDK_DISPLAY_DEBUG_CHECK (display, GL_TEXTURE_RECT))
|
||||||
priv->use_texture_rectangle = TRUE;
|
priv->use_texture_rectangle = TRUE;
|
||||||
else if (has_npot)
|
else if (has_npot)
|
||||||
|
|||||||
@@ -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));
|
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))
|
if (gdk_texture_set_render_data (texture, self, t, gsk_gl_driver_release_texture))
|
||||||
t->user = texture;
|
t->user = texture;
|
||||||
@@ -547,6 +545,9 @@ gsk_gl_driver_get_texture_for_texture (GskGLDriver *self,
|
|||||||
surface,
|
surface,
|
||||||
min_filter,
|
min_filter,
|
||||||
mag_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);
|
cairo_surface_destroy (surface);
|
||||||
|
|
||||||
return t->texture_id;
|
return t->texture_id;
|
||||||
|
|||||||
@@ -326,6 +326,7 @@ struct _GskGLRenderer
|
|||||||
Program unblurred_outset_shadow_program;
|
Program unblurred_outset_shadow_program;
|
||||||
Program border_program;
|
Program border_program;
|
||||||
Program cross_fade_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,
|
texture_id = gsk_gl_driver_create_texture (self->gl_driver,
|
||||||
surface_width,
|
surface_width,
|
||||||
surface_height);
|
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_bind_source_texture (self->gl_driver, texture_id);
|
||||||
gsk_gl_driver_init_texture_with_surface (self->gl_driver,
|
gsk_gl_driver_init_texture_with_surface (self->gl_driver,
|
||||||
texture_id,
|
texture_id,
|
||||||
surface,
|
surface,
|
||||||
GL_NEAREST, GL_NEAREST);
|
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);
|
cairo_surface_destroy (surface);
|
||||||
|
|
||||||
@@ -1431,10 +1432,10 @@ render_outset_shadow_node (GskGLRenderer *self,
|
|||||||
GskRoundedRect blit_clip;
|
GskRoundedRect blit_clip;
|
||||||
|
|
||||||
texture_id = gsk_gl_driver_create_texture (self->gl_driver, texture_width, texture_height);
|
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_bind_source_texture (self->gl_driver, texture_id);
|
||||||
gsk_gl_driver_init_texture_empty (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);
|
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,
|
gdk_gl_context_label_object_printf (self->gl_context, GL_FRAMEBUFFER, render_target,
|
||||||
"Outset Shadow FB Temp %d", 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);
|
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_bind_source_texture (self->gl_driver, blurred_texture_id);
|
||||||
gsk_gl_driver_init_texture_empty (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);
|
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,
|
gdk_gl_context_label_object_printf (self->gl_context, GL_FRAMEBUFFER, render_target,
|
||||||
"Outset Shadow Cache FB %d", render_target);
|
"Outset Shadow Cache FB %d", render_target);
|
||||||
@@ -1900,6 +1901,54 @@ render_cross_fade_node (GskGLRenderer *self,
|
|||||||
ops_draw (builder, vertex_data);
|
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
|
static inline void
|
||||||
apply_viewport_op (const Program *program,
|
apply_viewport_op (const Program *program,
|
||||||
const RenderOp *op)
|
const RenderOp *op)
|
||||||
@@ -2174,6 +2223,18 @@ apply_cross_fade_op (const Program *program,
|
|||||||
glUniform1f (program->cross_fade.progress_location, op->cross_fade.progress);
|
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
|
static void
|
||||||
gsk_gl_renderer_dispose (GObject *gobject)
|
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" },
|
{ "unblurred outset shadow", "unblurred_outset_shadow.fs.glsl" },
|
||||||
{ "border", "border.fs.glsl" },
|
{ "border", "border.fs.glsl" },
|
||||||
{ "cross fade", "cross_fade.fs.glsl" },
|
{ "cross fade", "cross_fade.fs.glsl" },
|
||||||
|
{ "blend", "blend.fs.glsl" },
|
||||||
};
|
};
|
||||||
|
|
||||||
builder = gsk_shader_builder_new ();
|
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, progress);
|
||||||
INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, source2);
|
INIT_PROGRAM_UNIFORM_LOCATION (cross_fade, source2);
|
||||||
|
|
||||||
|
/* blend */
|
||||||
|
INIT_PROGRAM_UNIFORM_LOCATION (blend, source2);
|
||||||
|
INIT_PROGRAM_UNIFORM_LOCATION (blend, mode);
|
||||||
|
|
||||||
g_object_unref (builder);
|
g_object_unref (builder);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -2588,8 +2654,11 @@ gsk_gl_renderer_add_render_ops (GskGLRenderer *self,
|
|||||||
render_cross_fade_node (self, node, builder);
|
render_cross_fade_node (self, node, builder);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
|
||||||
case GSK_BLEND_NODE:
|
case GSK_BLEND_NODE:
|
||||||
|
render_blend_node (self, node, builder);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GSK_REPEATING_LINEAR_GRADIENT_NODE:
|
||||||
case GSK_REPEAT_NODE:
|
case GSK_REPEAT_NODE:
|
||||||
case GSK_CAIRO_NODE:
|
case GSK_CAIRO_NODE:
|
||||||
default:
|
default:
|
||||||
@@ -2855,6 +2924,11 @@ gsk_gl_renderer_render_ops (GskGLRenderer *self,
|
|||||||
apply_cross_fade_op (program, op);
|
apply_cross_fade_op (program, op);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OP_CHANGE_BLEND:
|
||||||
|
g_assert (program == &self->blend_program);
|
||||||
|
apply_blend_op (program, op);
|
||||||
|
break;
|
||||||
|
|
||||||
case OP_CHANGE_LINEAR_GRADIENT:
|
case OP_CHANGE_LINEAR_GRADIENT:
|
||||||
apply_linear_gradient_op (program, op);
|
apply_linear_gradient_op (program, op);
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#include "gskrendernodeprivate.h"
|
#include "gskrendernodeprivate.h"
|
||||||
|
|
||||||
#define GL_N_VERTICES 6
|
#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_DUMP_FRAMEBUFFER = 23,
|
||||||
OP_PUSH_DEBUG_GROUP = 24,
|
OP_PUSH_DEBUG_GROUP = 24,
|
||||||
OP_POP_DEBUG_GROUP = 25,
|
OP_POP_DEBUG_GROUP = 25,
|
||||||
|
OP_CHANGE_BLEND = 26,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@@ -136,6 +137,10 @@ typedef struct
|
|||||||
int source2_location;
|
int source2_location;
|
||||||
int progress_location;
|
int progress_location;
|
||||||
} cross_fade;
|
} cross_fade;
|
||||||
|
struct {
|
||||||
|
int source2_location;
|
||||||
|
int mode_location;
|
||||||
|
} blend;
|
||||||
};
|
};
|
||||||
|
|
||||||
} Program;
|
} Program;
|
||||||
@@ -214,6 +219,10 @@ typedef struct
|
|||||||
float progress;
|
float progress;
|
||||||
int source2;
|
int source2;
|
||||||
} cross_fade;
|
} cross_fade;
|
||||||
|
struct {
|
||||||
|
int source2;
|
||||||
|
int mode;
|
||||||
|
} blend;
|
||||||
struct {
|
struct {
|
||||||
char *filename;
|
char *filename;
|
||||||
int width;
|
int width;
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
|
|
||||||
#include "gskdebugprivate.h"
|
#include "gskdebugprivate.h"
|
||||||
#include "gskrendererprivate.h"
|
#include "gskrendererprivate.h"
|
||||||
|
#include "gskrendernodeparserprivate.h"
|
||||||
|
|
||||||
#include <graphene-gobject.h>
|
#include <graphene-gobject.h>
|
||||||
|
|
||||||
@@ -328,19 +329,11 @@ gsk_render_node_diff (GskRenderNode *node1,
|
|||||||
GBytes *
|
GBytes *
|
||||||
gsk_render_node_serialize (GskRenderNode *node)
|
gsk_render_node_serialize (GskRenderNode *node)
|
||||||
{
|
{
|
||||||
GVariant *node_variant, *variant;
|
|
||||||
GBytes *result;
|
GBytes *result;
|
||||||
|
char *str;
|
||||||
|
|
||||||
node_variant = gsk_render_node_serialize_node (node);
|
str = gsk_render_node_serialize_to_string (node);
|
||||||
|
result = g_bytes_new_take (str, strlen (str));
|
||||||
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);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -394,39 +387,13 @@ gsk_render_node_write_to_file (GskRenderNode *node,
|
|||||||
* error.
|
* error.
|
||||||
**/
|
**/
|
||||||
GskRenderNode *
|
GskRenderNode *
|
||||||
gsk_render_node_deserialize (GBytes *bytes,
|
gsk_render_node_deserialize (GBytes *bytes,
|
||||||
GError **error)
|
GskParseErrorFunc error_func,
|
||||||
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
char *id_string;
|
|
||||||
guint32 version, node_type;
|
|
||||||
GVariant *variant, *node_variant;
|
|
||||||
GskRenderNode *node = NULL;
|
GskRenderNode *node = NULL;
|
||||||
|
|
||||||
variant = g_variant_new_from_bytes (G_VARIANT_TYPE ("(suuv)"), bytes, FALSE);
|
node = gsk_render_node_deserialize_from_bytes (bytes, error_func, user_data);
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <gsk/gskroundedrect.h>
|
#include <gsk/gskroundedrect.h>
|
||||||
#include <gsk/gsktypes.h>
|
#include <gsk/gsktypes.h>
|
||||||
|
#include <gtk/css/gtkcss.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
@@ -52,6 +53,10 @@ struct _GskShadow
|
|||||||
float radius;
|
float radius;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef void (* GskParseErrorFunc) (const GtkCssSection *section,
|
||||||
|
const GError *error,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
GType gsk_render_node_get_type (void) G_GNUC_CONST;
|
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,
|
const char *filename,
|
||||||
GError **error);
|
GError **error);
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
GskRenderNode * gsk_render_node_deserialize (GBytes *bytes,
|
GskRenderNode * gsk_render_node_deserialize (GBytes *bytes,
|
||||||
GError **error);
|
GskParseErrorFunc error_func,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
GDK_AVAILABLE_IN_ALL
|
GDK_AVAILABLE_IN_ALL
|
||||||
GskRenderNode * gsk_debug_node_new (GskRenderNode *child,
|
GskRenderNode * gsk_debug_node_new (GskRenderNode *child,
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -33,9 +33,6 @@ struct _GskRenderNodeClass
|
|||||||
void (* diff) (GskRenderNode *node1,
|
void (* diff) (GskRenderNode *node1,
|
||||||
GskRenderNode *node2,
|
GskRenderNode *node2,
|
||||||
cairo_region_t *region);
|
cairo_region_t *region);
|
||||||
GVariant * (* serialize) (GskRenderNode *node);
|
|
||||||
GskRenderNode * (* deserialize) (GVariant *variant,
|
|
||||||
GError **error);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
GskRenderNode * gsk_render_node_new (const GskRenderNodeClass *node_class,
|
GskRenderNode * gsk_render_node_new (const GskRenderNodeClass *node_class,
|
||||||
@@ -50,11 +47,6 @@ void gsk_render_node_diff_impossible (GskRenderNode *nod
|
|||||||
GskRenderNode *node2,
|
GskRenderNode *node2,
|
||||||
cairo_region_t *region);
|
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,
|
GskRenderNode * gsk_cairo_node_new_for_surface (const graphene_rect_t *bounds,
|
||||||
cairo_surface_t *surface);
|
cairo_surface_t *surface);
|
||||||
|
|
||||||
|
|||||||
@@ -1695,6 +1695,7 @@ gsk_transform_parser_parse (GtkCssParser *parser,
|
|||||||
if (gtk_css_token_is_ident (token, "none"))
|
if (gtk_css_token_is_ident (token, "none"))
|
||||||
{
|
{
|
||||||
gtk_css_parser_consume_token (parser);
|
gtk_css_parser_consume_token (parser);
|
||||||
|
|
||||||
*out_transform = NULL;
|
*out_transform = NULL;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
@@ -1902,6 +1903,7 @@ gsk_transform_parse (const char *string,
|
|||||||
result = FALSE;
|
result = FALSE;
|
||||||
}
|
}
|
||||||
gtk_css_parser_unref (parser);
|
gtk_css_parser_unref (parser);
|
||||||
|
|
||||||
g_bytes_unref (bytes);
|
g_bytes_unref (bytes);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ gsk_private_gl_shaders = [
|
|||||||
'resources/glsl/unblurred_outset_shadow.fs.glsl',
|
'resources/glsl/unblurred_outset_shadow.fs.glsl',
|
||||||
'resources/glsl/border.fs.glsl',
|
'resources/glsl/border.fs.glsl',
|
||||||
'resources/glsl/cross_fade.fs.glsl',
|
'resources/glsl/cross_fade.fs.glsl',
|
||||||
|
'resources/glsl/blend.fs.glsl',
|
||||||
'resources/glsl/es2_common.fs.glsl',
|
'resources/glsl/es2_common.fs.glsl',
|
||||||
'resources/glsl/es2_common.vs.glsl',
|
'resources/glsl/es2_common.vs.glsl',
|
||||||
'resources/glsl/gl3_common.fs.glsl',
|
'resources/glsl/gl3_common.fs.glsl',
|
||||||
@@ -34,6 +35,7 @@ gsk_private_sources = files([
|
|||||||
'gskdebug.c',
|
'gskdebug.c',
|
||||||
'gskprivate.c',
|
'gskprivate.c',
|
||||||
'gskprofiler.c',
|
'gskprofiler.c',
|
||||||
|
'gskrendernodeparser.c',
|
||||||
'gl/gskshaderbuilder.c',
|
'gl/gskshaderbuilder.c',
|
||||||
'gl/gskglprofiler.c',
|
'gl/gskglprofiler.c',
|
||||||
'gl/gskglrenderer.c',
|
'gl/gskglrenderer.c',
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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_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))
|
#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 _GtkCssProvider GtkCssProvider;
|
||||||
typedef struct _GtkCssProviderClass GtkCssProviderClass;
|
typedef struct _GtkCssProviderClass GtkCssProviderClass;
|
||||||
typedef struct _GtkCssProviderPrivate GtkCssProviderPrivate;
|
typedef struct _GtkCssProviderPrivate GtkCssProviderPrivate;
|
||||||
|
|||||||
@@ -13,6 +13,19 @@ static GOptionEntry options[] = {
|
|||||||
{ NULL }
|
{ 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
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -66,7 +79,7 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
start = g_get_monotonic_time ();
|
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 ();
|
end = g_get_monotonic_time ();
|
||||||
if (benchmark)
|
if (benchmark)
|
||||||
{
|
{
|
||||||
@@ -78,8 +91,6 @@ main(int argc, char **argv)
|
|||||||
|
|
||||||
if (node == NULL)
|
if (node == NULL)
|
||||||
{
|
{
|
||||||
g_printerr ("Invalid node file: %s\n", error->message);
|
|
||||||
g_clear_error (&error);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,18 @@ gtk_node_view_class_init (GtkNodeViewClass *klass)
|
|||||||
widget_class->snapshot = gtk_node_view_snapshot;
|
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
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
{
|
{
|
||||||
@@ -152,7 +164,7 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bytes = g_bytes_new_take (contents, len);
|
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);
|
g_bytes_unref (bytes);
|
||||||
|
|
||||||
if (GTK_NODE_VIEW (nodeview)->node == NULL)
|
if (GTK_NODE_VIEW (nodeview)->node == NULL)
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 120 KiB |
|
Before Width: | Height: | Size: 121 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 76 KiB |
@@ -54,6 +54,18 @@ save_image (cairo_surface_t *surface,
|
|||||||
g_free (filename);
|
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:
|
* Arguments:
|
||||||
* 1) .node file to compare
|
* 1) .node file to compare
|
||||||
@@ -101,7 +113,7 @@ main (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bytes = g_bytes_new_take (contents, len);
|
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_bytes_unref (bytes);
|
||||||
|
|
||||||
g_assert_no_error (error);
|
g_assert_no_error (error);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 269 B |
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 237 B |
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 1.9 KiB |
@@ -0,0 +1,8 @@
|
|||||||
|
outset-shadow {
|
||||||
|
outline: 100 100 100 100;
|
||||||
|
color: black;
|
||||||
|
dx: -100;
|
||||||
|
dy: 100;
|
||||||
|
spread: 10;
|
||||||
|
blur: 0;
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 527 B After Width: | Height: | Size: 527 B |
@@ -0,0 +1,8 @@
|
|||||||
|
outset-shadow {
|
||||||
|
outline: 100 100 100 100;
|
||||||
|
color: black;
|
||||||
|
dx: 10;
|
||||||
|
dy: 0;
|
||||||
|
spread: 10;
|
||||||
|
blur: 0;
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 391 B |
@@ -0,0 +1,8 @@
|
|||||||
|
outset-shadow {
|
||||||
|
outline: 100 100 100 100;
|
||||||
|
color: black;
|
||||||
|
dx: 0;
|
||||||
|
dy: 10;
|
||||||
|
spread: 10;
|
||||||
|
blur: 0;
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 391 B After Width: | Height: | Size: 391 B |
@@ -0,0 +1,8 @@
|
|||||||
|
outset-shadow {
|
||||||
|
outline: 100 100 100 100;
|
||||||
|
color: black;
|
||||||
|
dx: 0;
|
||||||
|
dy: 0;
|
||||||
|
spread: 10;
|
||||||
|
blur: 0;
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 396 B After Width: | Height: | Size: 396 B |
|
Before Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 243 KiB |
|
Before Width: | Height: | Size: 157 B |
|
Before Width: | Height: | Size: 613 B |
|
After Width: | Height: | Size: 618 B |
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.6 KiB |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 394 B |
|
Before Width: | Height: | Size: 744 B |
|
Before Width: | Height: | Size: 543 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 344 B |
|
Before Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 761 B |
|
Before Width: | Height: | Size: 790 B |
|
After Width: | Height: | Size: 408 B |
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Before Width: | Height: | Size: 1011 B |